claude-mpm 3.4.10__py3-none-any.whl → 5.4.85__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 (1062) hide show
  1. claude_mpm/BUILD_NUMBER +1 -0
  2. claude_mpm/VERSION +1 -0
  3. claude_mpm/__init__.py +50 -12
  4. claude_mpm/__main__.py +7 -2
  5. claude_mpm/agents/BASE_AGENT.md +164 -0
  6. claude_mpm/agents/BASE_ENGINEER.md +658 -0
  7. claude_mpm/agents/CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md +405 -0
  8. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +112 -0
  9. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +186 -0
  10. claude_mpm/agents/MEMORY.md +72 -0
  11. claude_mpm/agents/PM_INSTRUCTIONS.md +1429 -0
  12. claude_mpm/agents/WORKFLOW.md +111 -0
  13. claude_mpm/agents/__init__.py +92 -80
  14. claude_mpm/agents/agent-template.yaml +83 -0
  15. claude_mpm/agents/agent_loader.py +560 -745
  16. claude_mpm/agents/agent_loader_integration.py +53 -55
  17. claude_mpm/agents/agents_metadata.py +186 -27
  18. claude_mpm/agents/async_agent_loader.py +436 -0
  19. claude_mpm/agents/base_agent.json +8 -4
  20. claude_mpm/agents/frontmatter_validator.py +754 -0
  21. claude_mpm/agents/system_agent_config.py +222 -155
  22. claude_mpm/agents/templates/README.md +465 -0
  23. claude_mpm/agents/templates/__init__.py +17 -13
  24. claude_mpm/agents/templates/circuit-breakers.md +1391 -0
  25. claude_mpm/agents/templates/context-management-examples.md +544 -0
  26. claude_mpm/agents/templates/git-file-tracking.md +584 -0
  27. claude_mpm/agents/templates/pm-examples.md +474 -0
  28. claude_mpm/agents/templates/pm-red-flags.md +310 -0
  29. claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
  30. claude_mpm/agents/templates/research-gate-examples.md +669 -0
  31. claude_mpm/agents/templates/response-format.md +583 -0
  32. claude_mpm/agents/templates/structured-questions-examples.md +615 -0
  33. claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
  34. claude_mpm/agents/templates/ticketing-examples.md +277 -0
  35. claude_mpm/agents/templates/validation-templates.md +312 -0
  36. claude_mpm/cli/__init__.py +94 -128
  37. claude_mpm/cli/__main__.py +33 -0
  38. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  39. claude_mpm/cli/commands/__init__.py +36 -12
  40. claude_mpm/cli/commands/agent_manager.py +1403 -0
  41. claude_mpm/cli/commands/agent_source.py +774 -0
  42. claude_mpm/cli/commands/agent_state_manager.py +335 -0
  43. claude_mpm/cli/commands/agents.py +2501 -168
  44. claude_mpm/cli/commands/agents_cleanup.py +210 -0
  45. claude_mpm/cli/commands/agents_discover.py +338 -0
  46. claude_mpm/cli/commands/agents_reconcile.py +197 -0
  47. claude_mpm/cli/commands/aggregate.py +540 -0
  48. claude_mpm/cli/commands/analyze.py +553 -0
  49. claude_mpm/cli/commands/analyze_code.py +528 -0
  50. claude_mpm/cli/commands/auto_configure.py +1053 -0
  51. claude_mpm/cli/commands/cleanup.py +588 -0
  52. claude_mpm/cli/commands/cleanup_orphaned_agents.py +150 -0
  53. claude_mpm/cli/commands/config.py +586 -0
  54. claude_mpm/cli/commands/configure.py +3253 -0
  55. claude_mpm/cli/commands/configure_agent_display.py +282 -0
  56. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  57. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  58. claude_mpm/cli/commands/configure_models.py +18 -0
  59. claude_mpm/cli/commands/configure_navigation.py +184 -0
  60. claude_mpm/cli/commands/configure_paths.py +104 -0
  61. claude_mpm/cli/commands/configure_persistence.py +254 -0
  62. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  63. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  64. claude_mpm/cli/commands/configure_validators.py +73 -0
  65. claude_mpm/cli/commands/dashboard.py +286 -0
  66. claude_mpm/cli/commands/debug.py +1386 -0
  67. claude_mpm/cli/commands/doctor.py +243 -0
  68. claude_mpm/cli/commands/hook_errors.py +277 -0
  69. claude_mpm/cli/commands/info.py +195 -74
  70. claude_mpm/cli/commands/local_deploy.py +534 -0
  71. claude_mpm/cli/commands/mcp.py +205 -0
  72. claude_mpm/cli/commands/mcp_command_router.py +161 -0
  73. claude_mpm/cli/commands/mcp_config.py +154 -0
  74. claude_mpm/cli/commands/mcp_config_commands.py +20 -0
  75. claude_mpm/cli/commands/mcp_external_commands.py +249 -0
  76. claude_mpm/cli/commands/mcp_install_commands.py +346 -0
  77. claude_mpm/cli/commands/mcp_pipx_config.py +208 -0
  78. claude_mpm/cli/commands/mcp_server_commands.py +155 -0
  79. claude_mpm/cli/commands/mcp_setup_external.py +868 -0
  80. claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
  81. claude_mpm/cli/commands/memory.py +585 -846
  82. claude_mpm/cli/commands/monitor.py +228 -310
  83. claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
  84. claude_mpm/cli/commands/mpm_init/core.py +759 -0
  85. claude_mpm/cli/commands/mpm_init/display.py +341 -0
  86. claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
  87. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  88. claude_mpm/cli/commands/mpm_init/modes.py +397 -0
  89. claude_mpm/cli/commands/mpm_init/prompts.py +722 -0
  90. claude_mpm/cli/commands/mpm_init_cli.py +396 -0
  91. claude_mpm/cli/commands/mpm_init_handler.py +195 -0
  92. claude_mpm/cli/commands/postmortem.py +401 -0
  93. claude_mpm/cli/commands/profile.py +276 -0
  94. claude_mpm/cli/commands/run.py +910 -488
  95. claude_mpm/cli/commands/search.py +458 -0
  96. claude_mpm/cli/commands/skill_source.py +694 -0
  97. claude_mpm/cli/commands/skills.py +1398 -0
  98. claude_mpm/cli/commands/summarize.py +413 -0
  99. claude_mpm/cli/commands/tickets.py +536 -53
  100. claude_mpm/cli/commands/uninstall.py +176 -0
  101. claude_mpm/cli/commands/upgrade.py +152 -0
  102. claude_mpm/cli/commands/verify.py +119 -0
  103. claude_mpm/cli/executor.py +298 -0
  104. claude_mpm/cli/helpers.py +105 -0
  105. claude_mpm/cli/interactive/__init__.py +31 -0
  106. claude_mpm/cli/interactive/agent_wizard.py +1927 -0
  107. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  108. claude_mpm/cli/interactive/skill_selector.py +481 -0
  109. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  110. claude_mpm/cli/parser.py +87 -563
  111. claude_mpm/cli/parsers/__init__.py +35 -0
  112. claude_mpm/cli/parsers/agent_manager_parser.py +393 -0
  113. claude_mpm/cli/parsers/agent_source_parser.py +171 -0
  114. claude_mpm/cli/parsers/agents_parser.py +575 -0
  115. claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
  116. claude_mpm/cli/parsers/analyze_parser.py +135 -0
  117. claude_mpm/cli/parsers/auto_configure_parser.py +120 -0
  118. claude_mpm/cli/parsers/base_parser.py +649 -0
  119. claude_mpm/cli/parsers/config_parser.py +208 -0
  120. claude_mpm/cli/parsers/configure_parser.py +138 -0
  121. claude_mpm/cli/parsers/dashboard_parser.py +113 -0
  122. claude_mpm/cli/parsers/debug_parser.py +319 -0
  123. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  124. claude_mpm/cli/parsers/mcp_parser.py +195 -0
  125. claude_mpm/cli/parsers/memory_parser.py +138 -0
  126. claude_mpm/cli/parsers/monitor_parser.py +142 -0
  127. claude_mpm/cli/parsers/mpm_init_parser.py +311 -0
  128. claude_mpm/cli/parsers/profile_parser.py +147 -0
  129. claude_mpm/cli/parsers/run_parser.py +157 -0
  130. claude_mpm/cli/parsers/search_parser.py +245 -0
  131. claude_mpm/cli/parsers/skill_source_parser.py +169 -0
  132. claude_mpm/cli/parsers/skills_parser.py +277 -0
  133. claude_mpm/cli/parsers/source_parser.py +138 -0
  134. claude_mpm/cli/parsers/tickets_parser.py +203 -0
  135. claude_mpm/cli/shared/__init__.py +40 -0
  136. claude_mpm/cli/shared/argument_patterns.py +205 -0
  137. claude_mpm/cli/shared/base_command.py +242 -0
  138. claude_mpm/cli/shared/error_handling.py +242 -0
  139. claude_mpm/cli/shared/output_formatters.py +241 -0
  140. claude_mpm/cli/startup.py +1578 -0
  141. claude_mpm/cli/startup_display.py +480 -0
  142. claude_mpm/cli/startup_logging.py +839 -0
  143. claude_mpm/cli/utils.py +136 -47
  144. claude_mpm/cli_module/__init__.py +6 -6
  145. claude_mpm/cli_module/args.py +188 -140
  146. claude_mpm/cli_module/commands.py +79 -70
  147. claude_mpm/cli_module/migration_example.py +42 -64
  148. claude_mpm/commands/__init__.py +14 -0
  149. claude_mpm/commands/mpm-config.md +28 -0
  150. claude_mpm/commands/mpm-doctor.md +20 -0
  151. claude_mpm/commands/mpm-help.md +20 -0
  152. claude_mpm/commands/mpm-init.md +120 -0
  153. claude_mpm/commands/mpm-monitor.md +31 -0
  154. claude_mpm/commands/mpm-organize.md +120 -0
  155. claude_mpm/commands/mpm-postmortem.md +21 -0
  156. claude_mpm/commands/mpm-session-resume.md +30 -0
  157. claude_mpm/commands/mpm-status.md +20 -0
  158. claude_mpm/commands/mpm-ticket-view.md +109 -0
  159. claude_mpm/commands/mpm-version.md +20 -0
  160. claude_mpm/commands/mpm.md +31 -0
  161. claude_mpm/config/__init__.py +42 -2
  162. claude_mpm/config/agent_config.py +402 -0
  163. claude_mpm/config/agent_presets.py +488 -0
  164. claude_mpm/config/agent_sources.py +352 -0
  165. claude_mpm/config/experimental_features.py +217 -0
  166. claude_mpm/config/model_config.py +428 -0
  167. claude_mpm/config/paths.py +258 -0
  168. claude_mpm/config/skill_presets.py +392 -0
  169. claude_mpm/config/skill_sources.py +590 -0
  170. claude_mpm/config/socketio_config.py +125 -83
  171. claude_mpm/constants.py +133 -22
  172. claude_mpm/core/__init__.py +62 -36
  173. claude_mpm/core/agent_name_normalizer.py +71 -73
  174. claude_mpm/core/agent_registry.py +385 -492
  175. claude_mpm/core/agent_session_manager.py +81 -70
  176. claude_mpm/core/api_validator.py +330 -0
  177. claude_mpm/core/base_service.py +159 -122
  178. claude_mpm/core/cache.py +560 -0
  179. claude_mpm/core/claude_runner.py +696 -916
  180. claude_mpm/core/config.py +613 -122
  181. claude_mpm/core/config_aliases.py +74 -73
  182. claude_mpm/core/config_constants.py +314 -0
  183. claude_mpm/core/constants.py +361 -0
  184. claude_mpm/core/container.py +646 -104
  185. claude_mpm/core/enums.py +452 -0
  186. claude_mpm/core/error_handler.py +623 -0
  187. claude_mpm/core/exceptions.py +536 -0
  188. claude_mpm/core/factories.py +105 -109
  189. claude_mpm/core/file_utils.py +764 -0
  190. claude_mpm/core/framework/__init__.py +25 -0
  191. claude_mpm/core/framework/formatters/__init__.py +11 -0
  192. claude_mpm/core/framework/formatters/capability_generator.py +367 -0
  193. claude_mpm/core/framework/formatters/content_formatter.py +278 -0
  194. claude_mpm/core/framework/formatters/context_generator.py +185 -0
  195. claude_mpm/core/framework/loaders/__init__.py +13 -0
  196. claude_mpm/core/framework/loaders/agent_loader.py +213 -0
  197. claude_mpm/core/framework/loaders/file_loader.py +176 -0
  198. claude_mpm/core/framework/loaders/instruction_loader.py +222 -0
  199. claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
  200. claude_mpm/core/framework/processors/__init__.py +11 -0
  201. claude_mpm/core/framework/processors/memory_processor.py +230 -0
  202. claude_mpm/core/framework/processors/metadata_processor.py +146 -0
  203. claude_mpm/core/framework/processors/template_processor.py +244 -0
  204. claude_mpm/core/framework_loader.py +485 -414
  205. claude_mpm/core/hook_error_memory.py +381 -0
  206. claude_mpm/core/hook_manager.py +246 -86
  207. claude_mpm/core/hook_performance_config.py +147 -0
  208. claude_mpm/core/injectable_service.py +72 -63
  209. claude_mpm/core/instruction_reinforcement_hook.py +267 -0
  210. claude_mpm/core/interactive_session.py +670 -0
  211. claude_mpm/core/interfaces.py +570 -164
  212. claude_mpm/core/lazy.py +467 -0
  213. claude_mpm/core/log_manager.py +707 -0
  214. claude_mpm/core/logger.py +295 -134
  215. claude_mpm/core/logging_config.py +474 -0
  216. claude_mpm/core/logging_utils.py +520 -0
  217. claude_mpm/core/minimal_framework_loader.py +24 -22
  218. claude_mpm/core/mixins.py +30 -29
  219. claude_mpm/core/oneshot_session.py +594 -0
  220. claude_mpm/core/optimized_agent_loader.py +479 -0
  221. claude_mpm/core/optimized_startup.py +554 -0
  222. claude_mpm/core/output_style_manager.py +491 -0
  223. claude_mpm/core/pm_hook_interceptor.py +197 -82
  224. claude_mpm/core/protocols/__init__.py +23 -0
  225. claude_mpm/core/protocols/runner_protocol.py +103 -0
  226. claude_mpm/core/protocols/session_protocol.py +131 -0
  227. claude_mpm/core/service_registry.py +153 -116
  228. claude_mpm/core/session_manager.py +179 -64
  229. claude_mpm/core/shared/__init__.py +17 -0
  230. claude_mpm/core/shared/config_loader.py +326 -0
  231. claude_mpm/core/shared/path_resolver.py +281 -0
  232. claude_mpm/core/shared/singleton_manager.py +221 -0
  233. claude_mpm/core/socketio_pool.py +400 -137
  234. claude_mpm/core/system_context.py +38 -0
  235. claude_mpm/core/tool_access_control.py +64 -57
  236. claude_mpm/core/types.py +307 -0
  237. claude_mpm/core/typing_utils.py +553 -0
  238. claude_mpm/core/unified_agent_registry.py +969 -0
  239. claude_mpm/core/unified_config.py +612 -0
  240. claude_mpm/core/unified_paths.py +958 -0
  241. claude_mpm/dashboard/__init__.py +12 -0
  242. claude_mpm/dashboard/api/simple_directory.py +261 -0
  243. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  244. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +1 -0
  245. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +1 -0
  246. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +1 -0
  247. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +24 -0
  248. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B0uc0UOD.js +36 -0
  249. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7RN905-.js +1 -0
  250. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7xVLGWV.js +2 -0
  251. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BIF9m_hv.js +61 -0
  252. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +1 -0
  253. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BPYeabCQ.js +1 -0
  254. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  255. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
  256. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Be7GpZd6.js +7 -0
  257. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bh0LDWpI.js +145 -0
  258. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BofRWZRR.js +10 -0
  259. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BovzEFCE.js +30 -0
  260. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C30mlcqg.js +165 -0
  261. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4B-KCzX.js +1 -0
  262. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4JcI4KD.js +122 -0
  263. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CBBdVcY8.js +1 -0
  264. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CDuw-vjf.js +1 -0
  265. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C_Usid8X.js +15 -0
  266. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cfqx1Qun.js +10 -0
  267. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CiIAseT4.js +128 -0
  268. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  269. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CnA0NrzZ.js +1 -0
  270. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cs_tUR18.js +24 -0
  271. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  272. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CyWMqx4W.js +43 -0
  273. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzZX-COe.js +220 -0
  274. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzeYkLYB.js +65 -0
  275. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D3k0OPJN.js +4 -0
  276. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9lljYKQ.js +1 -0
  277. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DGkLK5U1.js +267 -0
  278. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DI7hHRFL.js +1 -0
  279. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DLVjFsZ3.js +139 -0
  280. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUrLdbGD.js +89 -0
  281. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  282. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DY1XQ8fi.js +2 -0
  283. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DZX00Y4g.js +1 -0
  284. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +1 -0
  285. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DaimHw_p.js +68 -0
  286. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +323 -0
  287. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dhb8PKl3.js +1 -0
  288. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dle-35c7.js +64 -0
  289. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DmxopI1J.js +1 -0
  290. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DwBR2MJi.js +60 -0
  291. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/GYwsonyD.js +1 -0
  292. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  293. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
  294. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/RJiighC3.js +1 -0
  295. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Vzk33B_K.js +2 -0
  296. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ZGh7QtNv.js +7 -0
  297. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bT1r9zLR.js +1 -0
  298. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bTOqqlTd.js +1 -0
  299. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/eNVUfhuA.js +1 -0
  300. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/iEWssX7S.js +162 -0
  301. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/sQeU3Y1z.js +1 -0
  302. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uuIeMWc-.js +1 -0
  303. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.D6-I5TpK.js +2 -0
  304. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +1 -0
  305. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.m1gL8KXf.js +1 -0
  306. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.CgNOuw-d.js +1 -0
  307. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +1 -0
  308. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  309. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  310. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  311. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  312. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  313. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  314. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  315. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  316. claude_mpm/experimental/__init__.py +10 -0
  317. claude_mpm/experimental/cli_enhancements.py +104 -89
  318. claude_mpm/generators/__init__.py +1 -1
  319. claude_mpm/generators/agent_profile_generator.py +76 -66
  320. claude_mpm/hooks/__init__.py +37 -1
  321. claude_mpm/hooks/base_hook.py +37 -32
  322. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  323. claude_mpm/hooks/claude_hooks/connection_pool.py +250 -0
  324. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  325. claude_mpm/hooks/claude_hooks/event_handlers.py +888 -0
  326. claude_mpm/hooks/claude_hooks/hook_handler.py +652 -875
  327. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +10 -7
  328. claude_mpm/hooks/claude_hooks/installer.py +806 -0
  329. claude_mpm/hooks/claude_hooks/memory_integration.py +249 -0
  330. claude_mpm/hooks/claude_hooks/response_tracking.py +412 -0
  331. claude_mpm/hooks/claude_hooks/services/__init__.py +15 -0
  332. claude_mpm/hooks/claude_hooks/services/connection_manager.py +229 -0
  333. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +254 -0
  334. claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
  335. claude_mpm/hooks/claude_hooks/services/state_manager.py +284 -0
  336. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
  337. claude_mpm/hooks/claude_hooks/tool_analysis.py +224 -0
  338. claude_mpm/hooks/failure_learning/__init__.py +54 -0
  339. claude_mpm/hooks/failure_learning/failure_detection_hook.py +230 -0
  340. claude_mpm/hooks/failure_learning/fix_detection_hook.py +212 -0
  341. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +281 -0
  342. claude_mpm/hooks/instruction_reinforcement.py +301 -0
  343. claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
  344. claude_mpm/hooks/kuzu_memory_hook.py +386 -0
  345. claude_mpm/hooks/kuzu_response_hook.py +179 -0
  346. claude_mpm/hooks/memory_integration_hook.py +201 -107
  347. claude_mpm/hooks/session_resume_hook.py +121 -0
  348. claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
  349. claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
  350. claude_mpm/hooks/tool_call_interceptor.py +92 -76
  351. claude_mpm/hooks/validation_hooks.py +62 -54
  352. claude_mpm/init.py +518 -83
  353. claude_mpm/models/__init__.py +9 -9
  354. claude_mpm/models/agent_definition.py +40 -23
  355. claude_mpm/models/agent_session.py +538 -0
  356. claude_mpm/models/git_repository.py +198 -0
  357. claude_mpm/models/resume_log.py +340 -0
  358. claude_mpm/schemas/__init__.py +12 -0
  359. claude_mpm/scripts/__init__.py +15 -0
  360. claude_mpm/scripts/claude-hook-handler.sh +227 -0
  361. claude_mpm/scripts/launch_monitor.py +165 -0
  362. claude_mpm/scripts/mpm_doctor.py +322 -0
  363. claude_mpm/scripts/socketio_daemon.py +189 -200
  364. claude_mpm/scripts/start_activity_logging.py +91 -0
  365. claude_mpm/services/__init__.py +208 -39
  366. claude_mpm/services/agent_capabilities_service.py +266 -0
  367. claude_mpm/services/agents/__init__.py +89 -0
  368. claude_mpm/services/agents/agent_builder.py +514 -0
  369. claude_mpm/services/agents/agent_preset_service.py +238 -0
  370. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  371. claude_mpm/services/agents/agent_review_service.py +280 -0
  372. claude_mpm/services/agents/agent_selection_service.py +484 -0
  373. claude_mpm/services/agents/auto_config_manager.py +796 -0
  374. claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
  375. claude_mpm/services/agents/cache_git_manager.py +621 -0
  376. claude_mpm/services/agents/deployment/__init__.py +21 -0
  377. claude_mpm/services/agents/deployment/agent_config_provider.py +410 -0
  378. claude_mpm/services/agents/deployment/agent_configuration_manager.py +358 -0
  379. claude_mpm/services/agents/deployment/agent_definition_factory.py +80 -0
  380. claude_mpm/services/agents/deployment/agent_deployment.py +1037 -0
  381. claude_mpm/services/agents/deployment/agent_discovery_service.py +546 -0
  382. claude_mpm/services/agents/deployment/agent_environment_manager.py +288 -0
  383. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +383 -0
  384. claude_mpm/services/agents/deployment/agent_format_converter.py +505 -0
  385. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +160 -0
  386. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +957 -0
  387. claude_mpm/services/agents/deployment/agent_metrics_collector.py +273 -0
  388. claude_mpm/services/agents/deployment/agent_operation_service.py +573 -0
  389. claude_mpm/services/agents/deployment/agent_record_service.py +418 -0
  390. claude_mpm/services/agents/deployment/agent_restore_handler.py +84 -0
  391. claude_mpm/services/agents/deployment/agent_state_service.py +381 -0
  392. claude_mpm/services/agents/deployment/agent_template_builder.py +1377 -0
  393. claude_mpm/services/agents/deployment/agent_validator.py +376 -0
  394. claude_mpm/services/agents/deployment/agent_version_manager.py +322 -0
  395. claude_mpm/services/{agent_versioning.py → agents/deployment/agent_versioning.py} +10 -13
  396. claude_mpm/services/agents/deployment/agents_directory_resolver.py +149 -0
  397. claude_mpm/services/agents/deployment/async_agent_deployment.py +768 -0
  398. claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
  399. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  400. claude_mpm/services/agents/deployment/config/deployment_config.py +181 -0
  401. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  402. claude_mpm/services/agents/deployment/deployment_config_loader.py +178 -0
  403. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  404. claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
  405. claude_mpm/services/agents/deployment/deployment_type_detector.py +120 -0
  406. claude_mpm/services/agents/deployment/deployment_wrapper.py +129 -0
  407. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  408. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  409. claude_mpm/services/agents/deployment/facade/deployment_executor.py +70 -0
  410. claude_mpm/services/agents/deployment/facade/deployment_facade.py +269 -0
  411. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  412. claude_mpm/services/agents/deployment/interface_adapter.py +226 -0
  413. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  414. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  415. claude_mpm/services/agents/deployment/local_template_deployment.py +362 -0
  416. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +1478 -0
  417. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  418. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  419. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +162 -0
  420. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  421. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  422. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +240 -0
  423. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +110 -0
  424. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +80 -0
  425. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +92 -0
  426. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +101 -0
  427. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  428. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +102 -0
  429. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  430. claude_mpm/services/agents/deployment/processors/agent_processor.py +269 -0
  431. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +311 -0
  432. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +862 -0
  433. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  434. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  435. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  436. claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
  437. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  438. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  439. claude_mpm/services/agents/deployment/strategies/base_strategy.py +113 -0
  440. claude_mpm/services/agents/deployment/strategies/project_strategy.py +148 -0
  441. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  442. claude_mpm/services/agents/deployment/strategies/system_strategy.py +131 -0
  443. claude_mpm/services/agents/deployment/strategies/user_strategy.py +130 -0
  444. claude_mpm/services/agents/deployment/system_instructions_deployer.py +228 -0
  445. claude_mpm/services/agents/deployment/validation/__init__.py +21 -0
  446. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  447. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  448. claude_mpm/services/agents/deployment/validation/template_validator.py +319 -0
  449. claude_mpm/services/agents/deployment/validation/validation_result.py +214 -0
  450. claude_mpm/services/agents/git_source_manager.py +682 -0
  451. claude_mpm/services/agents/loading/__init__.py +11 -0
  452. claude_mpm/services/{agent_profile_loader.py → agents/loading/agent_profile_loader.py} +306 -228
  453. claude_mpm/services/{base_agent_manager.py → agents/loading/base_agent_manager.py} +106 -91
  454. claude_mpm/services/agents/loading/framework_agent_loader.py +433 -0
  455. claude_mpm/services/agents/local_template_manager.py +784 -0
  456. claude_mpm/services/agents/management/__init__.py +9 -0
  457. claude_mpm/services/{agent_capabilities_generator.py → agents/management/agent_capabilities_generator.py} +92 -69
  458. claude_mpm/services/{agent_management_service.py → agents/management/agent_management_service.py} +219 -168
  459. claude_mpm/services/agents/memory/__init__.py +22 -0
  460. claude_mpm/services/agents/memory/agent_memory_manager.py +784 -0
  461. claude_mpm/services/{agent_persistence_service.py → agents/memory/agent_persistence_service.py} +20 -18
  462. claude_mpm/services/agents/memory/content_manager.py +470 -0
  463. claude_mpm/services/agents/memory/memory_categorization_service.py +167 -0
  464. claude_mpm/services/agents/memory/memory_file_service.py +129 -0
  465. claude_mpm/services/agents/memory/memory_format_service.py +201 -0
  466. claude_mpm/services/agents/memory/memory_limits_service.py +101 -0
  467. claude_mpm/services/agents/memory/template_generator.py +83 -0
  468. claude_mpm/services/agents/observers.py +547 -0
  469. claude_mpm/services/agents/recommender.py +617 -0
  470. claude_mpm/services/agents/registry/__init__.py +30 -0
  471. claude_mpm/services/agents/registry/deployed_agent_discovery.py +273 -0
  472. claude_mpm/services/{agent_modification_tracker.py → agents/registry/modification_tracker.py} +370 -295
  473. claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
  474. claude_mpm/services/agents/sources/__init__.py +13 -0
  475. claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
  476. claude_mpm/services/agents/sources/git_source_sync_service.py +1205 -0
  477. claude_mpm/services/agents/startup_sync.py +262 -0
  478. claude_mpm/services/agents/toolchain_detector.py +478 -0
  479. claude_mpm/services/analysis/__init__.py +35 -0
  480. claude_mpm/services/analysis/clone_detector.py +1030 -0
  481. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  482. claude_mpm/services/analysis/postmortem_service.py +765 -0
  483. claude_mpm/services/async_session_logger.py +665 -0
  484. claude_mpm/services/claude_session_logger.py +321 -0
  485. claude_mpm/services/cli/__init__.py +18 -0
  486. claude_mpm/services/cli/agent_cleanup_service.py +408 -0
  487. claude_mpm/services/cli/agent_dependency_service.py +395 -0
  488. claude_mpm/services/cli/agent_listing_service.py +463 -0
  489. claude_mpm/services/cli/agent_output_formatter.py +605 -0
  490. claude_mpm/services/cli/agent_validation_service.py +590 -0
  491. claude_mpm/services/cli/memory_crud_service.py +622 -0
  492. claude_mpm/services/cli/memory_output_formatter.py +604 -0
  493. claude_mpm/services/cli/resume_service.py +617 -0
  494. claude_mpm/services/cli/session_manager.py +604 -0
  495. claude_mpm/services/cli/session_pause_manager.py +504 -0
  496. claude_mpm/services/cli/session_resume_helper.py +372 -0
  497. claude_mpm/services/cli/startup_checker.py +362 -0
  498. claude_mpm/services/cli/unified_dashboard_manager.py +439 -0
  499. claude_mpm/services/command_deployment_service.py +446 -0
  500. claude_mpm/services/command_handler_service.py +221 -0
  501. claude_mpm/services/communication/__init__.py +22 -0
  502. claude_mpm/services/core/__init__.py +108 -0
  503. claude_mpm/services/core/base.py +269 -0
  504. claude_mpm/services/core/cache_manager.py +309 -0
  505. claude_mpm/services/core/interfaces/__init__.py +273 -0
  506. claude_mpm/services/core/interfaces/agent.py +514 -0
  507. claude_mpm/services/core/interfaces/communication.py +316 -0
  508. claude_mpm/services/core/interfaces/health.py +169 -0
  509. claude_mpm/services/core/interfaces/infrastructure.py +357 -0
  510. claude_mpm/services/core/interfaces/model.py +281 -0
  511. claude_mpm/services/core/interfaces/process.py +372 -0
  512. claude_mpm/services/core/interfaces/project.py +121 -0
  513. claude_mpm/services/core/interfaces/restart.py +307 -0
  514. claude_mpm/services/core/interfaces/service.py +405 -0
  515. claude_mpm/services/core/interfaces/stability.py +260 -0
  516. claude_mpm/services/core/interfaces.py +81 -0
  517. claude_mpm/services/core/memory_manager.py +682 -0
  518. claude_mpm/services/core/models/__init__.py +70 -0
  519. claude_mpm/services/core/models/agent_config.py +384 -0
  520. claude_mpm/services/core/models/health.py +162 -0
  521. claude_mpm/services/core/models/process.py +239 -0
  522. claude_mpm/services/core/models/restart.py +302 -0
  523. claude_mpm/services/core/models/stability.py +264 -0
  524. claude_mpm/services/core/models/toolchain.py +306 -0
  525. claude_mpm/services/core/path_resolver.py +517 -0
  526. claude_mpm/services/core/service_container.py +520 -0
  527. claude_mpm/services/core/service_interfaces.py +436 -0
  528. claude_mpm/services/diagnostics/__init__.py +18 -0
  529. claude_mpm/services/diagnostics/checks/__init__.py +38 -0
  530. claude_mpm/services/diagnostics/checks/agent_check.py +370 -0
  531. claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
  532. claude_mpm/services/diagnostics/checks/base_check.py +60 -0
  533. claude_mpm/services/diagnostics/checks/claude_code_check.py +270 -0
  534. claude_mpm/services/diagnostics/checks/common_issues_check.py +363 -0
  535. claude_mpm/services/diagnostics/checks/configuration_check.py +306 -0
  536. claude_mpm/services/diagnostics/checks/filesystem_check.py +233 -0
  537. claude_mpm/services/diagnostics/checks/installation_check.py +520 -0
  538. claude_mpm/services/diagnostics/checks/instructions_check.py +415 -0
  539. claude_mpm/services/diagnostics/checks/mcp_check.py +330 -0
  540. claude_mpm/services/diagnostics/checks/mcp_services_check.py +1058 -0
  541. claude_mpm/services/diagnostics/checks/monitor_check.py +281 -0
  542. claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
  543. claude_mpm/services/diagnostics/checks/startup_log_check.py +319 -0
  544. claude_mpm/services/diagnostics/diagnostic_runner.py +286 -0
  545. claude_mpm/services/diagnostics/doctor_reporter.py +578 -0
  546. claude_mpm/services/diagnostics/models.py +138 -0
  547. claude_mpm/services/event_aggregator.py +582 -0
  548. claude_mpm/services/event_bus/__init__.py +18 -0
  549. claude_mpm/services/event_bus/config.py +186 -0
  550. claude_mpm/services/event_bus/direct_relay.py +312 -0
  551. claude_mpm/services/event_bus/event_bus.py +396 -0
  552. claude_mpm/services/event_bus/relay.py +326 -0
  553. claude_mpm/services/events/__init__.py +44 -0
  554. claude_mpm/services/events/consumers/__init__.py +18 -0
  555. claude_mpm/services/events/consumers/dead_letter.py +306 -0
  556. claude_mpm/services/events/consumers/logging.py +184 -0
  557. claude_mpm/services/events/consumers/metrics.py +241 -0
  558. claude_mpm/services/events/consumers/socketio.py +377 -0
  559. claude_mpm/services/events/core.py +480 -0
  560. claude_mpm/services/events/interfaces.py +214 -0
  561. claude_mpm/services/events/producers/__init__.py +14 -0
  562. claude_mpm/services/events/producers/hook.py +269 -0
  563. claude_mpm/services/events/producers/system.py +329 -0
  564. claude_mpm/services/exceptions.py +433 -353
  565. claude_mpm/services/framework_claude_md_generator/__init__.py +81 -80
  566. claude_mpm/services/framework_claude_md_generator/content_assembler.py +74 -67
  567. claude_mpm/services/framework_claude_md_generator/content_validator.py +66 -62
  568. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +82 -60
  569. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +36 -37
  570. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +41 -40
  571. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +15 -15
  572. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +5 -4
  573. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  574. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  575. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  576. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  577. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +5 -4
  578. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  579. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  580. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +26 -30
  581. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +6 -5
  582. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  583. claude_mpm/services/framework_claude_md_generator/version_manager.py +31 -30
  584. claude_mpm/services/git/__init__.py +21 -0
  585. claude_mpm/services/git/git_operations_service.py +579 -0
  586. claude_mpm/services/github/__init__.py +21 -0
  587. claude_mpm/services/github/github_cli_service.py +397 -0
  588. claude_mpm/services/hook_installer_service.py +506 -0
  589. claude_mpm/services/hook_service.py +159 -111
  590. claude_mpm/services/infrastructure/__init__.py +52 -0
  591. claude_mpm/services/infrastructure/context_preservation.py +569 -0
  592. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  593. claude_mpm/services/infrastructure/logging.py +209 -0
  594. claude_mpm/services/infrastructure/monitoring/__init__.py +39 -0
  595. claude_mpm/services/infrastructure/monitoring/aggregator.py +432 -0
  596. claude_mpm/services/infrastructure/monitoring/base.py +122 -0
  597. claude_mpm/services/infrastructure/monitoring/legacy.py +203 -0
  598. claude_mpm/services/infrastructure/monitoring/network.py +219 -0
  599. claude_mpm/services/infrastructure/monitoring/process.py +343 -0
  600. claude_mpm/services/infrastructure/monitoring/resources.py +244 -0
  601. claude_mpm/services/infrastructure/monitoring/service.py +368 -0
  602. claude_mpm/services/infrastructure/monitoring.py +71 -0
  603. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  604. claude_mpm/services/instructions/__init__.py +9 -0
  605. claude_mpm/services/instructions/instruction_cache_service.py +374 -0
  606. claude_mpm/services/local_ops/__init__.py +155 -0
  607. claude_mpm/services/local_ops/crash_detector.py +257 -0
  608. claude_mpm/services/local_ops/health_checks/__init__.py +26 -0
  609. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  610. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  611. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  612. claude_mpm/services/local_ops/health_manager.py +427 -0
  613. claude_mpm/services/local_ops/log_monitor.py +396 -0
  614. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  615. claude_mpm/services/local_ops/process_manager.py +595 -0
  616. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  617. claude_mpm/services/local_ops/restart_manager.py +401 -0
  618. claude_mpm/services/local_ops/restart_policy.py +387 -0
  619. claude_mpm/services/local_ops/state_manager.py +372 -0
  620. claude_mpm/services/local_ops/unified_manager.py +600 -0
  621. claude_mpm/services/mcp_config_manager.py +1542 -0
  622. claude_mpm/services/mcp_service_verifier.py +732 -0
  623. claude_mpm/services/memory/__init__.py +19 -0
  624. claude_mpm/services/{memory_builder.py → memory/builder.py} +465 -373
  625. claude_mpm/services/memory/cache/__init__.py +14 -0
  626. claude_mpm/services/{shared_prompt_cache.py → memory/cache/shared_prompt_cache.py} +237 -200
  627. claude_mpm/services/memory/cache/simple_cache.py +331 -0
  628. claude_mpm/services/memory/failure_tracker.py +578 -0
  629. claude_mpm/services/memory/indexed_memory.py +648 -0
  630. claude_mpm/services/{memory_optimizer.py → memory/optimizer.py} +272 -243
  631. claude_mpm/services/memory/router.py +951 -0
  632. claude_mpm/services/memory_hook_service.py +470 -0
  633. claude_mpm/services/model/__init__.py +147 -0
  634. claude_mpm/services/model/base_provider.py +365 -0
  635. claude_mpm/services/model/claude_provider.py +412 -0
  636. claude_mpm/services/model/model_router.py +452 -0
  637. claude_mpm/services/model/ollama_provider.py +415 -0
  638. claude_mpm/services/monitor/__init__.py +20 -0
  639. claude_mpm/services/monitor/daemon.py +698 -0
  640. claude_mpm/services/monitor/daemon_manager.py +1076 -0
  641. claude_mpm/services/monitor/event_emitter.py +350 -0
  642. claude_mpm/services/monitor/handlers/__init__.py +21 -0
  643. claude_mpm/services/monitor/handlers/code_analysis.py +332 -0
  644. claude_mpm/services/monitor/handlers/dashboard.py +299 -0
  645. claude_mpm/services/monitor/handlers/file.py +264 -0
  646. claude_mpm/services/monitor/handlers/hooks.py +512 -0
  647. claude_mpm/services/monitor/management/__init__.py +18 -0
  648. claude_mpm/services/monitor/management/health.py +124 -0
  649. claude_mpm/services/monitor/management/lifecycle.py +730 -0
  650. claude_mpm/services/monitor/server.py +1493 -0
  651. claude_mpm/services/monitor_build_service.py +349 -0
  652. claude_mpm/services/native_agent_converter.py +356 -0
  653. claude_mpm/services/orphan_detection.py +786 -0
  654. claude_mpm/services/pm_skills_deployer.py +711 -0
  655. claude_mpm/services/port_manager.py +597 -0
  656. claude_mpm/services/pr/__init__.py +14 -0
  657. claude_mpm/services/pr/pr_template_service.py +329 -0
  658. claude_mpm/services/profile_manager.py +337 -0
  659. claude_mpm/services/project/__init__.py +44 -0
  660. claude_mpm/services/{project_analyzer.py → project/analyzer.py} +541 -291
  661. claude_mpm/services/project/analyzer_v2.py +566 -0
  662. claude_mpm/services/project/architecture_analyzer.py +461 -0
  663. claude_mpm/services/project/archive_manager.py +1045 -0
  664. claude_mpm/services/project/dependency_analyzer.py +462 -0
  665. claude_mpm/services/project/detection_strategies.py +719 -0
  666. claude_mpm/services/project/documentation_manager.py +554 -0
  667. claude_mpm/services/project/enhanced_analyzer.py +572 -0
  668. claude_mpm/services/project/language_analyzer.py +265 -0
  669. claude_mpm/services/project/metrics_collector.py +407 -0
  670. claude_mpm/services/project/project_organizer.py +1009 -0
  671. claude_mpm/services/project/registry.py +636 -0
  672. claude_mpm/services/project/toolchain_analyzer.py +583 -0
  673. claude_mpm/services/project_port_allocator.py +596 -0
  674. claude_mpm/services/recovery_manager.py +293 -240
  675. claude_mpm/services/response_tracker.py +267 -0
  676. claude_mpm/services/runner_configuration_service.py +605 -0
  677. claude_mpm/services/self_upgrade_service.py +608 -0
  678. claude_mpm/services/session_management_service.py +314 -0
  679. claude_mpm/services/session_manager.py +380 -0
  680. claude_mpm/services/shared/__init__.py +21 -0
  681. claude_mpm/services/shared/async_service_base.py +216 -0
  682. claude_mpm/services/shared/config_service_base.py +301 -0
  683. claude_mpm/services/shared/lifecycle_service_base.py +308 -0
  684. claude_mpm/services/shared/manager_base.py +315 -0
  685. claude_mpm/services/shared/service_factory.py +309 -0
  686. claude_mpm/services/skills/__init__.py +21 -0
  687. claude_mpm/services/skills/git_skill_source_manager.py +1340 -0
  688. claude_mpm/services/skills/selective_skill_deployer.py +743 -0
  689. claude_mpm/services/skills/skill_discovery_service.py +568 -0
  690. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  691. claude_mpm/services/skills_config.py +547 -0
  692. claude_mpm/services/skills_deployer.py +1168 -0
  693. claude_mpm/services/socketio/__init__.py +25 -0
  694. claude_mpm/services/socketio/client_proxy.py +229 -0
  695. claude_mpm/services/socketio/dashboard_server.py +362 -0
  696. claude_mpm/services/socketio/event_normalizer.py +798 -0
  697. claude_mpm/services/socketio/handlers/__init__.py +30 -0
  698. claude_mpm/services/socketio/handlers/base.py +136 -0
  699. claude_mpm/services/socketio/handlers/code_analysis.py +682 -0
  700. claude_mpm/services/socketio/handlers/connection.py +643 -0
  701. claude_mpm/services/socketio/handlers/connection_handler.py +333 -0
  702. claude_mpm/services/socketio/handlers/file.py +263 -0
  703. claude_mpm/services/socketio/handlers/git.py +962 -0
  704. claude_mpm/services/socketio/handlers/hook.py +211 -0
  705. claude_mpm/services/socketio/handlers/memory.py +26 -0
  706. claude_mpm/services/socketio/handlers/project.py +24 -0
  707. claude_mpm/services/socketio/handlers/registry.py +214 -0
  708. claude_mpm/services/socketio/migration_utils.py +343 -0
  709. claude_mpm/services/socketio/monitor_client.py +364 -0
  710. claude_mpm/services/socketio/server/__init__.py +18 -0
  711. claude_mpm/services/socketio/server/broadcaster.py +569 -0
  712. claude_mpm/services/socketio/server/connection_manager.py +579 -0
  713. claude_mpm/services/socketio/server/core.py +1079 -0
  714. claude_mpm/services/socketio/server/eventbus_integration.py +245 -0
  715. claude_mpm/services/socketio/server/main.py +501 -0
  716. claude_mpm/services/socketio_client_manager.py +173 -143
  717. claude_mpm/services/socketio_server.py +38 -1657
  718. claude_mpm/services/subprocess_launcher_service.py +322 -0
  719. claude_mpm/services/system_instructions_service.py +270 -0
  720. claude_mpm/services/ticket_manager.py +25 -209
  721. claude_mpm/services/ticket_services/__init__.py +26 -0
  722. claude_mpm/services/ticket_services/crud_service.py +328 -0
  723. claude_mpm/services/ticket_services/formatter_service.py +290 -0
  724. claude_mpm/services/ticket_services/search_service.py +324 -0
  725. claude_mpm/services/ticket_services/validation_service.py +303 -0
  726. claude_mpm/services/ticket_services/workflow_service.py +244 -0
  727. claude_mpm/services/unified/__init__.py +65 -0
  728. claude_mpm/services/unified/analyzer_strategies/__init__.py +44 -0
  729. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +518 -0
  730. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +680 -0
  731. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +900 -0
  732. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +745 -0
  733. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +733 -0
  734. claude_mpm/services/unified/config_strategies/__init__.py +175 -0
  735. claude_mpm/services/unified/config_strategies/config_schema.py +731 -0
  736. claude_mpm/services/unified/config_strategies/context_strategy.py +747 -0
  737. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1005 -0
  738. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +881 -0
  739. claude_mpm/services/unified/config_strategies/unified_config_service.py +823 -0
  740. claude_mpm/services/unified/config_strategies/validation_strategy.py +1148 -0
  741. claude_mpm/services/unified/deployment_strategies/__init__.py +97 -0
  742. claude_mpm/services/unified/deployment_strategies/base.py +553 -0
  743. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +573 -0
  744. claude_mpm/services/unified/deployment_strategies/local.py +607 -0
  745. claude_mpm/services/unified/deployment_strategies/utils.py +667 -0
  746. claude_mpm/services/unified/deployment_strategies/vercel.py +471 -0
  747. claude_mpm/services/unified/interfaces.py +475 -0
  748. claude_mpm/services/unified/migration.py +509 -0
  749. claude_mpm/services/unified/strategies.py +534 -0
  750. claude_mpm/services/unified/unified_analyzer.py +542 -0
  751. claude_mpm/services/unified/unified_config.py +691 -0
  752. claude_mpm/services/unified/unified_deployment.py +466 -0
  753. claude_mpm/services/utility_service.py +280 -0
  754. claude_mpm/services/version_control/__init__.py +34 -37
  755. claude_mpm/services/version_control/branch_strategy.py +26 -17
  756. claude_mpm/services/version_control/conflict_resolution.py +52 -36
  757. claude_mpm/services/version_control/git_operations.py +183 -49
  758. claude_mpm/services/version_control/semantic_versioning.py +172 -61
  759. claude_mpm/services/version_control/version_parser.py +546 -0
  760. claude_mpm/services/version_service.py +379 -0
  761. claude_mpm/services/visualization/__init__.py +15 -0
  762. claude_mpm/services/visualization/mermaid_generator.py +937 -0
  763. claude_mpm/skills/__init__.py +42 -0
  764. claude_mpm/skills/agent_skills_injector.py +324 -0
  765. claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
  766. claude_mpm/skills/bundled/__init__.py +6 -0
  767. claude_mpm/skills/bundled/api-documentation.md +393 -0
  768. claude_mpm/skills/bundled/async-testing.md +571 -0
  769. claude_mpm/skills/bundled/code-review.md +143 -0
  770. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  771. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  772. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  773. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  774. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  775. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  776. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  777. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  778. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  779. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  780. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  781. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  782. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  783. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  784. claude_mpm/skills/bundled/database-migration.md +199 -0
  785. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  786. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  787. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  788. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  789. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  790. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  791. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  792. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  793. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  794. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  795. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  796. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  797. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  798. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  799. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  800. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  801. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  802. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  803. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  804. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  805. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  806. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  807. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  808. claude_mpm/skills/bundled/git-workflow.md +414 -0
  809. claude_mpm/skills/bundled/imagemagick.md +204 -0
  810. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  811. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  812. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  813. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  814. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  815. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  816. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  817. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  818. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  819. claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
  820. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  821. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  822. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  823. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  824. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  825. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  826. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  827. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  828. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  829. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  830. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  831. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  832. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  833. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  834. claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
  835. claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
  836. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  837. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  838. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  839. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  840. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  841. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  842. claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
  843. claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
  844. claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -0
  845. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  846. claude_mpm/skills/bundled/pdf.md +141 -0
  847. claude_mpm/skills/bundled/performance-profiling.md +573 -0
  848. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  849. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  850. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  851. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  852. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  853. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  854. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  855. claude_mpm/skills/bundled/pm/pm-bug-reporting/pm-bug-reporting.md +248 -0
  856. claude_mpm/skills/bundled/pm/pm-delegation-patterns/SKILL.md +167 -0
  857. claude_mpm/skills/bundled/pm/pm-git-file-tracking/SKILL.md +113 -0
  858. claude_mpm/skills/bundled/pm/pm-pr-workflow/SKILL.md +124 -0
  859. claude_mpm/skills/bundled/pm/pm-teaching-mode/SKILL.md +657 -0
  860. claude_mpm/skills/bundled/pm/pm-ticketing-integration/SKILL.md +154 -0
  861. claude_mpm/skills/bundled/pm/pm-verification-protocols/SKILL.md +198 -0
  862. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  863. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  864. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  865. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  866. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  867. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  868. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  869. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  870. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  871. claude_mpm/skills/bundled/security-scanning.md +439 -0
  872. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  873. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  874. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  875. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  876. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  877. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  878. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  879. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  880. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  881. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  882. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  883. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  884. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  885. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  886. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  887. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  888. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  889. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  890. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  891. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  892. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  893. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  894. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  895. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  896. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  897. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  898. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  899. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  900. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  901. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  902. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  903. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  904. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  905. claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
  906. claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
  907. claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
  908. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  909. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  910. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
  911. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  912. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  913. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  914. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  915. claude_mpm/skills/bundled/xlsx.md +157 -0
  916. claude_mpm/skills/registry.py +286 -0
  917. claude_mpm/skills/skill_manager.py +405 -0
  918. claude_mpm/skills/skills_registry.py +347 -0
  919. claude_mpm/skills/skills_service.py +739 -0
  920. claude_mpm/storage/__init__.py +9 -0
  921. claude_mpm/storage/state_storage.py +546 -0
  922. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  923. claude_mpm/templates/questions/__init__.py +38 -0
  924. claude_mpm/templates/questions/base.py +193 -0
  925. claude_mpm/templates/questions/pr_strategy.py +311 -0
  926. claude_mpm/templates/questions/project_init.py +385 -0
  927. claude_mpm/templates/questions/ticket_mgmt.py +394 -0
  928. claude_mpm/ticket_wrapper.py +2 -2
  929. claude_mpm/tools/__init__.py +10 -0
  930. claude_mpm/tools/__main__.py +208 -0
  931. claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
  932. claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
  933. claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
  934. claude_mpm/tools/code_tree_analyzer/core.py +380 -0
  935. claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
  936. claude_mpm/tools/code_tree_analyzer/events.py +168 -0
  937. claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
  938. claude_mpm/tools/code_tree_analyzer/models.py +39 -0
  939. claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
  940. claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
  941. claude_mpm/tools/code_tree_builder.py +631 -0
  942. claude_mpm/tools/code_tree_events.py +420 -0
  943. claude_mpm/tools/socketio_debug.py +671 -0
  944. claude_mpm/utils/__init__.py +8 -8
  945. claude_mpm/utils/agent_dependency_loader.py +1189 -0
  946. claude_mpm/utils/agent_filters.py +261 -0
  947. claude_mpm/utils/common.py +544 -0
  948. claude_mpm/utils/config_manager.py +168 -126
  949. claude_mpm/utils/console.py +11 -0
  950. claude_mpm/utils/database_connector.py +298 -0
  951. claude_mpm/utils/dependency_cache.py +373 -0
  952. claude_mpm/utils/dependency_manager.py +60 -59
  953. claude_mpm/utils/dependency_strategies.py +381 -0
  954. claude_mpm/utils/display_helper.py +260 -0
  955. claude_mpm/utils/environment_context.py +313 -0
  956. claude_mpm/utils/error_handler.py +78 -66
  957. claude_mpm/utils/file_utils.py +305 -0
  958. claude_mpm/utils/framework_detection.py +12 -11
  959. claude_mpm/utils/git_analyzer.py +407 -0
  960. claude_mpm/utils/gitignore.py +244 -0
  961. claude_mpm/utils/import_migration_example.py +12 -60
  962. claude_mpm/utils/imports.py +48 -45
  963. claude_mpm/utils/log_cleanup.py +627 -0
  964. claude_mpm/utils/migration.py +372 -0
  965. claude_mpm/utils/path_operations.py +110 -104
  966. claude_mpm/utils/progress.py +387 -0
  967. claude_mpm/utils/robust_installer.py +844 -0
  968. claude_mpm/utils/session_logging.py +121 -0
  969. claude_mpm/utils/structured_questions.py +619 -0
  970. claude_mpm/utils/subprocess_utils.py +343 -0
  971. claude_mpm/validation/__init__.py +1 -1
  972. claude_mpm/validation/agent_validator.py +214 -108
  973. claude_mpm/validation/frontmatter_validator.py +252 -0
  974. claude_mpm-5.4.85.dist-info/METADATA +1023 -0
  975. claude_mpm-5.4.85.dist-info/RECORD +980 -0
  976. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.85.dist-info}/entry_points.txt +1 -3
  977. claude_mpm-5.4.85.dist-info/licenses/LICENSE +94 -0
  978. claude_mpm-5.4.85.dist-info/licenses/LICENSE-FAQ.md +153 -0
  979. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -88
  980. claude_mpm/agents/INSTRUCTIONS.md +0 -352
  981. claude_mpm/agents/backups/INSTRUCTIONS.md +0 -352
  982. claude_mpm/agents/base_agent_loader.py +0 -529
  983. claude_mpm/agents/schema/agent_schema.json +0 -314
  984. claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -36
  985. claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +0 -46
  986. claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +0 -45
  987. claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +0 -49
  988. claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +0 -46
  989. claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +0 -45
  990. claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +0 -49
  991. claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +0 -46
  992. claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +0 -46
  993. claude_mpm/agents/templates/data_engineer.json +0 -110
  994. claude_mpm/agents/templates/documentation.json +0 -109
  995. claude_mpm/agents/templates/engineer.json +0 -113
  996. claude_mpm/agents/templates/ops.json +0 -109
  997. claude_mpm/agents/templates/pm.json +0 -25
  998. claude_mpm/agents/templates/qa.json +0 -111
  999. claude_mpm/agents/templates/research.json +0 -65
  1000. claude_mpm/agents/templates/security.json +0 -113
  1001. claude_mpm/agents/templates/test_integration.json +0 -112
  1002. claude_mpm/agents/templates/version_control.json +0 -107
  1003. claude_mpm/cli/commands/ui.py +0 -57
  1004. claude_mpm/core/simple_runner.py +0 -1046
  1005. claude_mpm/dashboard/open_dashboard.py +0 -34
  1006. claude_mpm/deployment_paths.py +0 -261
  1007. claude_mpm/hooks/builtin/__init__.py +0 -1
  1008. claude_mpm/hooks/builtin/logging_hook_example.py +0 -165
  1009. claude_mpm/hooks/builtin/memory_hooks_example.py +0 -67
  1010. claude_mpm/hooks/builtin/mpm_command_hook.py +0 -125
  1011. claude_mpm/hooks/builtin/post_delegation_hook_example.py +0 -124
  1012. claude_mpm/hooks/builtin/pre_delegation_hook_example.py +0 -125
  1013. claude_mpm/hooks/builtin/submit_hook_example.py +0 -100
  1014. claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +0 -237
  1015. claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +0 -240
  1016. claude_mpm/hooks/builtin/workflow_start_hook.py +0 -181
  1017. claude_mpm/orchestration/__init__.py +0 -6
  1018. claude_mpm/orchestration/archive/direct_orchestrator.py +0 -195
  1019. claude_mpm/orchestration/archive/factory.py +0 -215
  1020. claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +0 -188
  1021. claude_mpm/orchestration/archive/hook_integration_example.py +0 -178
  1022. claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +0 -826
  1023. claude_mpm/orchestration/archive/orchestrator.py +0 -501
  1024. claude_mpm/orchestration/archive/pexpect_orchestrator.py +0 -252
  1025. claude_mpm/orchestration/archive/pty_orchestrator.py +0 -270
  1026. claude_mpm/orchestration/archive/simple_orchestrator.py +0 -82
  1027. claude_mpm/orchestration/archive/subprocess_orchestrator.py +0 -801
  1028. claude_mpm/orchestration/archive/system_prompt_orchestrator.py +0 -278
  1029. claude_mpm/orchestration/archive/wrapper_orchestrator.py +0 -187
  1030. claude_mpm/schemas/workflow_validator.py +0 -411
  1031. claude_mpm/services/agent_deployment.py +0 -1534
  1032. claude_mpm/services/agent_lifecycle_manager.py +0 -1169
  1033. claude_mpm/services/agent_memory_manager.py +0 -1415
  1034. claude_mpm/services/agent_registry.py +0 -676
  1035. claude_mpm/services/deployed_agent_discovery.py +0 -226
  1036. claude_mpm/services/framework_agent_loader.py +0 -337
  1037. claude_mpm/services/framework_claude_md_generator.py +0 -621
  1038. claude_mpm/services/health_monitor.py +0 -892
  1039. claude_mpm/services/memory_router.py +0 -538
  1040. claude_mpm/services/parent_directory_manager/__init__.py +0 -577
  1041. claude_mpm/services/parent_directory_manager/backup_manager.py +0 -258
  1042. claude_mpm/services/parent_directory_manager/config_manager.py +0 -210
  1043. claude_mpm/services/parent_directory_manager/deduplication_manager.py +0 -279
  1044. claude_mpm/services/parent_directory_manager/framework_protector.py +0 -143
  1045. claude_mpm/services/parent_directory_manager/operations.py +0 -186
  1046. claude_mpm/services/parent_directory_manager/state_manager.py +0 -624
  1047. claude_mpm/services/parent_directory_manager/template_deployer.py +0 -579
  1048. claude_mpm/services/parent_directory_manager/validation_manager.py +0 -378
  1049. claude_mpm/services/parent_directory_manager/version_control_helper.py +0 -339
  1050. claude_mpm/services/parent_directory_manager/version_manager.py +0 -222
  1051. claude_mpm/services/standalone_socketio_server.py +0 -1300
  1052. claude_mpm/services/ticket_manager_di.py +0 -318
  1053. claude_mpm/services/ticketing_service_original.py +0 -508
  1054. claude_mpm/ui/__init__.py +0 -1
  1055. claude_mpm/ui/rich_terminal_ui.py +0 -295
  1056. claude_mpm/ui/terminal_ui.py +0 -328
  1057. claude_mpm/utils/paths.py +0 -289
  1058. claude_mpm-3.4.10.dist-info/METADATA +0 -183
  1059. claude_mpm-3.4.10.dist-info/RECORD +0 -201
  1060. claude_mpm-3.4.10.dist-info/licenses/LICENSE +0 -21
  1061. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.85.dist-info}/WHEEL +0 -0
  1062. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.85.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1478 @@
1
+ """Multi-Source Agent Deployment Service
2
+
3
+ This service implements proper version comparison across multiple agent sources,
4
+ ensuring the highest version agent is deployed regardless of source.
5
+
6
+ Key Features:
7
+ - Discovers agents from multiple sources (system templates, project agents, user agents)
8
+ - Compares versions across all sources
9
+ - Deploys the highest version for each agent
10
+ - Tracks which source provided the deployed agent
11
+ - Maintains backward compatibility with existing deployment modes
12
+ """
13
+
14
+ import json
15
+ import os
16
+ from pathlib import Path
17
+ from typing import Any, Dict, List, Optional, Tuple
18
+
19
+ import yaml
20
+
21
+ from claude_mpm.core.config import Config
22
+ from claude_mpm.core.logging_config import get_logger
23
+
24
+ from .agent_discovery_service import AgentDiscoveryService
25
+ from .agent_version_manager import AgentVersionManager
26
+ from .remote_agent_discovery_service import RemoteAgentDiscoveryService
27
+
28
+
29
+ def _normalize_agent_name(name: str) -> str:
30
+ """Normalize agent name for consistent comparison.
31
+
32
+ Converts spaces, underscores to hyphens and lowercases.
33
+ Examples:
34
+ "Dart Engineer" -> "dart-engineer"
35
+ "dart_engineer" -> "dart-engineer"
36
+ "DART-ENGINEER" -> "dart-engineer"
37
+ """
38
+ return name.lower().replace(" ", "-").replace("_", "-")
39
+
40
+
41
+ class MultiSourceAgentDeploymentService:
42
+ """Service for deploying agents from multiple sources with version comparison.
43
+
44
+ This service ensures that the highest version of each agent is deployed,
45
+ regardless of whether it comes from system templates, project agents,
46
+ user agents, or remote agents.
47
+
48
+ 4-Tier Agent Discovery:
49
+ 1. System templates (lowest priority) - Built-in agents
50
+ 2. User agents (DEPRECATED) - User-level customizations (~/.claude-mpm/agents/)
51
+ 3. Remote agents - Agents cached from GitHub
52
+ 4. Project agents (highest priority) - Project-specific customizations
53
+
54
+ WHY: The current system processes agents from a single source at a time,
55
+ which can result in lower version agents being deployed if they exist in
56
+ a higher priority source. This service fixes that by comparing versions
57
+ across all sources.
58
+
59
+ DEPRECATION: User-level agents (~/.claude-mpm/agents/) are deprecated and
60
+ will be removed in v5.0.0. Use project-level agents instead.
61
+ """
62
+
63
+ def __init__(self):
64
+ """Initialize the multi-source deployment service."""
65
+ self.logger = get_logger(__name__)
66
+ self.version_manager = AgentVersionManager()
67
+
68
+ def _read_template_version(self, template_path: Path) -> Optional[str]:
69
+ """Read version from template file (supports both .md and .json formats).
70
+
71
+ For .md files: Extract version from YAML frontmatter
72
+ For .json files: Extract version from JSON structure
73
+
74
+ Args:
75
+ template_path: Path to template file
76
+
77
+ Returns:
78
+ Version string or None if version cannot be extracted
79
+ """
80
+ try:
81
+ if template_path.suffix == ".md":
82
+ # Parse markdown with YAML frontmatter
83
+ content = template_path.read_text()
84
+
85
+ # Extract YAML frontmatter (between --- markers)
86
+ if not content.strip().startswith("---"):
87
+ return None
88
+
89
+ parts = content.split("---", 2)
90
+ if len(parts) < 3:
91
+ return None
92
+
93
+ # Parse YAML frontmatter
94
+ frontmatter = yaml.safe_load(parts[1])
95
+ if not frontmatter:
96
+ return None
97
+
98
+ # Extract version from frontmatter
99
+ version = frontmatter.get("version")
100
+ return version if version else None
101
+
102
+ if template_path.suffix == ".json":
103
+ # Parse JSON template
104
+ template_data = json.loads(template_path.read_text())
105
+ metadata = template_data.get("metadata", {})
106
+ version = (
107
+ template_data.get("agent_version")
108
+ or template_data.get("version")
109
+ or metadata.get("version")
110
+ )
111
+ return version if version else None
112
+
113
+ self.logger.warning(
114
+ f"Unknown template format: {template_path.suffix} for {template_path.name}"
115
+ )
116
+ return None
117
+
118
+ except yaml.YAMLError as e:
119
+ self.logger.warning(
120
+ f"Invalid YAML frontmatter in {template_path.name}: {e}"
121
+ )
122
+ return None
123
+ except json.JSONDecodeError as e:
124
+ self.logger.warning(f"Invalid JSON in {template_path.name}: {e}")
125
+ return None
126
+ except Exception as e:
127
+ self.logger.warning(
128
+ f"Error reading template version from {template_path.name}: {e}"
129
+ )
130
+ return None
131
+
132
+ def _build_canonical_id_for_agent(self, agent_info: Dict[str, Any]) -> str:
133
+ """Build or retrieve canonical_id for an agent.
134
+
135
+ NEW: Supports enhanced agent matching via canonical_id.
136
+
137
+ Priority:
138
+ 1. Use existing canonical_id from agent_info if present
139
+ 2. Generate from collection_id + agent_id if available
140
+ 3. Fallback to legacy:{filename} for backward compatibility
141
+
142
+ Args:
143
+ agent_info: Agent dictionary with metadata
144
+
145
+ Returns:
146
+ Canonical ID string for matching
147
+
148
+ Example:
149
+ Remote agent: "bobmatnyc/claude-mpm-agents:pm"
150
+ Legacy agent: "legacy:custom-agent"
151
+ """
152
+ # Priority 1: Existing canonical_id
153
+ if "canonical_id" in agent_info:
154
+ return agent_info["canonical_id"]
155
+
156
+ # Priority 2: Generate from collection_id + agent_id
157
+ collection_id = agent_info.get("collection_id")
158
+ agent_id = agent_info.get("agent_id")
159
+
160
+ if collection_id and agent_id:
161
+ canonical_id = f"{collection_id}:{agent_id}"
162
+ # Cache it in agent_info for future use
163
+ agent_info["canonical_id"] = canonical_id
164
+ return canonical_id
165
+
166
+ # Priority 3: Fallback to legacy format
167
+ # Use filename or agent name
168
+ agent_name = agent_info.get("name") or agent_info.get("metadata", {}).get(
169
+ "name", "unknown"
170
+ )
171
+
172
+ # Extract filename from path
173
+ path_str = (
174
+ agent_info.get("path")
175
+ or agent_info.get("file_path")
176
+ or agent_info.get("source_file")
177
+ )
178
+
179
+ if path_str:
180
+ filename = Path(path_str).stem
181
+ canonical_id = f"legacy:{filename}"
182
+ else:
183
+ canonical_id = f"legacy:{agent_name}"
184
+
185
+ # Cache it
186
+ agent_info["canonical_id"] = canonical_id
187
+ return canonical_id
188
+
189
+ def discover_agents_from_all_sources(
190
+ self,
191
+ system_templates_dir: Optional[Path] = None,
192
+ project_agents_dir: Optional[Path] = None,
193
+ user_agents_dir: Optional[Path] = None,
194
+ agents_cache_dir: Optional[Path] = None,
195
+ working_directory: Optional[Path] = None,
196
+ ) -> Dict[str, List[Dict[str, Any]]]:
197
+ """Discover agents from all 4 tiers (system, user, cache, project).
198
+
199
+ Priority hierarchy (highest to lowest):
200
+ 4. Project agents - Highest priority, project-specific customizations
201
+ 3. Cached agents - GitHub-synced agents from cache
202
+ 2. User agents - DEPRECATED, user-level customizations
203
+ 1. System templates - Lowest priority, built-in agents
204
+
205
+ Args:
206
+ system_templates_dir: Directory containing system agent templates
207
+ project_agents_dir: Directory containing project-specific agents
208
+ user_agents_dir: Directory containing user custom agents (DEPRECATED)
209
+ agents_cache_dir: Directory containing cached agents from Git sources
210
+ working_directory: Current working directory for finding project agents
211
+
212
+ Returns:
213
+ Dictionary mapping agent names to list of agent info from different sources
214
+
215
+ Deprecation Warning:
216
+ User-level agents are deprecated and will show a warning if found.
217
+ Use 'claude-mpm agents migrate-to-project' to migrate them.
218
+ """
219
+ agents_by_name = {}
220
+
221
+ # Determine directories if not provided
222
+ if not system_templates_dir:
223
+ # Use default system templates location
224
+ from claude_mpm.config.paths import paths
225
+
226
+ system_templates_dir = paths.agents_dir / "templates"
227
+
228
+ if not project_agents_dir and working_directory:
229
+ # Check for project agents in working directory
230
+ project_agents_dir = working_directory / ".claude-mpm" / "agents"
231
+ if not project_agents_dir.exists():
232
+ project_agents_dir = None
233
+
234
+ if not user_agents_dir:
235
+ # Check for user agents in home directory
236
+ user_agents_dir = Path.home() / ".claude-mpm" / "agents"
237
+ if not user_agents_dir.exists():
238
+ user_agents_dir = None
239
+
240
+ if not agents_cache_dir:
241
+ # Check for agents in cache directory
242
+ cache_dir = Path.home() / ".claude-mpm" / "cache"
243
+ agents_cache_dir = cache_dir / "agents"
244
+ if not agents_cache_dir.exists():
245
+ agents_cache_dir = None
246
+
247
+ # Discover agents from each source in priority order
248
+ # Note: We process in reverse priority order (system first) and build up the dictionary
249
+ # The select_highest_version_agents() method will handle the actual prioritization
250
+ sources = [
251
+ ("system", system_templates_dir),
252
+ ("user", user_agents_dir),
253
+ ("remote", agents_cache_dir),
254
+ ("project", project_agents_dir),
255
+ ]
256
+
257
+ # Track if we found user agents for deprecation warning
258
+ user_agents_found = False
259
+
260
+ for source_name, source_dir in sources:
261
+ if source_dir and source_dir.exists():
262
+ self.logger.debug(
263
+ f"Discovering agents from {source_name} source: {source_dir}"
264
+ )
265
+
266
+ # Use appropriate discovery service based on source type
267
+ if source_name == "remote":
268
+ # Remote agents are Markdown, use RemoteAgentDiscoveryService
269
+ remote_service = RemoteAgentDiscoveryService(source_dir)
270
+ agents = remote_service.discover_remote_agents()
271
+ else:
272
+ # Other sources are JSON, use AgentDiscoveryService
273
+ discovery_service = AgentDiscoveryService(source_dir)
274
+ # Pass log_discovery=False to avoid duplicate logging
275
+ agents = discovery_service.list_available_agents(
276
+ log_discovery=False
277
+ )
278
+
279
+ # Track user agents for deprecation warning
280
+ if source_name == "user" and agents:
281
+ user_agents_found = True
282
+
283
+ for agent_info in agents:
284
+ agent_name = agent_info.get("name") or agent_info.get(
285
+ "metadata", {}
286
+ ).get("name")
287
+ if not agent_name:
288
+ continue
289
+
290
+ # Add source information
291
+ agent_info["source"] = source_name
292
+ agent_info["source_dir"] = str(source_dir)
293
+
294
+ # NEW: Build canonical_id for enhanced matching
295
+ canonical_id = self._build_canonical_id_for_agent(agent_info)
296
+
297
+ # Group by canonical_id (PRIMARY) for enhanced matching
298
+ # This allows matching agents from different sources with same canonical_id
299
+ # while maintaining backward compatibility with name-based matching
300
+ matching_key = canonical_id
301
+
302
+ # Initialize list if this is the first occurrence of this agent
303
+ if matching_key not in agents_by_name:
304
+ agents_by_name[matching_key] = []
305
+
306
+ agents_by_name[matching_key].append(agent_info)
307
+
308
+ # Use more specific log message
309
+ self.logger.info(
310
+ f"Discovered {len(agents)} {source_name} agent templates from {source_dir.name}"
311
+ )
312
+
313
+ # Show deprecation warning if user agents found
314
+ if user_agents_found:
315
+ self.logger.warning(
316
+ "\n"
317
+ "⚠️ DEPRECATION WARNING: User-level agents found in ~/.claude-mpm/agents/\n"
318
+ " User-level agent deployment is deprecated and will be removed in v5.0.0\n"
319
+ "\n"
320
+ " Why this change?\n"
321
+ " - Project isolation: Agents should be project-specific\n"
322
+ " - Version control: Project agents can be versioned with your code\n"
323
+ " - Team consistency: All team members use the same agents\n"
324
+ "\n"
325
+ " Migration:\n"
326
+ " 1. Run: claude-mpm agents migrate-to-project\n"
327
+ " 2. Verify agents work in .claude-mpm/agents/\n"
328
+ " 3. Remove: rm -rf ~/.claude-mpm/agents/\n"
329
+ "\n"
330
+ " Learn more: https://docs.claude-mpm.dev/agents/migration\n"
331
+ )
332
+
333
+ return agents_by_name
334
+
335
+ def get_agents_by_collection(
336
+ self,
337
+ collection_id: str,
338
+ agents_cache_dir: Optional[Path] = None,
339
+ ) -> List[Dict[str, Any]]:
340
+ """Get all agents from a specific collection.
341
+
342
+ NEW: Enables collection-based agent selection.
343
+
344
+ Args:
345
+ collection_id: Collection identifier (e.g., "bobmatnyc/claude-mpm-agents")
346
+ agents_cache_dir: Directory containing agents cache
347
+
348
+ Returns:
349
+ List of agent dictionaries from the specified collection
350
+
351
+ Example:
352
+ >>> service = MultiSourceAgentDeploymentService()
353
+ >>> agents = service.get_agents_by_collection("bobmatnyc/claude-mpm-agents")
354
+ >>> len(agents)
355
+ 45
356
+ """
357
+ if not agents_cache_dir:
358
+ cache_dir = Path.home() / ".claude-mpm" / "cache"
359
+ agents_cache_dir = cache_dir / "agents"
360
+
361
+ if not agents_cache_dir.exists():
362
+ self.logger.warning(f"Agents cache directory not found: {agents_cache_dir}")
363
+ return []
364
+
365
+ # Use RemoteAgentDiscoveryService to get collection agents
366
+ remote_service = RemoteAgentDiscoveryService(agents_cache_dir)
367
+ collection_agents = remote_service.get_agents_by_collection(collection_id)
368
+
369
+ self.logger.info(
370
+ f"Retrieved {len(collection_agents)} agents from collection '{collection_id}'"
371
+ )
372
+
373
+ return collection_agents
374
+
375
+ def select_highest_version_agents(
376
+ self, agents_by_name: Dict[str, List[Dict[str, Any]]]
377
+ ) -> Dict[str, Dict[str, Any]]:
378
+ """Select the highest version agent from multiple sources.
379
+
380
+ Args:
381
+ agents_by_name: Dictionary mapping agent names to list of agent info
382
+
383
+ Returns:
384
+ Dictionary mapping agent names to the highest version agent info
385
+ """
386
+ selected_agents = {}
387
+
388
+ for agent_name, agent_versions in agents_by_name.items():
389
+ if not agent_versions:
390
+ continue
391
+
392
+ # If only one version exists, use it
393
+ if len(agent_versions) == 1:
394
+ selected_agents[agent_name] = agent_versions[0]
395
+ self.logger.debug(
396
+ f"Agent '{agent_name}' has single source: {agent_versions[0]['source']}"
397
+ )
398
+ continue
399
+
400
+ # Compare versions to find the highest
401
+ highest_version_agent = None
402
+ highest_version_tuple = (0, 0, 0)
403
+
404
+ for agent_info in agent_versions:
405
+ version_str = agent_info.get("version", "0.0.0")
406
+ version_tuple = self.version_manager.parse_version(version_str)
407
+
408
+ self.logger.debug(
409
+ f"Agent '{agent_name}' from {agent_info['source']}: "
410
+ f"version {version_str} -> {version_tuple}"
411
+ )
412
+
413
+ # Compare with current highest
414
+ if (
415
+ self.version_manager.compare_versions(
416
+ version_tuple, highest_version_tuple
417
+ )
418
+ > 0
419
+ ):
420
+ highest_version_agent = agent_info
421
+ highest_version_tuple = version_tuple
422
+
423
+ if highest_version_agent:
424
+ selected_agents[agent_name] = highest_version_agent
425
+ self.logger.info(
426
+ f"Selected agent '{agent_name}' version {highest_version_agent['version']} "
427
+ f"from {highest_version_agent['source']} source"
428
+ )
429
+
430
+ # Log if a higher priority source was overridden by version
431
+ for other_agent in agent_versions:
432
+ if other_agent != highest_version_agent:
433
+ # Parse both versions for comparison
434
+ other_version = self.version_manager.parse_version(
435
+ other_agent.get("version", "0.0.0")
436
+ )
437
+ highest_version = self.version_manager.parse_version(
438
+ highest_version_agent.get("version", "0.0.0")
439
+ )
440
+
441
+ # Compare the versions
442
+ version_comparison = self.version_manager.compare_versions(
443
+ other_version, highest_version
444
+ )
445
+
446
+ # Only warn if the other version is actually lower
447
+ if version_comparison < 0:
448
+ if (
449
+ other_agent["source"] == "project"
450
+ and highest_version_agent["source"] == "system"
451
+ ):
452
+ self.logger.warning(
453
+ f"Project agent '{agent_name}' v{other_agent['version']} "
454
+ f"overridden by higher system version v{highest_version_agent['version']}"
455
+ )
456
+ elif other_agent[
457
+ "source"
458
+ ] == "user" and highest_version_agent["source"] in [
459
+ "system",
460
+ "project",
461
+ ]:
462
+ self.logger.warning(
463
+ f"User agent '{agent_name}' v{other_agent['version']} "
464
+ f"overridden by higher {highest_version_agent['source']} version v{highest_version_agent['version']}"
465
+ )
466
+ elif (
467
+ version_comparison == 0
468
+ and other_agent["source"] != highest_version_agent["source"]
469
+ ):
470
+ # Log info when versions are equal but different sources
471
+ self.logger.info(
472
+ f"Using {highest_version_agent['source']} source for '{agent_name}' "
473
+ f"(same version v{highest_version_agent['version']} as {other_agent['source']} source)"
474
+ )
475
+
476
+ return selected_agents
477
+
478
+ def get_agents_for_deployment(
479
+ self,
480
+ system_templates_dir: Optional[Path] = None,
481
+ project_agents_dir: Optional[Path] = None,
482
+ user_agents_dir: Optional[Path] = None,
483
+ agents_cache_dir: Optional[Path] = None,
484
+ working_directory: Optional[Path] = None,
485
+ excluded_agents: Optional[List[str]] = None,
486
+ config: Optional[Config] = None,
487
+ cleanup_outdated: bool = True,
488
+ ) -> Tuple[Dict[str, Path], Dict[str, str], Dict[str, Any]]:
489
+ """Get the highest version agents from all 4 tiers for deployment.
490
+
491
+ Args:
492
+ system_templates_dir: Directory containing system agent templates
493
+ project_agents_dir: Directory containing project-specific agents
494
+ user_agents_dir: Directory containing user custom agents (DEPRECATED)
495
+ agents_cache_dir: Directory containing cached agents from Git sources
496
+ working_directory: Current working directory for finding project agents
497
+ excluded_agents: List of agent names to exclude from deployment
498
+ config: Configuration object for additional filtering
499
+ cleanup_outdated: Whether to cleanup outdated user agents (default: True)
500
+
501
+ Returns:
502
+ Tuple of:
503
+ - Dictionary mapping agent names to template file paths
504
+ - Dictionary mapping agent names to their source
505
+ - Dictionary with cleanup results (removed, preserved, errors)
506
+ """
507
+ # Discover all available agents from 4 tiers
508
+ agents_by_name = self.discover_agents_from_all_sources(
509
+ system_templates_dir=system_templates_dir,
510
+ project_agents_dir=project_agents_dir,
511
+ user_agents_dir=user_agents_dir,
512
+ agents_cache_dir=agents_cache_dir,
513
+ working_directory=working_directory,
514
+ )
515
+
516
+ # Select highest version for each agent
517
+ selected_agents = self.select_highest_version_agents(agents_by_name)
518
+
519
+ # Clean up outdated user agents if enabled
520
+ cleanup_results = {"removed": [], "preserved": [], "errors": []}
521
+ if cleanup_outdated:
522
+ # Check if cleanup is enabled in config or environment
523
+ cleanup_enabled = True
524
+
525
+ # Check environment variable first (for CI/CD and testing)
526
+ env_cleanup = os.environ.get("CLAUDE_MPM_CLEANUP_USER_AGENTS", "").lower()
527
+ if env_cleanup in ["false", "0", "no", "disabled"]:
528
+ cleanup_enabled = False
529
+ self.logger.debug(
530
+ "User agent cleanup disabled via environment variable"
531
+ )
532
+
533
+ # Check config if environment doesn't disable it
534
+ if cleanup_enabled and config:
535
+ cleanup_enabled = config.get(
536
+ "agent_deployment.cleanup_outdated_user_agents", True
537
+ )
538
+
539
+ if cleanup_enabled:
540
+ cleanup_results = self.cleanup_outdated_user_agents(
541
+ agents_by_name, selected_agents
542
+ )
543
+
544
+ # Apply exclusion filters
545
+ if excluded_agents:
546
+ # Find agents to remove by matching normalized names
547
+ # Normalization handles: "Dart Engineer", "dart_engineer", "dart-engineer"
548
+ agents_to_remove = []
549
+ excluded_set = {_normalize_agent_name(name) for name in excluded_agents}
550
+
551
+ for canonical_id, agent_info in list(selected_agents.items()):
552
+ # Check agent name field (normalized)
553
+ agent_name = _normalize_agent_name(agent_info.get("name", ""))
554
+
555
+ # Also check the agent_id portion of canonical_id (after the colon)
556
+ # Example: "bobmatnyc/claude-mpm-agents:pm" -> "pm"
557
+ raw_agent_id = (
558
+ canonical_id.split(":")[-1] if ":" in canonical_id else canonical_id
559
+ )
560
+ agent_id = _normalize_agent_name(raw_agent_id)
561
+
562
+ # Check file stem from path (most reliable match)
563
+ file_stem = ""
564
+ path_str = agent_info.get("path") or agent_info.get("file_path")
565
+ if path_str:
566
+ file_stem = _normalize_agent_name(Path(path_str).stem)
567
+
568
+ if (
569
+ agent_name in excluded_set
570
+ or agent_id in excluded_set
571
+ or file_stem in excluded_set
572
+ ):
573
+ agents_to_remove.append(canonical_id)
574
+ self.logger.info(
575
+ f"Excluding agent '{agent_info.get('name', raw_agent_id)}' "
576
+ f"(canonical_id: {canonical_id}) from deployment"
577
+ )
578
+
579
+ # Remove matched agents
580
+ for canonical_id in agents_to_remove:
581
+ del selected_agents[canonical_id]
582
+
583
+ # Apply config-based filtering if provided
584
+ if config:
585
+ selected_agents = self._apply_config_filters(selected_agents, config)
586
+
587
+ # Create deployment mappings
588
+ agents_to_deploy = {}
589
+ agent_sources = {}
590
+
591
+ for agent_name, agent_info in selected_agents.items():
592
+ # Defensive: Try multiple path fields for backward compatibility (ticket 1M-480)
593
+ # Priority: 'path' -> 'file_path' -> 'source_file'
594
+ path_str = (
595
+ agent_info.get("path")
596
+ or agent_info.get("file_path")
597
+ or agent_info.get("source_file")
598
+ )
599
+
600
+ if not path_str:
601
+ self.logger.warning(
602
+ f"Agent '{agent_name}' missing path information (no 'path', 'file_path', or 'source_file' field)"
603
+ )
604
+ continue
605
+
606
+ template_path = Path(path_str)
607
+ if template_path.exists():
608
+ # Use the file stem as the key for consistency
609
+ file_stem = template_path.stem
610
+ agents_to_deploy[file_stem] = template_path
611
+ agent_sources[file_stem] = agent_info["source"]
612
+
613
+ # Also keep the display name mapping for logging
614
+ if file_stem != agent_name:
615
+ self.logger.debug(f"Mapping '{agent_name}' -> '{file_stem}'")
616
+ else:
617
+ self.logger.warning(
618
+ f"Template file not found for agent '{agent_name}': {template_path}"
619
+ )
620
+
621
+ self.logger.info(
622
+ f"Selected {len(agents_to_deploy)} agents for deployment "
623
+ f"(system: {sum(1 for s in agent_sources.values() if s == 'system')}, "
624
+ f"project: {sum(1 for s in agent_sources.values() if s == 'project')}, "
625
+ f"user: {sum(1 for s in agent_sources.values() if s == 'user')})"
626
+ )
627
+
628
+ return agents_to_deploy, agent_sources, cleanup_results
629
+
630
+ def cleanup_excluded_agents(
631
+ self,
632
+ deployed_agents_dir: Path,
633
+ agents_to_deploy: Dict[str, Path],
634
+ ) -> Dict[str, Any]:
635
+ """Remove agents from deployed directory that aren't in the deployment list.
636
+
637
+ Similar to skill cleanup logic, this removes agents that were previously
638
+ deployed but are no longer in the enabled agents list (e.g., filtered out
639
+ by profile configuration).
640
+
641
+ Args:
642
+ deployed_agents_dir: Directory containing deployed agents (~/.claude/agents)
643
+ agents_to_deploy: Dictionary mapping agent file stems to template paths
644
+
645
+ Returns:
646
+ Dictionary with cleanup results:
647
+ - removed: List of removed agent names
648
+ - errors: List of errors during cleanup
649
+ """
650
+ cleanup_results = {"removed": [], "errors": []}
651
+
652
+ # Safety check - only operate on deployed agents directory
653
+ if not deployed_agents_dir.exists():
654
+ self.logger.debug(
655
+ "Deployed agents directory does not exist, no cleanup needed"
656
+ )
657
+ return cleanup_results
658
+
659
+ # Build set of agent names that should exist (file stems without .md extension)
660
+ expected_agents = set(agents_to_deploy.keys())
661
+
662
+ try:
663
+ # Check each file in deployed_agents_dir
664
+ for item in deployed_agents_dir.iterdir():
665
+ # Only process .md files
666
+ if not item.is_file() or item.suffix != ".md":
667
+ continue
668
+
669
+ # Skip hidden files
670
+ if item.name.startswith("."):
671
+ continue
672
+
673
+ # Get agent name (file stem)
674
+ agent_name = item.stem
675
+
676
+ # Check if this agent should be kept
677
+ if agent_name not in expected_agents:
678
+ try:
679
+ # Security: Validate path is within deployed_agents_dir
680
+ resolved_item = item.resolve()
681
+ resolved_target = deployed_agents_dir.resolve()
682
+
683
+ if not str(resolved_item).startswith(str(resolved_target)):
684
+ self.logger.error(
685
+ f"Refusing to remove path outside target directory: {item}"
686
+ )
687
+ cleanup_results["errors"].append(
688
+ {
689
+ "agent": agent_name,
690
+ "error": "Path outside target directory",
691
+ }
692
+ )
693
+ continue
694
+
695
+ # Remove the agent file
696
+ item.unlink()
697
+ cleanup_results["removed"].append(agent_name)
698
+ self.logger.info(f"Removed excluded agent: {agent_name}")
699
+
700
+ except PermissionError as e:
701
+ error_msg = f"Permission denied removing {agent_name}: {e}"
702
+ self.logger.error(error_msg)
703
+ cleanup_results["errors"].append(
704
+ {"agent": agent_name, "error": error_msg}
705
+ )
706
+ except Exception as e:
707
+ error_msg = f"Error removing {agent_name}: {e}"
708
+ self.logger.error(error_msg)
709
+ cleanup_results["errors"].append(
710
+ {"agent": agent_name, "error": error_msg}
711
+ )
712
+
713
+ except Exception as e:
714
+ self.logger.error(f"Error during agent cleanup: {e}")
715
+ cleanup_results["errors"].append(
716
+ {"agent": "cleanup_process", "error": str(e)}
717
+ )
718
+
719
+ # Log cleanup summary
720
+ if cleanup_results["removed"]:
721
+ self.logger.info(
722
+ f"Cleanup complete: removed {len(cleanup_results['removed'])} excluded agents"
723
+ )
724
+ if cleanup_results["errors"]:
725
+ self.logger.warning(
726
+ f"Encountered {len(cleanup_results['errors'])} errors during cleanup"
727
+ )
728
+
729
+ return cleanup_results
730
+
731
+ def cleanup_outdated_user_agents(
732
+ self,
733
+ agents_by_name: Dict[str, List[Dict[str, Any]]],
734
+ selected_agents: Dict[str, Dict[str, Any]],
735
+ ) -> Dict[str, Any]:
736
+ """Remove outdated user agents when project or system agents have higher versions.
737
+
738
+ WHY: When project agents are updated to newer versions, outdated user agent
739
+ copies should be removed to prevent confusion and ensure the latest version
740
+ is always used. User agents with same or higher versions are preserved to
741
+ respect user customizations.
742
+
743
+ Args:
744
+ agents_by_name: Dictionary mapping agent names to list of agent info from different sources
745
+ selected_agents: Dictionary mapping agent names to the selected highest version agent
746
+
747
+ Returns:
748
+ Dictionary with cleanup results:
749
+ - removed: List of removed agent info
750
+ - preserved: List of preserved agent info with reasons
751
+ - errors: List of errors during cleanup
752
+ """
753
+ cleanup_results = {"removed": [], "preserved": [], "errors": []}
754
+
755
+ # Get user agents directory
756
+ user_agents_dir = Path.home() / ".claude-mpm" / "agents"
757
+
758
+ # Safety check - only operate on user agents directory
759
+ if not user_agents_dir.exists():
760
+ self.logger.debug("User agents directory does not exist, no cleanup needed")
761
+ return cleanup_results
762
+
763
+ for agent_name, agent_versions in agents_by_name.items():
764
+ # Skip if only one version exists
765
+ if len(agent_versions) < 2:
766
+ continue
767
+
768
+ selected = selected_agents.get(agent_name)
769
+ if not selected:
770
+ continue
771
+
772
+ # Process each version of this agent
773
+ for agent_info in agent_versions:
774
+ # Only consider user agents for cleanup
775
+ if agent_info["source"] != "user":
776
+ continue
777
+
778
+ # Defensive: Get path from agent_info (ticket 1M-480)
779
+ path_str = (
780
+ agent_info.get("path")
781
+ or agent_info.get("file_path")
782
+ or agent_info.get("source_file")
783
+ )
784
+ if not path_str:
785
+ self.logger.warning(
786
+ f"User agent '{agent_name}' missing path information, skipping cleanup"
787
+ )
788
+ continue
789
+
790
+ # Safety check - ensure path is within user agents directory
791
+ user_agent_path = Path(path_str)
792
+ try:
793
+ # Resolve paths to compare them safely
794
+ resolved_user_path = user_agent_path.resolve()
795
+ resolved_user_agents_dir = user_agents_dir.resolve()
796
+
797
+ # Verify the agent is actually in the user agents directory
798
+ if not str(resolved_user_path).startswith(
799
+ str(resolved_user_agents_dir)
800
+ ):
801
+ self.logger.warning(
802
+ f"Skipping cleanup for {agent_name}: path {user_agent_path} "
803
+ f"is not within user agents directory"
804
+ )
805
+ cleanup_results["errors"].append(
806
+ {
807
+ "agent": agent_name,
808
+ "error": "Path outside user agents directory",
809
+ }
810
+ )
811
+ continue
812
+ except Exception as e:
813
+ self.logger.error(f"Error resolving paths for {agent_name}: {e}")
814
+ cleanup_results["errors"].append(
815
+ {"agent": agent_name, "error": f"Path resolution error: {e}"}
816
+ )
817
+ continue
818
+
819
+ # Compare versions
820
+ user_version = self.version_manager.parse_version(
821
+ agent_info.get("version", "0.0.0")
822
+ )
823
+ selected_version = self.version_manager.parse_version(
824
+ selected.get("version", "0.0.0")
825
+ )
826
+
827
+ version_comparison = self.version_manager.compare_versions(
828
+ user_version, selected_version
829
+ )
830
+
831
+ # Determine action based on version comparison and selected source
832
+ if version_comparison < 0 and selected["source"] in [
833
+ "project",
834
+ "system",
835
+ ]:
836
+ # User agent has lower version than selected project/system agent - remove it
837
+ if user_agent_path.exists():
838
+ try:
839
+ # Log before removal for audit trail
840
+ self.logger.info(
841
+ f"Removing outdated user agent: {agent_name} "
842
+ f"v{self.version_manager.format_version_display(user_version)} "
843
+ f"(superseded by {selected['source']} "
844
+ f"v{self.version_manager.format_version_display(selected_version)})"
845
+ )
846
+
847
+ # Remove the file
848
+ user_agent_path.unlink()
849
+
850
+ cleanup_results["removed"].append(
851
+ {
852
+ "name": agent_name,
853
+ "version": self.version_manager.format_version_display(
854
+ user_version
855
+ ),
856
+ "path": str(user_agent_path),
857
+ "reason": f"Superseded by {selected['source']} v{self.version_manager.format_version_display(selected_version)}",
858
+ }
859
+ )
860
+ except PermissionError as e:
861
+ error_msg = f"Permission denied removing {agent_name}: {e}"
862
+ self.logger.error(error_msg)
863
+ cleanup_results["errors"].append(
864
+ {"agent": agent_name, "error": error_msg}
865
+ )
866
+ except Exception as e:
867
+ error_msg = f"Error removing {agent_name}: {e}"
868
+ self.logger.error(error_msg)
869
+ cleanup_results["errors"].append(
870
+ {"agent": agent_name, "error": error_msg}
871
+ )
872
+ else:
873
+ # Preserve the user agent
874
+ if version_comparison >= 0:
875
+ reason = "User version same or higher than selected version"
876
+ elif selected["source"] == "user":
877
+ reason = "User agent is the selected version"
878
+ else:
879
+ reason = "User customization preserved"
880
+
881
+ cleanup_results["preserved"].append(
882
+ {
883
+ "name": agent_name,
884
+ "version": self.version_manager.format_version_display(
885
+ user_version
886
+ ),
887
+ "reason": reason,
888
+ }
889
+ )
890
+
891
+ self.logger.debug(
892
+ f"Preserving user agent {agent_name} "
893
+ f"v{self.version_manager.format_version_display(user_version)}: {reason}"
894
+ )
895
+
896
+ # Log cleanup summary
897
+ if cleanup_results["removed"]:
898
+ self.logger.info(
899
+ f"Cleanup complete: removed {len(cleanup_results['removed'])} outdated user agents"
900
+ )
901
+ if cleanup_results["preserved"]:
902
+ self.logger.debug(
903
+ f"Preserved {len(cleanup_results['preserved'])} user agents"
904
+ )
905
+ if cleanup_results["errors"]:
906
+ self.logger.warning(
907
+ f"Encountered {len(cleanup_results['errors'])} errors during cleanup"
908
+ )
909
+
910
+ return cleanup_results
911
+
912
+ def _is_user_created_agent(self, agent_file: Path) -> bool:
913
+ """Check if an agent is user-created based on metadata.
914
+
915
+ User agents are identified by:
916
+ - Lack of MPM authorship indicators
917
+ - Missing version or v0.0.0
918
+ - Certain naming patterns
919
+
920
+ Args:
921
+ agent_file: Path to the agent file to check
922
+
923
+ Returns:
924
+ True if the agent appears to be user-created, False otherwise
925
+ """
926
+ try:
927
+ content = agent_file.read_text()
928
+
929
+ # Check for MPM authorship indicators
930
+ mpm_indicators = [
931
+ "author: claude-mpm",
932
+ "author: 'claude-mpm'",
933
+ 'author: "claude-mpm"',
934
+ "author: Claude MPM",
935
+ "Claude MPM Team",
936
+ "Generated by Claude MPM",
937
+ "claude-mpm-project",
938
+ ]
939
+
940
+ for indicator in mpm_indicators:
941
+ if indicator.lower() in content.lower():
942
+ return False # This is an MPM agent
943
+
944
+ # Check for version 0.0.0 (typical user agent default)
945
+ if "version: 0.0.0" in content or "version: '0.0.0'" in content:
946
+ return True
947
+
948
+ return True # Default to user-created if no MPM indicators
949
+
950
+ except Exception:
951
+ return True # Default to user-created if we can't read it
952
+
953
+ def _apply_config_filters(
954
+ self, selected_agents: Dict[str, Dict[str, Any]], config: Config
955
+ ) -> Dict[str, Dict[str, Any]]:
956
+ """Apply configuration-based filtering to selected agents.
957
+
958
+ Args:
959
+ selected_agents: Dictionary of selected agents
960
+ config: Configuration object
961
+
962
+ Returns:
963
+ Filtered dictionary of agents
964
+ """
965
+ filtered_agents = {}
966
+
967
+ # Get exclusion patterns from config
968
+ exclusion_patterns = config.get("agent_deployment.exclusion_patterns", [])
969
+
970
+ # Get environment-specific exclusions
971
+ environment = config.get("environment", "development")
972
+ env_exclusions = config.get(f"agent_deployment.{environment}_exclusions", [])
973
+
974
+ for agent_name, agent_info in selected_agents.items():
975
+ # Check exclusion patterns
976
+ excluded = False
977
+
978
+ for pattern in exclusion_patterns:
979
+ if pattern in agent_name:
980
+ self.logger.debug(
981
+ f"Excluding '{agent_name}' due to pattern '{pattern}'"
982
+ )
983
+ excluded = True
984
+ break
985
+
986
+ # Check environment exclusions
987
+ if not excluded and agent_name in env_exclusions:
988
+ self.logger.debug(
989
+ f"Excluding '{agent_name}' due to {environment} environment"
990
+ )
991
+ excluded = True
992
+
993
+ if not excluded:
994
+ filtered_agents[agent_name] = agent_info
995
+
996
+ return filtered_agents
997
+
998
+ def compare_deployed_versions(
999
+ self,
1000
+ deployed_agents_dir: Path,
1001
+ agents_to_deploy: Dict[str, Path],
1002
+ agent_sources: Dict[str, str],
1003
+ ) -> Dict[str, Any]:
1004
+ """Compare deployed agent versions with candidates for deployment.
1005
+
1006
+ Args:
1007
+ deployed_agents_dir: Directory containing currently deployed agents
1008
+ agents_to_deploy: Dictionary mapping agent names to template paths
1009
+ agent_sources: Dictionary mapping agent names to their sources
1010
+
1011
+ Returns:
1012
+ Dictionary with comparison results including which agents need updates
1013
+ """
1014
+ comparison_results = {
1015
+ "needs_update": [],
1016
+ "up_to_date": [],
1017
+ "new_agents": [],
1018
+ "orphaned_agents": [], # System agents without templates
1019
+ "user_agents": [], # User-created agents (no templates required)
1020
+ "version_upgrades": [],
1021
+ "version_downgrades": [],
1022
+ "source_changes": [],
1023
+ }
1024
+
1025
+ for agent_name, template_path in agents_to_deploy.items():
1026
+ deployed_file = deployed_agents_dir / f"{agent_name}.md"
1027
+
1028
+ if not deployed_file.exists():
1029
+ comparison_results["new_agents"].append(
1030
+ {
1031
+ "name": agent_name,
1032
+ "source": agent_sources[agent_name],
1033
+ "template": str(template_path),
1034
+ }
1035
+ )
1036
+ comparison_results["needs_update"].append(agent_name)
1037
+ continue
1038
+
1039
+ # Read template version using format-aware helper
1040
+ version_string = self._read_template_version(template_path)
1041
+ if not version_string:
1042
+ self.logger.warning(
1043
+ f"Could not extract version from template for '{agent_name}', skipping"
1044
+ )
1045
+ continue
1046
+
1047
+ try:
1048
+ template_version = self.version_manager.parse_version(version_string)
1049
+ except Exception as e:
1050
+ self.logger.warning(
1051
+ f"Error parsing version '{version_string}' for '{agent_name}': {e}"
1052
+ )
1053
+ continue
1054
+
1055
+ # Read deployed version
1056
+ try:
1057
+ deployed_content = deployed_file.read_text()
1058
+ deployed_version, _, _ = (
1059
+ self.version_manager.extract_version_from_frontmatter(
1060
+ deployed_content
1061
+ )
1062
+ )
1063
+
1064
+ # Extract source from deployed agent if available
1065
+ deployed_source = "unknown"
1066
+ if "source:" in deployed_content:
1067
+ import re
1068
+
1069
+ source_match = re.search(
1070
+ r"^source:\s*(.+)$", deployed_content, re.MULTILINE
1071
+ )
1072
+ if source_match:
1073
+ deployed_source = source_match.group(1).strip()
1074
+
1075
+ # If source is still unknown, try to infer it from deployment context
1076
+ if deployed_source == "unknown":
1077
+ deployed_source = self._infer_agent_source_from_context(
1078
+ agent_name, deployed_agents_dir
1079
+ )
1080
+ except Exception as e:
1081
+ self.logger.warning(f"Error reading deployed agent '{agent_name}': {e}")
1082
+ comparison_results["needs_update"].append(agent_name)
1083
+ continue
1084
+
1085
+ # Compare versions
1086
+ version_comparison = self.version_manager.compare_versions(
1087
+ template_version, deployed_version
1088
+ )
1089
+
1090
+ if version_comparison > 0:
1091
+ # Template version is higher
1092
+ comparison_results["version_upgrades"].append(
1093
+ {
1094
+ "name": agent_name,
1095
+ "deployed_version": self.version_manager.format_version_display(
1096
+ deployed_version
1097
+ ),
1098
+ "new_version": self.version_manager.format_version_display(
1099
+ template_version
1100
+ ),
1101
+ "source": agent_sources[agent_name],
1102
+ "previous_source": deployed_source,
1103
+ }
1104
+ )
1105
+ comparison_results["needs_update"].append(agent_name)
1106
+
1107
+ if deployed_source != agent_sources[agent_name]:
1108
+ comparison_results["source_changes"].append(
1109
+ {
1110
+ "name": agent_name,
1111
+ "from_source": deployed_source,
1112
+ "to_source": agent_sources[agent_name],
1113
+ }
1114
+ )
1115
+ elif version_comparison < 0:
1116
+ # Deployed version is higher (shouldn't happen with proper version management)
1117
+ comparison_results["version_downgrades"].append(
1118
+ {
1119
+ "name": agent_name,
1120
+ "deployed_version": self.version_manager.format_version_display(
1121
+ deployed_version
1122
+ ),
1123
+ "template_version": self.version_manager.format_version_display(
1124
+ template_version
1125
+ ),
1126
+ "warning": "Deployed version is higher than template",
1127
+ }
1128
+ )
1129
+ # Don't add to needs_update - keep the higher version
1130
+ else:
1131
+ # Versions are equal
1132
+ comparison_results["up_to_date"].append(
1133
+ {
1134
+ "name": agent_name,
1135
+ "version": self.version_manager.format_version_display(
1136
+ deployed_version
1137
+ ),
1138
+ "source": agent_sources[agent_name],
1139
+ }
1140
+ )
1141
+
1142
+ # Check for orphaned agents (deployed but no template)
1143
+ system_orphaned, user_orphaned = self._detect_orphaned_agents_simple(
1144
+ deployed_agents_dir, agents_to_deploy
1145
+ )
1146
+ comparison_results["orphaned_agents"] = system_orphaned
1147
+ comparison_results["user_agents"] = user_orphaned
1148
+
1149
+ # Log summary
1150
+ summary_parts = [
1151
+ f"{len(comparison_results['needs_update'])} need updates",
1152
+ f"{len(comparison_results['up_to_date'])} up to date",
1153
+ f"{len(comparison_results['new_agents'])} new agents",
1154
+ ]
1155
+ if comparison_results["orphaned_agents"]:
1156
+ summary_parts.append(
1157
+ f"{len(comparison_results['orphaned_agents'])} system orphaned"
1158
+ )
1159
+ if comparison_results["user_agents"]:
1160
+ summary_parts.append(
1161
+ f"{len(comparison_results['user_agents'])} user agents"
1162
+ )
1163
+
1164
+ self.logger.info(f"Version comparison complete: {', '.join(summary_parts)}")
1165
+
1166
+ # Don't log upgrades here - let the caller decide when to log
1167
+ # This prevents repeated upgrade messages on every startup
1168
+ if comparison_results["version_upgrades"]:
1169
+ for upgrade in comparison_results["version_upgrades"]:
1170
+ self.logger.debug(
1171
+ f" Upgrade available: {upgrade['name']} "
1172
+ f"{upgrade['deployed_version']} -> {upgrade['new_version']} "
1173
+ f"(from {upgrade['source']})"
1174
+ )
1175
+
1176
+ if comparison_results["source_changes"]:
1177
+ for change in comparison_results["source_changes"]:
1178
+ self.logger.debug(
1179
+ f" Source change available: {change['name']} "
1180
+ f"from {change['from_source']} to {change['to_source']}"
1181
+ )
1182
+
1183
+ if comparison_results["version_downgrades"]:
1184
+ for downgrade in comparison_results["version_downgrades"]:
1185
+ # Changed from warning to debug - deployed versions higher than templates
1186
+ # are not errors, just informational
1187
+ self.logger.debug(
1188
+ f" Note: {downgrade['name']} deployed version "
1189
+ f"{downgrade['deployed_version']} is higher than template "
1190
+ f"{downgrade['template_version']} (keeping deployed version)"
1191
+ )
1192
+
1193
+ # Log system orphaned agents if found
1194
+ if comparison_results["orphaned_agents"]:
1195
+ self.logger.info(
1196
+ f"Found {len(comparison_results['orphaned_agents'])} system orphaned agent(s) "
1197
+ f"(deployed without templates):"
1198
+ )
1199
+ for orphan in comparison_results["orphaned_agents"]:
1200
+ self.logger.info(
1201
+ f" - {orphan['name']} v{orphan['version']} "
1202
+ f"(consider removing or creating a template)"
1203
+ )
1204
+
1205
+ # Log user agents at debug level if found
1206
+ if comparison_results["user_agents"]:
1207
+ self.logger.debug(
1208
+ f"Found {len(comparison_results['user_agents'])} user-created agent(s) "
1209
+ f"(no templates required):"
1210
+ )
1211
+ for user_agent in comparison_results["user_agents"]:
1212
+ self.logger.debug(
1213
+ f" - {user_agent['name']} v{user_agent['version']} "
1214
+ f"(user-created agent)"
1215
+ )
1216
+
1217
+ return comparison_results
1218
+
1219
+ def _infer_agent_source_from_context(
1220
+ self, agent_name: str, deployed_agents_dir: Path
1221
+ ) -> str:
1222
+ """Infer the source of a deployed agent when source metadata is missing.
1223
+
1224
+ This method attempts to determine the agent source based on:
1225
+ 1. Deployment context (development vs pipx)
1226
+ 2. Agent naming patterns
1227
+ 3. Known system agents
1228
+
1229
+ Args:
1230
+ agent_name: Name of the agent
1231
+ deployed_agents_dir: Directory where agent is deployed
1232
+
1233
+ Returns:
1234
+ Inferred source string (system/project/user)
1235
+ """
1236
+ # List of known system agents that ship with claude-mpm
1237
+ system_agents = {
1238
+ "pm",
1239
+ "engineer",
1240
+ "qa",
1241
+ "research",
1242
+ "documentation",
1243
+ "ops",
1244
+ "security",
1245
+ "web-ui",
1246
+ "api-qa",
1247
+ "version-control",
1248
+ }
1249
+
1250
+ # If this is a known system agent, it's from system
1251
+ if agent_name in system_agents:
1252
+ return "system"
1253
+
1254
+ # Check deployment context
1255
+ from ....core.unified_paths import get_path_manager
1256
+
1257
+ path_manager = get_path_manager()
1258
+
1259
+ # If deployed_agents_dir is under user home/.claude/agents, check context
1260
+ user_claude_dir = Path.home() / ".claude" / "agents"
1261
+ if deployed_agents_dir == user_claude_dir:
1262
+ # Check if we're in development mode
1263
+ try:
1264
+ from ....core.unified_paths import DeploymentContext, PathContext
1265
+
1266
+ deployment_context = PathContext.detect_deployment_context()
1267
+
1268
+ if deployment_context in (
1269
+ DeploymentContext.DEVELOPMENT,
1270
+ DeploymentContext.EDITABLE_INSTALL,
1271
+ ):
1272
+ # In development mode, unknown agents are likely system agents being tested
1273
+ return "system"
1274
+ if (
1275
+ deployment_context == DeploymentContext.PIPX_INSTALL
1276
+ and agent_name.count("-") <= 2
1277
+ and len(agent_name) <= 20
1278
+ ):
1279
+ # In pipx mode, check if agent follows system naming patterns
1280
+ return "system"
1281
+ except Exception:
1282
+ pass
1283
+
1284
+ # Check if deployed to project-specific directory
1285
+ try:
1286
+ project_root = path_manager.project_root
1287
+ if str(deployed_agents_dir).startswith(str(project_root)):
1288
+ return "project"
1289
+ except Exception:
1290
+ pass
1291
+
1292
+ # Default inference based on naming patterns
1293
+ # System agents typically have simple names
1294
+ if "-" not in agent_name or agent_name.count("-") <= 1:
1295
+ return "system"
1296
+
1297
+ # Complex names are more likely to be user/project agents
1298
+ return "user"
1299
+
1300
+ def detect_orphaned_agents(
1301
+ self, deployed_agents_dir: Path, available_agents: Dict[str, Any]
1302
+ ) -> List[Dict[str, Any]]:
1303
+ """Detect deployed agents that don't have corresponding templates.
1304
+
1305
+ WHY: Orphaned agents can cause confusion with version warnings.
1306
+ This method identifies them so they can be handled appropriately.
1307
+
1308
+ Args:
1309
+ deployed_agents_dir: Directory containing deployed agents
1310
+ available_agents: Dictionary of available agents from all sources
1311
+
1312
+ Returns:
1313
+ List of orphaned agent information
1314
+ """
1315
+ orphaned = []
1316
+
1317
+ if not deployed_agents_dir.exists():
1318
+ return orphaned
1319
+
1320
+ # Build a mapping of file stems to agent names for comparison
1321
+ # Since available_agents uses display names like "Code Analysis Agent"
1322
+ # but deployed files use stems like "code_analyzer"
1323
+ available_stems = set()
1324
+ stem_to_name = {}
1325
+
1326
+ for agent_name, agent_sources in available_agents.items():
1327
+ # Get the file path from the first source to extract the stem
1328
+ if (
1329
+ agent_sources
1330
+ and isinstance(agent_sources, list)
1331
+ and len(agent_sources) > 0
1332
+ ):
1333
+ first_source = agent_sources[0]
1334
+ if "file_path" in first_source:
1335
+ file_path = Path(first_source["file_path"])
1336
+ stem = file_path.stem
1337
+ available_stems.add(stem)
1338
+ stem_to_name[stem] = agent_name
1339
+
1340
+ for deployed_file in deployed_agents_dir.glob("*.md"):
1341
+ agent_stem = deployed_file.stem
1342
+
1343
+ # Skip if this agent has a template (check by stem, not display name)
1344
+ if agent_stem in available_stems:
1345
+ continue
1346
+
1347
+ # This is an orphaned agent
1348
+ try:
1349
+ deployed_content = deployed_file.read_text()
1350
+ deployed_version, _, _ = (
1351
+ self.version_manager.extract_version_from_frontmatter(
1352
+ deployed_content
1353
+ )
1354
+ )
1355
+ version_str = self.version_manager.format_version_display(
1356
+ deployed_version
1357
+ )
1358
+ except Exception:
1359
+ version_str = "unknown"
1360
+
1361
+ orphaned.append(
1362
+ {"name": agent_stem, "file": str(deployed_file), "version": version_str}
1363
+ )
1364
+
1365
+ return orphaned
1366
+
1367
+ def _detect_orphaned_agents_simple(
1368
+ self, deployed_agents_dir: Path, agents_to_deploy: Dict[str, Path]
1369
+ ) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]:
1370
+ """Simple orphan detection that works with agents_to_deploy structure.
1371
+
1372
+ Args:
1373
+ deployed_agents_dir: Directory containing deployed agents
1374
+ agents_to_deploy: Dictionary mapping file stems to template paths
1375
+
1376
+ Returns:
1377
+ Tuple of (system_orphaned_agents, user_orphaned_agents)
1378
+ """
1379
+ system_orphaned = []
1380
+ user_orphaned = []
1381
+
1382
+ if not deployed_agents_dir.exists():
1383
+ return system_orphaned, user_orphaned
1384
+
1385
+ # agents_to_deploy already contains file stems as keys
1386
+ available_stems = set(agents_to_deploy.keys())
1387
+
1388
+ for deployed_file in deployed_agents_dir.glob("*.md"):
1389
+ agent_stem = deployed_file.stem
1390
+
1391
+ # Skip if this agent has a template (check by stem)
1392
+ if agent_stem in available_stems:
1393
+ continue
1394
+
1395
+ # This is an orphaned agent - determine if it's user-created or system
1396
+ try:
1397
+ deployed_content = deployed_file.read_text()
1398
+ deployed_version, _, _ = (
1399
+ self.version_manager.extract_version_from_frontmatter(
1400
+ deployed_content
1401
+ )
1402
+ )
1403
+ version_str = self.version_manager.format_version_display(
1404
+ deployed_version
1405
+ )
1406
+ except Exception:
1407
+ version_str = "unknown"
1408
+
1409
+ orphan_info = {
1410
+ "name": agent_stem,
1411
+ "file": str(deployed_file),
1412
+ "version": version_str,
1413
+ }
1414
+
1415
+ # Determine if this is a user-created agent
1416
+ if self._is_user_created_agent(deployed_file):
1417
+ user_orphaned.append(orphan_info)
1418
+ else:
1419
+ system_orphaned.append(orphan_info)
1420
+
1421
+ return system_orphaned, user_orphaned
1422
+
1423
+ def cleanup_orphaned_agents(
1424
+ self, deployed_agents_dir: Path, dry_run: bool = True
1425
+ ) -> Dict[str, Any]:
1426
+ """Clean up orphaned agents that don't have templates.
1427
+
1428
+ WHY: Orphaned agents can accumulate over time and cause confusion.
1429
+ This method provides a way to clean them up systematically.
1430
+
1431
+ Args:
1432
+ deployed_agents_dir: Directory containing deployed agents
1433
+ dry_run: If True, only report what would be removed
1434
+
1435
+ Returns:
1436
+ Dictionary with cleanup results
1437
+ """
1438
+ results = {"orphaned": [], "removed": [], "errors": []}
1439
+
1440
+ # First, discover all available agents from all sources
1441
+ all_agents = self.discover_agents_from_all_sources()
1442
+ set(all_agents.keys())
1443
+
1444
+ # Detect orphaned agents
1445
+ orphaned = self.detect_orphaned_agents(deployed_agents_dir, all_agents)
1446
+ results["orphaned"] = orphaned
1447
+
1448
+ if not orphaned:
1449
+ self.logger.info("No orphaned agents found")
1450
+ return results
1451
+
1452
+ self.logger.info(f"Found {len(orphaned)} orphaned agent(s)")
1453
+
1454
+ for orphan in orphaned:
1455
+ agent_file = Path(orphan["file"])
1456
+
1457
+ if dry_run:
1458
+ self.logger.info(
1459
+ f" Would remove: {orphan['name']} v{orphan['version']}"
1460
+ )
1461
+ else:
1462
+ try:
1463
+ agent_file.unlink()
1464
+ results["removed"].append(orphan["name"])
1465
+ self.logger.info(
1466
+ f" Removed: {orphan['name']} v{orphan['version']}"
1467
+ )
1468
+ except Exception as e:
1469
+ error_msg = f"Failed to remove {orphan['name']}: {e}"
1470
+ results["errors"].append(error_msg)
1471
+ self.logger.error(f" {error_msg}")
1472
+
1473
+ if dry_run and orphaned:
1474
+ self.logger.info(
1475
+ "Run with dry_run=False to actually remove orphaned agents"
1476
+ )
1477
+
1478
+ return results