claude-mpm 3.4.10__py3-none-any.whl → 5.4.55__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 (950) 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_OUTPUT_STYLE.md +290 -0
  8. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +2002 -0
  9. claude_mpm/agents/MEMORY.md +72 -0
  10. claude_mpm/agents/PM_INSTRUCTIONS.md +1402 -0
  11. claude_mpm/agents/WORKFLOW.md +111 -0
  12. claude_mpm/agents/__init__.py +92 -80
  13. claude_mpm/agents/agent-template.yaml +83 -0
  14. claude_mpm/agents/agent_loader.py +560 -745
  15. claude_mpm/agents/agent_loader_integration.py +53 -55
  16. claude_mpm/agents/agents_metadata.py +186 -27
  17. claude_mpm/agents/async_agent_loader.py +436 -0
  18. claude_mpm/agents/base_agent.json +8 -4
  19. claude_mpm/agents/frontmatter_validator.py +754 -0
  20. claude_mpm/agents/system_agent_config.py +222 -155
  21. claude_mpm/agents/templates/README.md +465 -0
  22. claude_mpm/agents/templates/__init__.py +17 -13
  23. claude_mpm/agents/templates/circuit-breakers.md +1391 -0
  24. claude_mpm/agents/templates/context-management-examples.md +544 -0
  25. claude_mpm/agents/templates/git-file-tracking.md +584 -0
  26. claude_mpm/agents/templates/pm-examples.md +474 -0
  27. claude_mpm/agents/templates/pm-red-flags.md +310 -0
  28. claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
  29. claude_mpm/agents/templates/research-gate-examples.md +669 -0
  30. claude_mpm/agents/templates/response-format.md +583 -0
  31. claude_mpm/agents/templates/structured-questions-examples.md +615 -0
  32. claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
  33. claude_mpm/agents/templates/ticketing-examples.md +277 -0
  34. claude_mpm/agents/templates/validation-templates.md +312 -0
  35. claude_mpm/cli/__init__.py +90 -128
  36. claude_mpm/cli/__main__.py +33 -0
  37. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  38. claude_mpm/cli/commands/__init__.py +36 -12
  39. claude_mpm/cli/commands/agent_manager.py +1403 -0
  40. claude_mpm/cli/commands/agent_source.py +774 -0
  41. claude_mpm/cli/commands/agent_state_manager.py +335 -0
  42. claude_mpm/cli/commands/agents.py +2503 -168
  43. claude_mpm/cli/commands/agents_cleanup.py +210 -0
  44. claude_mpm/cli/commands/agents_discover.py +338 -0
  45. claude_mpm/cli/commands/aggregate.py +540 -0
  46. claude_mpm/cli/commands/analyze.py +553 -0
  47. claude_mpm/cli/commands/analyze_code.py +528 -0
  48. claude_mpm/cli/commands/auto_configure.py +1053 -0
  49. claude_mpm/cli/commands/cleanup.py +588 -0
  50. claude_mpm/cli/commands/cleanup_orphaned_agents.py +150 -0
  51. claude_mpm/cli/commands/config.py +586 -0
  52. claude_mpm/cli/commands/configure.py +2654 -0
  53. claude_mpm/cli/commands/configure_agent_display.py +282 -0
  54. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  55. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  56. claude_mpm/cli/commands/configure_models.py +18 -0
  57. claude_mpm/cli/commands/configure_navigation.py +184 -0
  58. claude_mpm/cli/commands/configure_paths.py +104 -0
  59. claude_mpm/cli/commands/configure_persistence.py +254 -0
  60. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  61. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  62. claude_mpm/cli/commands/configure_validators.py +73 -0
  63. claude_mpm/cli/commands/dashboard.py +286 -0
  64. claude_mpm/cli/commands/debug.py +1386 -0
  65. claude_mpm/cli/commands/doctor.py +243 -0
  66. claude_mpm/cli/commands/hook_errors.py +277 -0
  67. claude_mpm/cli/commands/info.py +195 -74
  68. claude_mpm/cli/commands/local_deploy.py +534 -0
  69. claude_mpm/cli/commands/mcp.py +205 -0
  70. claude_mpm/cli/commands/mcp_command_router.py +161 -0
  71. claude_mpm/cli/commands/mcp_config.py +154 -0
  72. claude_mpm/cli/commands/mcp_config_commands.py +20 -0
  73. claude_mpm/cli/commands/mcp_external_commands.py +249 -0
  74. claude_mpm/cli/commands/mcp_install_commands.py +346 -0
  75. claude_mpm/cli/commands/mcp_pipx_config.py +208 -0
  76. claude_mpm/cli/commands/mcp_server_commands.py +155 -0
  77. claude_mpm/cli/commands/mcp_setup_external.py +868 -0
  78. claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
  79. claude_mpm/cli/commands/memory.py +585 -846
  80. claude_mpm/cli/commands/monitor.py +228 -310
  81. claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
  82. claude_mpm/cli/commands/mpm_init/core.py +759 -0
  83. claude_mpm/cli/commands/mpm_init/display.py +341 -0
  84. claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
  85. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  86. claude_mpm/cli/commands/mpm_init/modes.py +397 -0
  87. claude_mpm/cli/commands/mpm_init/prompts.py +722 -0
  88. claude_mpm/cli/commands/mpm_init_cli.py +396 -0
  89. claude_mpm/cli/commands/mpm_init_handler.py +195 -0
  90. claude_mpm/cli/commands/postmortem.py +401 -0
  91. claude_mpm/cli/commands/profile.py +276 -0
  92. claude_mpm/cli/commands/run.py +910 -488
  93. claude_mpm/cli/commands/search.py +458 -0
  94. claude_mpm/cli/commands/skill_source.py +694 -0
  95. claude_mpm/cli/commands/skills.py +1246 -0
  96. claude_mpm/cli/commands/summarize.py +413 -0
  97. claude_mpm/cli/commands/tickets.py +536 -53
  98. claude_mpm/cli/commands/uninstall.py +176 -0
  99. claude_mpm/cli/commands/upgrade.py +152 -0
  100. claude_mpm/cli/commands/verify.py +119 -0
  101. claude_mpm/cli/executor.py +297 -0
  102. claude_mpm/cli/helpers.py +105 -0
  103. claude_mpm/cli/interactive/__init__.py +21 -0
  104. claude_mpm/cli/interactive/agent_wizard.py +1947 -0
  105. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  106. claude_mpm/cli/parser.py +87 -563
  107. claude_mpm/cli/parsers/__init__.py +35 -0
  108. claude_mpm/cli/parsers/agent_manager_parser.py +393 -0
  109. claude_mpm/cli/parsers/agent_source_parser.py +171 -0
  110. claude_mpm/cli/parsers/agents_parser.py +575 -0
  111. claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
  112. claude_mpm/cli/parsers/analyze_parser.py +135 -0
  113. claude_mpm/cli/parsers/auto_configure_parser.py +120 -0
  114. claude_mpm/cli/parsers/base_parser.py +644 -0
  115. claude_mpm/cli/parsers/config_parser.py +208 -0
  116. claude_mpm/cli/parsers/configure_parser.py +138 -0
  117. claude_mpm/cli/parsers/dashboard_parser.py +113 -0
  118. claude_mpm/cli/parsers/debug_parser.py +319 -0
  119. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  120. claude_mpm/cli/parsers/mcp_parser.py +195 -0
  121. claude_mpm/cli/parsers/memory_parser.py +138 -0
  122. claude_mpm/cli/parsers/monitor_parser.py +142 -0
  123. claude_mpm/cli/parsers/mpm_init_parser.py +311 -0
  124. claude_mpm/cli/parsers/profile_parser.py +147 -0
  125. claude_mpm/cli/parsers/run_parser.py +157 -0
  126. claude_mpm/cli/parsers/search_parser.py +245 -0
  127. claude_mpm/cli/parsers/skill_source_parser.py +169 -0
  128. claude_mpm/cli/parsers/skills_parser.py +277 -0
  129. claude_mpm/cli/parsers/source_parser.py +138 -0
  130. claude_mpm/cli/parsers/tickets_parser.py +203 -0
  131. claude_mpm/cli/shared/__init__.py +40 -0
  132. claude_mpm/cli/shared/argument_patterns.py +205 -0
  133. claude_mpm/cli/shared/base_command.py +242 -0
  134. claude_mpm/cli/shared/error_handling.py +242 -0
  135. claude_mpm/cli/shared/output_formatters.py +241 -0
  136. claude_mpm/cli/startup.py +1743 -0
  137. claude_mpm/cli/startup_display.py +480 -0
  138. claude_mpm/cli/startup_logging.py +839 -0
  139. claude_mpm/cli/utils.py +136 -47
  140. claude_mpm/cli_module/__init__.py +6 -6
  141. claude_mpm/cli_module/args.py +188 -140
  142. claude_mpm/cli_module/commands.py +79 -70
  143. claude_mpm/cli_module/migration_example.py +42 -64
  144. claude_mpm/commands/__init__.py +14 -0
  145. claude_mpm/commands/mpm-config.md +28 -0
  146. claude_mpm/commands/mpm-doctor.md +20 -0
  147. claude_mpm/commands/mpm-help.md +20 -0
  148. claude_mpm/commands/mpm-init.md +120 -0
  149. claude_mpm/commands/mpm-monitor.md +31 -0
  150. claude_mpm/commands/mpm-organize.md +120 -0
  151. claude_mpm/commands/mpm-postmortem.md +21 -0
  152. claude_mpm/commands/mpm-session-resume.md +30 -0
  153. claude_mpm/commands/mpm-status.md +20 -0
  154. claude_mpm/commands/mpm-ticket-view.md +109 -0
  155. claude_mpm/commands/mpm-version.md +20 -0
  156. claude_mpm/commands/mpm.md +31 -0
  157. claude_mpm/config/__init__.py +42 -2
  158. claude_mpm/config/agent_config.py +402 -0
  159. claude_mpm/config/agent_presets.py +488 -0
  160. claude_mpm/config/agent_sources.py +352 -0
  161. claude_mpm/config/experimental_features.py +217 -0
  162. claude_mpm/config/model_config.py +428 -0
  163. claude_mpm/config/paths.py +258 -0
  164. claude_mpm/config/skill_presets.py +392 -0
  165. claude_mpm/config/skill_sources.py +590 -0
  166. claude_mpm/config/socketio_config.py +125 -83
  167. claude_mpm/constants.py +132 -22
  168. claude_mpm/core/__init__.py +62 -36
  169. claude_mpm/core/agent_name_normalizer.py +71 -73
  170. claude_mpm/core/agent_registry.py +385 -492
  171. claude_mpm/core/agent_session_manager.py +81 -70
  172. claude_mpm/core/api_validator.py +330 -0
  173. claude_mpm/core/base_service.py +159 -122
  174. claude_mpm/core/cache.py +560 -0
  175. claude_mpm/core/claude_runner.py +696 -916
  176. claude_mpm/core/config.py +613 -122
  177. claude_mpm/core/config_aliases.py +74 -73
  178. claude_mpm/core/config_constants.py +314 -0
  179. claude_mpm/core/constants.py +361 -0
  180. claude_mpm/core/container.py +646 -104
  181. claude_mpm/core/enums.py +452 -0
  182. claude_mpm/core/error_handler.py +623 -0
  183. claude_mpm/core/exceptions.py +536 -0
  184. claude_mpm/core/factories.py +105 -109
  185. claude_mpm/core/file_utils.py +764 -0
  186. claude_mpm/core/framework/__init__.py +25 -0
  187. claude_mpm/core/framework/formatters/__init__.py +11 -0
  188. claude_mpm/core/framework/formatters/capability_generator.py +367 -0
  189. claude_mpm/core/framework/formatters/content_formatter.py +278 -0
  190. claude_mpm/core/framework/formatters/context_generator.py +185 -0
  191. claude_mpm/core/framework/loaders/__init__.py +13 -0
  192. claude_mpm/core/framework/loaders/agent_loader.py +213 -0
  193. claude_mpm/core/framework/loaders/file_loader.py +176 -0
  194. claude_mpm/core/framework/loaders/instruction_loader.py +222 -0
  195. claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
  196. claude_mpm/core/framework/processors/__init__.py +11 -0
  197. claude_mpm/core/framework/processors/memory_processor.py +230 -0
  198. claude_mpm/core/framework/processors/metadata_processor.py +146 -0
  199. claude_mpm/core/framework/processors/template_processor.py +244 -0
  200. claude_mpm/core/framework_loader.py +485 -414
  201. claude_mpm/core/hook_error_memory.py +381 -0
  202. claude_mpm/core/hook_manager.py +246 -86
  203. claude_mpm/core/hook_performance_config.py +147 -0
  204. claude_mpm/core/injectable_service.py +72 -63
  205. claude_mpm/core/instruction_reinforcement_hook.py +267 -0
  206. claude_mpm/core/interactive_session.py +670 -0
  207. claude_mpm/core/interfaces.py +570 -164
  208. claude_mpm/core/lazy.py +467 -0
  209. claude_mpm/core/log_manager.py +707 -0
  210. claude_mpm/core/logger.py +295 -134
  211. claude_mpm/core/logging_config.py +474 -0
  212. claude_mpm/core/logging_utils.py +520 -0
  213. claude_mpm/core/minimal_framework_loader.py +24 -22
  214. claude_mpm/core/mixins.py +30 -29
  215. claude_mpm/core/oneshot_session.py +594 -0
  216. claude_mpm/core/optimized_agent_loader.py +479 -0
  217. claude_mpm/core/optimized_startup.py +554 -0
  218. claude_mpm/core/output_style_manager.py +483 -0
  219. claude_mpm/core/pm_hook_interceptor.py +197 -82
  220. claude_mpm/core/protocols/__init__.py +23 -0
  221. claude_mpm/core/protocols/runner_protocol.py +103 -0
  222. claude_mpm/core/protocols/session_protocol.py +131 -0
  223. claude_mpm/core/service_registry.py +153 -116
  224. claude_mpm/core/session_manager.py +179 -64
  225. claude_mpm/core/shared/__init__.py +17 -0
  226. claude_mpm/core/shared/config_loader.py +326 -0
  227. claude_mpm/core/shared/path_resolver.py +281 -0
  228. claude_mpm/core/shared/singleton_manager.py +221 -0
  229. claude_mpm/core/socketio_pool.py +400 -137
  230. claude_mpm/core/system_context.py +38 -0
  231. claude_mpm/core/tool_access_control.py +64 -57
  232. claude_mpm/core/types.py +307 -0
  233. claude_mpm/core/typing_utils.py +553 -0
  234. claude_mpm/core/unified_agent_registry.py +969 -0
  235. claude_mpm/core/unified_config.py +570 -0
  236. claude_mpm/core/unified_paths.py +941 -0
  237. claude_mpm/dashboard/__init__.py +12 -0
  238. claude_mpm/dashboard/api/simple_directory.py +261 -0
  239. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  240. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +1 -0
  241. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +1 -0
  242. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +1 -0
  243. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +24 -0
  244. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B0uc0UOD.js +36 -0
  245. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7RN905-.js +1 -0
  246. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7xVLGWV.js +2 -0
  247. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BIF9m_hv.js +61 -0
  248. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +1 -0
  249. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BPYeabCQ.js +1 -0
  250. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  251. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
  252. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Be7GpZd6.js +7 -0
  253. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bh0LDWpI.js +145 -0
  254. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BofRWZRR.js +10 -0
  255. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BovzEFCE.js +30 -0
  256. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C30mlcqg.js +165 -0
  257. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4B-KCzX.js +1 -0
  258. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4JcI4KD.js +122 -0
  259. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CBBdVcY8.js +1 -0
  260. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CDuw-vjf.js +1 -0
  261. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C_Usid8X.js +15 -0
  262. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cfqx1Qun.js +10 -0
  263. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CiIAseT4.js +128 -0
  264. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  265. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CnA0NrzZ.js +1 -0
  266. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cs_tUR18.js +24 -0
  267. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  268. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CyWMqx4W.js +43 -0
  269. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzZX-COe.js +220 -0
  270. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzeYkLYB.js +65 -0
  271. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D3k0OPJN.js +4 -0
  272. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9lljYKQ.js +1 -0
  273. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DGkLK5U1.js +267 -0
  274. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DI7hHRFL.js +1 -0
  275. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DLVjFsZ3.js +139 -0
  276. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUrLdbGD.js +89 -0
  277. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  278. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DY1XQ8fi.js +2 -0
  279. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DZX00Y4g.js +1 -0
  280. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +1 -0
  281. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DaimHw_p.js +68 -0
  282. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +323 -0
  283. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dhb8PKl3.js +1 -0
  284. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dle-35c7.js +64 -0
  285. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DmxopI1J.js +1 -0
  286. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DwBR2MJi.js +60 -0
  287. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/GYwsonyD.js +1 -0
  288. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  289. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
  290. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/RJiighC3.js +1 -0
  291. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Vzk33B_K.js +2 -0
  292. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ZGh7QtNv.js +7 -0
  293. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bT1r9zLR.js +1 -0
  294. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bTOqqlTd.js +1 -0
  295. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/eNVUfhuA.js +1 -0
  296. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/iEWssX7S.js +162 -0
  297. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/sQeU3Y1z.js +1 -0
  298. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uuIeMWc-.js +1 -0
  299. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.D6-I5TpK.js +2 -0
  300. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +1 -0
  301. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.m1gL8KXf.js +1 -0
  302. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.CgNOuw-d.js +1 -0
  303. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +1 -0
  304. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  305. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  306. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  307. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  308. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  309. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  310. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  311. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  312. claude_mpm/experimental/__init__.py +10 -0
  313. claude_mpm/experimental/cli_enhancements.py +104 -89
  314. claude_mpm/generators/__init__.py +1 -1
  315. claude_mpm/generators/agent_profile_generator.py +76 -66
  316. claude_mpm/hooks/__init__.py +37 -1
  317. claude_mpm/hooks/base_hook.py +37 -32
  318. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  319. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  320. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  321. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  322. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  323. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  324. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  325. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  326. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  327. claude_mpm/hooks/claude_hooks/connection_pool.py +250 -0
  328. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  329. claude_mpm/hooks/claude_hooks/event_handlers.py +888 -0
  330. claude_mpm/hooks/claude_hooks/hook_handler.py +652 -875
  331. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +10 -7
  332. claude_mpm/hooks/claude_hooks/installer.py +806 -0
  333. claude_mpm/hooks/claude_hooks/memory_integration.py +249 -0
  334. claude_mpm/hooks/claude_hooks/response_tracking.py +412 -0
  335. claude_mpm/hooks/claude_hooks/services/__init__.py +15 -0
  336. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  337. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  338. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  339. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  340. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  341. claude_mpm/hooks/claude_hooks/services/connection_manager.py +229 -0
  342. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +254 -0
  343. claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
  344. claude_mpm/hooks/claude_hooks/services/state_manager.py +284 -0
  345. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
  346. claude_mpm/hooks/claude_hooks/tool_analysis.py +224 -0
  347. claude_mpm/hooks/failure_learning/__init__.py +54 -0
  348. claude_mpm/hooks/failure_learning/failure_detection_hook.py +230 -0
  349. claude_mpm/hooks/failure_learning/fix_detection_hook.py +212 -0
  350. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +281 -0
  351. claude_mpm/hooks/instruction_reinforcement.py +301 -0
  352. claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
  353. claude_mpm/hooks/kuzu_memory_hook.py +386 -0
  354. claude_mpm/hooks/kuzu_response_hook.py +179 -0
  355. claude_mpm/hooks/memory_integration_hook.py +201 -107
  356. claude_mpm/hooks/session_resume_hook.py +121 -0
  357. claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
  358. claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
  359. claude_mpm/hooks/tool_call_interceptor.py +92 -76
  360. claude_mpm/hooks/validation_hooks.py +62 -54
  361. claude_mpm/init.py +518 -83
  362. claude_mpm/models/__init__.py +9 -9
  363. claude_mpm/models/agent_definition.py +40 -23
  364. claude_mpm/models/agent_session.py +538 -0
  365. claude_mpm/models/git_repository.py +198 -0
  366. claude_mpm/models/resume_log.py +340 -0
  367. claude_mpm/schemas/__init__.py +12 -0
  368. claude_mpm/scripts/__init__.py +15 -0
  369. claude_mpm/scripts/claude-hook-handler.sh +227 -0
  370. claude_mpm/scripts/launch_monitor.py +165 -0
  371. claude_mpm/scripts/mpm_doctor.py +322 -0
  372. claude_mpm/scripts/socketio_daemon.py +189 -200
  373. claude_mpm/scripts/start_activity_logging.py +91 -0
  374. claude_mpm/services/__init__.py +208 -39
  375. claude_mpm/services/agent_capabilities_service.py +266 -0
  376. claude_mpm/services/agents/__init__.py +89 -0
  377. claude_mpm/services/agents/agent_builder.py +514 -0
  378. claude_mpm/services/agents/agent_preset_service.py +238 -0
  379. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  380. claude_mpm/services/agents/agent_review_service.py +280 -0
  381. claude_mpm/services/agents/agent_selection_service.py +484 -0
  382. claude_mpm/services/agents/auto_config_manager.py +796 -0
  383. claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
  384. claude_mpm/services/agents/cache_git_manager.py +621 -0
  385. claude_mpm/services/agents/deployment/__init__.py +21 -0
  386. claude_mpm/services/agents/deployment/agent_config_provider.py +410 -0
  387. claude_mpm/services/agents/deployment/agent_configuration_manager.py +358 -0
  388. claude_mpm/services/agents/deployment/agent_definition_factory.py +80 -0
  389. claude_mpm/services/agents/deployment/agent_deployment.py +1037 -0
  390. claude_mpm/services/agents/deployment/agent_discovery_service.py +546 -0
  391. claude_mpm/services/agents/deployment/agent_environment_manager.py +288 -0
  392. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +383 -0
  393. claude_mpm/services/agents/deployment/agent_format_converter.py +505 -0
  394. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +160 -0
  395. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +957 -0
  396. claude_mpm/services/agents/deployment/agent_metrics_collector.py +273 -0
  397. claude_mpm/services/agents/deployment/agent_operation_service.py +573 -0
  398. claude_mpm/services/agents/deployment/agent_record_service.py +418 -0
  399. claude_mpm/services/agents/deployment/agent_restore_handler.py +84 -0
  400. claude_mpm/services/agents/deployment/agent_state_service.py +381 -0
  401. claude_mpm/services/agents/deployment/agent_template_builder.py +1369 -0
  402. claude_mpm/services/agents/deployment/agent_validator.py +376 -0
  403. claude_mpm/services/agents/deployment/agent_version_manager.py +322 -0
  404. claude_mpm/services/{agent_versioning.py → agents/deployment/agent_versioning.py} +10 -13
  405. claude_mpm/services/agents/deployment/agents_directory_resolver.py +149 -0
  406. claude_mpm/services/agents/deployment/async_agent_deployment.py +768 -0
  407. claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
  408. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  409. claude_mpm/services/agents/deployment/config/deployment_config.py +181 -0
  410. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  411. claude_mpm/services/agents/deployment/deployment_config_loader.py +178 -0
  412. claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
  413. claude_mpm/services/agents/deployment/deployment_type_detector.py +120 -0
  414. claude_mpm/services/agents/deployment/deployment_wrapper.py +129 -0
  415. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  416. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  417. claude_mpm/services/agents/deployment/facade/deployment_executor.py +70 -0
  418. claude_mpm/services/agents/deployment/facade/deployment_facade.py +269 -0
  419. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  420. claude_mpm/services/agents/deployment/interface_adapter.py +226 -0
  421. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  422. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  423. claude_mpm/services/agents/deployment/local_template_deployment.py +362 -0
  424. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +1478 -0
  425. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  426. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  427. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +162 -0
  428. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  429. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  430. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +240 -0
  431. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +110 -0
  432. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +80 -0
  433. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +92 -0
  434. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +101 -0
  435. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  436. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +102 -0
  437. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  438. claude_mpm/services/agents/deployment/processors/agent_processor.py +269 -0
  439. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +311 -0
  440. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +862 -0
  441. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  442. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  443. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  444. claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
  445. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  446. claude_mpm/services/agents/deployment/strategies/base_strategy.py +113 -0
  447. claude_mpm/services/agents/deployment/strategies/project_strategy.py +148 -0
  448. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  449. claude_mpm/services/agents/deployment/strategies/system_strategy.py +131 -0
  450. claude_mpm/services/agents/deployment/strategies/user_strategy.py +130 -0
  451. claude_mpm/services/agents/deployment/system_instructions_deployer.py +228 -0
  452. claude_mpm/services/agents/deployment/validation/__init__.py +21 -0
  453. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  454. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  455. claude_mpm/services/agents/deployment/validation/template_validator.py +319 -0
  456. claude_mpm/services/agents/deployment/validation/validation_result.py +214 -0
  457. claude_mpm/services/agents/git_source_manager.py +682 -0
  458. claude_mpm/services/agents/loading/__init__.py +11 -0
  459. claude_mpm/services/{agent_profile_loader.py → agents/loading/agent_profile_loader.py} +306 -228
  460. claude_mpm/services/{base_agent_manager.py → agents/loading/base_agent_manager.py} +106 -91
  461. claude_mpm/services/agents/loading/framework_agent_loader.py +433 -0
  462. claude_mpm/services/agents/local_template_manager.py +784 -0
  463. claude_mpm/services/agents/management/__init__.py +9 -0
  464. claude_mpm/services/{agent_capabilities_generator.py → agents/management/agent_capabilities_generator.py} +92 -69
  465. claude_mpm/services/{agent_management_service.py → agents/management/agent_management_service.py} +219 -168
  466. claude_mpm/services/agents/memory/__init__.py +22 -0
  467. claude_mpm/services/agents/memory/agent_memory_manager.py +784 -0
  468. claude_mpm/services/{agent_persistence_service.py → agents/memory/agent_persistence_service.py} +20 -18
  469. claude_mpm/services/agents/memory/content_manager.py +470 -0
  470. claude_mpm/services/agents/memory/memory_categorization_service.py +167 -0
  471. claude_mpm/services/agents/memory/memory_file_service.py +129 -0
  472. claude_mpm/services/agents/memory/memory_format_service.py +201 -0
  473. claude_mpm/services/agents/memory/memory_limits_service.py +101 -0
  474. claude_mpm/services/agents/memory/template_generator.py +83 -0
  475. claude_mpm/services/agents/observers.py +547 -0
  476. claude_mpm/services/agents/recommender.py +617 -0
  477. claude_mpm/services/agents/registry/__init__.py +30 -0
  478. claude_mpm/services/agents/registry/deployed_agent_discovery.py +273 -0
  479. claude_mpm/services/{agent_modification_tracker.py → agents/registry/modification_tracker.py} +370 -295
  480. claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
  481. claude_mpm/services/agents/sources/__init__.py +13 -0
  482. claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
  483. claude_mpm/services/agents/sources/git_source_sync_service.py +1202 -0
  484. claude_mpm/services/agents/startup_sync.py +259 -0
  485. claude_mpm/services/agents/toolchain_detector.py +478 -0
  486. claude_mpm/services/analysis/__init__.py +35 -0
  487. claude_mpm/services/analysis/clone_detector.py +1030 -0
  488. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  489. claude_mpm/services/analysis/postmortem_service.py +765 -0
  490. claude_mpm/services/async_session_logger.py +665 -0
  491. claude_mpm/services/claude_session_logger.py +321 -0
  492. claude_mpm/services/cli/__init__.py +18 -0
  493. claude_mpm/services/cli/agent_cleanup_service.py +408 -0
  494. claude_mpm/services/cli/agent_dependency_service.py +395 -0
  495. claude_mpm/services/cli/agent_listing_service.py +463 -0
  496. claude_mpm/services/cli/agent_output_formatter.py +605 -0
  497. claude_mpm/services/cli/agent_validation_service.py +590 -0
  498. claude_mpm/services/cli/memory_crud_service.py +622 -0
  499. claude_mpm/services/cli/memory_output_formatter.py +604 -0
  500. claude_mpm/services/cli/resume_service.py +617 -0
  501. claude_mpm/services/cli/session_manager.py +604 -0
  502. claude_mpm/services/cli/session_pause_manager.py +504 -0
  503. claude_mpm/services/cli/session_resume_helper.py +372 -0
  504. claude_mpm/services/cli/startup_checker.py +362 -0
  505. claude_mpm/services/cli/unified_dashboard_manager.py +439 -0
  506. claude_mpm/services/command_deployment_service.py +446 -0
  507. claude_mpm/services/command_handler_service.py +221 -0
  508. claude_mpm/services/communication/__init__.py +22 -0
  509. claude_mpm/services/core/__init__.py +108 -0
  510. claude_mpm/services/core/base.py +269 -0
  511. claude_mpm/services/core/cache_manager.py +309 -0
  512. claude_mpm/services/core/interfaces/__init__.py +273 -0
  513. claude_mpm/services/core/interfaces/agent.py +514 -0
  514. claude_mpm/services/core/interfaces/communication.py +316 -0
  515. claude_mpm/services/core/interfaces/health.py +169 -0
  516. claude_mpm/services/core/interfaces/infrastructure.py +357 -0
  517. claude_mpm/services/core/interfaces/model.py +281 -0
  518. claude_mpm/services/core/interfaces/process.py +372 -0
  519. claude_mpm/services/core/interfaces/project.py +121 -0
  520. claude_mpm/services/core/interfaces/restart.py +307 -0
  521. claude_mpm/services/core/interfaces/service.py +405 -0
  522. claude_mpm/services/core/interfaces/stability.py +260 -0
  523. claude_mpm/services/core/interfaces.py +81 -0
  524. claude_mpm/services/core/memory_manager.py +682 -0
  525. claude_mpm/services/core/models/__init__.py +70 -0
  526. claude_mpm/services/core/models/agent_config.py +384 -0
  527. claude_mpm/services/core/models/health.py +162 -0
  528. claude_mpm/services/core/models/process.py +239 -0
  529. claude_mpm/services/core/models/restart.py +302 -0
  530. claude_mpm/services/core/models/stability.py +264 -0
  531. claude_mpm/services/core/models/toolchain.py +306 -0
  532. claude_mpm/services/core/path_resolver.py +517 -0
  533. claude_mpm/services/core/service_container.py +520 -0
  534. claude_mpm/services/core/service_interfaces.py +436 -0
  535. claude_mpm/services/diagnostics/__init__.py +18 -0
  536. claude_mpm/services/diagnostics/checks/__init__.py +38 -0
  537. claude_mpm/services/diagnostics/checks/agent_check.py +370 -0
  538. claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
  539. claude_mpm/services/diagnostics/checks/base_check.py +60 -0
  540. claude_mpm/services/diagnostics/checks/claude_code_check.py +270 -0
  541. claude_mpm/services/diagnostics/checks/common_issues_check.py +363 -0
  542. claude_mpm/services/diagnostics/checks/configuration_check.py +306 -0
  543. claude_mpm/services/diagnostics/checks/filesystem_check.py +233 -0
  544. claude_mpm/services/diagnostics/checks/installation_check.py +520 -0
  545. claude_mpm/services/diagnostics/checks/instructions_check.py +415 -0
  546. claude_mpm/services/diagnostics/checks/mcp_check.py +330 -0
  547. claude_mpm/services/diagnostics/checks/mcp_services_check.py +1058 -0
  548. claude_mpm/services/diagnostics/checks/monitor_check.py +281 -0
  549. claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
  550. claude_mpm/services/diagnostics/checks/startup_log_check.py +319 -0
  551. claude_mpm/services/diagnostics/diagnostic_runner.py +286 -0
  552. claude_mpm/services/diagnostics/doctor_reporter.py +578 -0
  553. claude_mpm/services/diagnostics/models.py +138 -0
  554. claude_mpm/services/event_aggregator.py +582 -0
  555. claude_mpm/services/event_bus/__init__.py +18 -0
  556. claude_mpm/services/event_bus/config.py +186 -0
  557. claude_mpm/services/event_bus/direct_relay.py +312 -0
  558. claude_mpm/services/event_bus/event_bus.py +396 -0
  559. claude_mpm/services/event_bus/relay.py +326 -0
  560. claude_mpm/services/events/__init__.py +44 -0
  561. claude_mpm/services/events/consumers/__init__.py +18 -0
  562. claude_mpm/services/events/consumers/dead_letter.py +306 -0
  563. claude_mpm/services/events/consumers/logging.py +184 -0
  564. claude_mpm/services/events/consumers/metrics.py +241 -0
  565. claude_mpm/services/events/consumers/socketio.py +377 -0
  566. claude_mpm/services/events/core.py +480 -0
  567. claude_mpm/services/events/interfaces.py +214 -0
  568. claude_mpm/services/events/producers/__init__.py +14 -0
  569. claude_mpm/services/events/producers/hook.py +269 -0
  570. claude_mpm/services/events/producers/system.py +329 -0
  571. claude_mpm/services/exceptions.py +433 -353
  572. claude_mpm/services/framework_claude_md_generator/__init__.py +81 -80
  573. claude_mpm/services/framework_claude_md_generator/content_assembler.py +74 -67
  574. claude_mpm/services/framework_claude_md_generator/content_validator.py +66 -62
  575. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +82 -60
  576. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +36 -37
  577. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +41 -40
  578. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +15 -15
  579. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +5 -4
  580. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  581. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  582. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  583. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  584. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +5 -4
  585. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  586. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  587. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +26 -30
  588. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +6 -5
  589. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  590. claude_mpm/services/framework_claude_md_generator/version_manager.py +31 -30
  591. claude_mpm/services/git/__init__.py +21 -0
  592. claude_mpm/services/git/git_operations_service.py +579 -0
  593. claude_mpm/services/github/__init__.py +21 -0
  594. claude_mpm/services/github/github_cli_service.py +397 -0
  595. claude_mpm/services/hook_installer_service.py +506 -0
  596. claude_mpm/services/hook_service.py +159 -111
  597. claude_mpm/services/infrastructure/__init__.py +52 -0
  598. claude_mpm/services/infrastructure/context_preservation.py +569 -0
  599. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  600. claude_mpm/services/infrastructure/logging.py +209 -0
  601. claude_mpm/services/infrastructure/monitoring/__init__.py +39 -0
  602. claude_mpm/services/infrastructure/monitoring/aggregator.py +432 -0
  603. claude_mpm/services/infrastructure/monitoring/base.py +122 -0
  604. claude_mpm/services/infrastructure/monitoring/legacy.py +203 -0
  605. claude_mpm/services/infrastructure/monitoring/network.py +219 -0
  606. claude_mpm/services/infrastructure/monitoring/process.py +343 -0
  607. claude_mpm/services/infrastructure/monitoring/resources.py +244 -0
  608. claude_mpm/services/infrastructure/monitoring/service.py +368 -0
  609. claude_mpm/services/infrastructure/monitoring.py +71 -0
  610. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  611. claude_mpm/services/instructions/__init__.py +9 -0
  612. claude_mpm/services/instructions/instruction_cache_service.py +374 -0
  613. claude_mpm/services/local_ops/__init__.py +155 -0
  614. claude_mpm/services/local_ops/crash_detector.py +257 -0
  615. claude_mpm/services/local_ops/health_checks/__init__.py +26 -0
  616. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  617. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  618. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  619. claude_mpm/services/local_ops/health_manager.py +427 -0
  620. claude_mpm/services/local_ops/log_monitor.py +396 -0
  621. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  622. claude_mpm/services/local_ops/process_manager.py +595 -0
  623. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  624. claude_mpm/services/local_ops/restart_manager.py +401 -0
  625. claude_mpm/services/local_ops/restart_policy.py +387 -0
  626. claude_mpm/services/local_ops/state_manager.py +372 -0
  627. claude_mpm/services/local_ops/unified_manager.py +600 -0
  628. claude_mpm/services/mcp_config_manager.py +1542 -0
  629. claude_mpm/services/mcp_service_verifier.py +732 -0
  630. claude_mpm/services/memory/__init__.py +19 -0
  631. claude_mpm/services/{memory_builder.py → memory/builder.py} +465 -373
  632. claude_mpm/services/memory/cache/__init__.py +14 -0
  633. claude_mpm/services/{shared_prompt_cache.py → memory/cache/shared_prompt_cache.py} +237 -200
  634. claude_mpm/services/memory/cache/simple_cache.py +331 -0
  635. claude_mpm/services/memory/failure_tracker.py +578 -0
  636. claude_mpm/services/memory/indexed_memory.py +648 -0
  637. claude_mpm/services/{memory_optimizer.py → memory/optimizer.py} +272 -243
  638. claude_mpm/services/memory/router.py +951 -0
  639. claude_mpm/services/memory_hook_service.py +470 -0
  640. claude_mpm/services/model/__init__.py +147 -0
  641. claude_mpm/services/model/base_provider.py +365 -0
  642. claude_mpm/services/model/claude_provider.py +412 -0
  643. claude_mpm/services/model/model_router.py +452 -0
  644. claude_mpm/services/model/ollama_provider.py +415 -0
  645. claude_mpm/services/monitor/__init__.py +20 -0
  646. claude_mpm/services/monitor/daemon.py +698 -0
  647. claude_mpm/services/monitor/daemon_manager.py +1076 -0
  648. claude_mpm/services/monitor/event_emitter.py +350 -0
  649. claude_mpm/services/monitor/handlers/__init__.py +21 -0
  650. claude_mpm/services/monitor/handlers/code_analysis.py +332 -0
  651. claude_mpm/services/monitor/handlers/dashboard.py +299 -0
  652. claude_mpm/services/monitor/handlers/file.py +264 -0
  653. claude_mpm/services/monitor/handlers/hooks.py +512 -0
  654. claude_mpm/services/monitor/management/__init__.py +18 -0
  655. claude_mpm/services/monitor/management/health.py +124 -0
  656. claude_mpm/services/monitor/management/lifecycle.py +730 -0
  657. claude_mpm/services/monitor/server.py +1493 -0
  658. claude_mpm/services/monitor_build_service.py +349 -0
  659. claude_mpm/services/native_agent_converter.py +356 -0
  660. claude_mpm/services/orphan_detection.py +786 -0
  661. claude_mpm/services/pm_skills_deployer.py +707 -0
  662. claude_mpm/services/port_manager.py +597 -0
  663. claude_mpm/services/pr/__init__.py +14 -0
  664. claude_mpm/services/pr/pr_template_service.py +329 -0
  665. claude_mpm/services/profile_manager.py +337 -0
  666. claude_mpm/services/project/__init__.py +44 -0
  667. claude_mpm/services/{project_analyzer.py → project/analyzer.py} +541 -291
  668. claude_mpm/services/project/analyzer_v2.py +566 -0
  669. claude_mpm/services/project/architecture_analyzer.py +461 -0
  670. claude_mpm/services/project/archive_manager.py +1045 -0
  671. claude_mpm/services/project/dependency_analyzer.py +462 -0
  672. claude_mpm/services/project/detection_strategies.py +719 -0
  673. claude_mpm/services/project/documentation_manager.py +554 -0
  674. claude_mpm/services/project/enhanced_analyzer.py +572 -0
  675. claude_mpm/services/project/language_analyzer.py +265 -0
  676. claude_mpm/services/project/metrics_collector.py +407 -0
  677. claude_mpm/services/project/project_organizer.py +1009 -0
  678. claude_mpm/services/project/registry.py +636 -0
  679. claude_mpm/services/project/toolchain_analyzer.py +583 -0
  680. claude_mpm/services/project_port_allocator.py +596 -0
  681. claude_mpm/services/recovery_manager.py +293 -240
  682. claude_mpm/services/response_tracker.py +267 -0
  683. claude_mpm/services/runner_configuration_service.py +605 -0
  684. claude_mpm/services/self_upgrade_service.py +608 -0
  685. claude_mpm/services/session_management_service.py +314 -0
  686. claude_mpm/services/session_manager.py +380 -0
  687. claude_mpm/services/shared/__init__.py +21 -0
  688. claude_mpm/services/shared/async_service_base.py +216 -0
  689. claude_mpm/services/shared/config_service_base.py +301 -0
  690. claude_mpm/services/shared/lifecycle_service_base.py +308 -0
  691. claude_mpm/services/shared/manager_base.py +315 -0
  692. claude_mpm/services/shared/service_factory.py +309 -0
  693. claude_mpm/services/skills/__init__.py +21 -0
  694. claude_mpm/services/skills/git_skill_source_manager.py +1324 -0
  695. claude_mpm/services/skills/selective_skill_deployer.py +744 -0
  696. claude_mpm/services/skills/skill_discovery_service.py +568 -0
  697. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  698. claude_mpm/services/skills_config.py +547 -0
  699. claude_mpm/services/skills_deployer.py +1168 -0
  700. claude_mpm/services/socketio/__init__.py +25 -0
  701. claude_mpm/services/socketio/client_proxy.py +229 -0
  702. claude_mpm/services/socketio/dashboard_server.py +362 -0
  703. claude_mpm/services/socketio/event_normalizer.py +798 -0
  704. claude_mpm/services/socketio/handlers/__init__.py +30 -0
  705. claude_mpm/services/socketio/handlers/base.py +136 -0
  706. claude_mpm/services/socketio/handlers/code_analysis.py +682 -0
  707. claude_mpm/services/socketio/handlers/connection.py +643 -0
  708. claude_mpm/services/socketio/handlers/connection_handler.py +333 -0
  709. claude_mpm/services/socketio/handlers/file.py +263 -0
  710. claude_mpm/services/socketio/handlers/git.py +962 -0
  711. claude_mpm/services/socketio/handlers/hook.py +211 -0
  712. claude_mpm/services/socketio/handlers/memory.py +26 -0
  713. claude_mpm/services/socketio/handlers/project.py +24 -0
  714. claude_mpm/services/socketio/handlers/registry.py +214 -0
  715. claude_mpm/services/socketio/migration_utils.py +343 -0
  716. claude_mpm/services/socketio/monitor_client.py +364 -0
  717. claude_mpm/services/socketio/server/__init__.py +18 -0
  718. claude_mpm/services/socketio/server/broadcaster.py +569 -0
  719. claude_mpm/services/socketio/server/connection_manager.py +579 -0
  720. claude_mpm/services/socketio/server/core.py +1079 -0
  721. claude_mpm/services/socketio/server/eventbus_integration.py +245 -0
  722. claude_mpm/services/socketio/server/main.py +501 -0
  723. claude_mpm/services/socketio_client_manager.py +173 -143
  724. claude_mpm/services/socketio_server.py +38 -1657
  725. claude_mpm/services/subprocess_launcher_service.py +322 -0
  726. claude_mpm/services/system_instructions_service.py +270 -0
  727. claude_mpm/services/ticket_manager.py +25 -209
  728. claude_mpm/services/ticket_services/__init__.py +26 -0
  729. claude_mpm/services/ticket_services/crud_service.py +328 -0
  730. claude_mpm/services/ticket_services/formatter_service.py +290 -0
  731. claude_mpm/services/ticket_services/search_service.py +324 -0
  732. claude_mpm/services/ticket_services/validation_service.py +303 -0
  733. claude_mpm/services/ticket_services/workflow_service.py +244 -0
  734. claude_mpm/services/unified/__init__.py +65 -0
  735. claude_mpm/services/unified/analyzer_strategies/__init__.py +44 -0
  736. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +518 -0
  737. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +680 -0
  738. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +900 -0
  739. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +745 -0
  740. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +733 -0
  741. claude_mpm/services/unified/config_strategies/__init__.py +175 -0
  742. claude_mpm/services/unified/config_strategies/config_schema.py +731 -0
  743. claude_mpm/services/unified/config_strategies/context_strategy.py +747 -0
  744. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1005 -0
  745. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +881 -0
  746. claude_mpm/services/unified/config_strategies/unified_config_service.py +823 -0
  747. claude_mpm/services/unified/config_strategies/validation_strategy.py +1148 -0
  748. claude_mpm/services/unified/deployment_strategies/__init__.py +97 -0
  749. claude_mpm/services/unified/deployment_strategies/base.py +553 -0
  750. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +573 -0
  751. claude_mpm/services/unified/deployment_strategies/local.py +607 -0
  752. claude_mpm/services/unified/deployment_strategies/utils.py +667 -0
  753. claude_mpm/services/unified/deployment_strategies/vercel.py +471 -0
  754. claude_mpm/services/unified/interfaces.py +475 -0
  755. claude_mpm/services/unified/migration.py +509 -0
  756. claude_mpm/services/unified/strategies.py +534 -0
  757. claude_mpm/services/unified/unified_analyzer.py +542 -0
  758. claude_mpm/services/unified/unified_config.py +691 -0
  759. claude_mpm/services/unified/unified_deployment.py +466 -0
  760. claude_mpm/services/utility_service.py +280 -0
  761. claude_mpm/services/version_control/__init__.py +34 -37
  762. claude_mpm/services/version_control/branch_strategy.py +26 -17
  763. claude_mpm/services/version_control/conflict_resolution.py +52 -36
  764. claude_mpm/services/version_control/git_operations.py +183 -49
  765. claude_mpm/services/version_control/semantic_versioning.py +172 -61
  766. claude_mpm/services/version_control/version_parser.py +546 -0
  767. claude_mpm/services/version_service.py +379 -0
  768. claude_mpm/services/visualization/__init__.py +15 -0
  769. claude_mpm/services/visualization/mermaid_generator.py +937 -0
  770. claude_mpm/skills/__init__.py +42 -0
  771. claude_mpm/skills/agent_skills_injector.py +324 -0
  772. claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
  773. claude_mpm/skills/bundled/__init__.py +6 -0
  774. claude_mpm/skills/bundled/api-documentation.md +393 -0
  775. claude_mpm/skills/bundled/async-testing.md +571 -0
  776. claude_mpm/skills/bundled/code-review.md +143 -0
  777. claude_mpm/skills/bundled/database-migration.md +199 -0
  778. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  779. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  780. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  781. claude_mpm/skills/bundled/git-workflow.md +414 -0
  782. claude_mpm/skills/bundled/imagemagick.md +204 -0
  783. claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
  784. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  785. claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
  786. claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
  787. claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
  788. claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
  789. claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -0
  790. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  791. claude_mpm/skills/bundled/pdf.md +141 -0
  792. claude_mpm/skills/bundled/performance-profiling.md +573 -0
  793. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  794. claude_mpm/skills/bundled/security-scanning.md +439 -0
  795. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  796. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  797. claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
  798. claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
  799. claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
  800. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
  801. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  802. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  803. claude_mpm/skills/bundled/xlsx.md +157 -0
  804. claude_mpm/skills/registry.py +286 -0
  805. claude_mpm/skills/skill_manager.py +405 -0
  806. claude_mpm/skills/skills_registry.py +347 -0
  807. claude_mpm/skills/skills_service.py +739 -0
  808. claude_mpm/storage/__init__.py +9 -0
  809. claude_mpm/storage/state_storage.py +546 -0
  810. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  811. claude_mpm/templates/questions/__init__.py +38 -0
  812. claude_mpm/templates/questions/base.py +193 -0
  813. claude_mpm/templates/questions/pr_strategy.py +311 -0
  814. claude_mpm/templates/questions/project_init.py +385 -0
  815. claude_mpm/templates/questions/ticket_mgmt.py +394 -0
  816. claude_mpm/ticket_wrapper.py +2 -2
  817. claude_mpm/tools/__init__.py +10 -0
  818. claude_mpm/tools/__main__.py +208 -0
  819. claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
  820. claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
  821. claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
  822. claude_mpm/tools/code_tree_analyzer/core.py +380 -0
  823. claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
  824. claude_mpm/tools/code_tree_analyzer/events.py +168 -0
  825. claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
  826. claude_mpm/tools/code_tree_analyzer/models.py +39 -0
  827. claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
  828. claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
  829. claude_mpm/tools/code_tree_builder.py +631 -0
  830. claude_mpm/tools/code_tree_events.py +420 -0
  831. claude_mpm/tools/socketio_debug.py +671 -0
  832. claude_mpm/utils/__init__.py +8 -8
  833. claude_mpm/utils/agent_dependency_loader.py +1090 -0
  834. claude_mpm/utils/agent_filters.py +261 -0
  835. claude_mpm/utils/common.py +544 -0
  836. claude_mpm/utils/config_manager.py +168 -126
  837. claude_mpm/utils/console.py +11 -0
  838. claude_mpm/utils/database_connector.py +298 -0
  839. claude_mpm/utils/dependency_cache.py +373 -0
  840. claude_mpm/utils/dependency_manager.py +60 -59
  841. claude_mpm/utils/dependency_strategies.py +381 -0
  842. claude_mpm/utils/display_helper.py +260 -0
  843. claude_mpm/utils/environment_context.py +313 -0
  844. claude_mpm/utils/error_handler.py +78 -66
  845. claude_mpm/utils/file_utils.py +305 -0
  846. claude_mpm/utils/framework_detection.py +12 -11
  847. claude_mpm/utils/git_analyzer.py +407 -0
  848. claude_mpm/utils/gitignore.py +244 -0
  849. claude_mpm/utils/import_migration_example.py +12 -60
  850. claude_mpm/utils/imports.py +48 -45
  851. claude_mpm/utils/log_cleanup.py +627 -0
  852. claude_mpm/utils/migration.py +372 -0
  853. claude_mpm/utils/path_operations.py +110 -104
  854. claude_mpm/utils/progress.py +387 -0
  855. claude_mpm/utils/robust_installer.py +823 -0
  856. claude_mpm/utils/session_logging.py +121 -0
  857. claude_mpm/utils/structured_questions.py +619 -0
  858. claude_mpm/utils/subprocess_utils.py +343 -0
  859. claude_mpm/validation/__init__.py +1 -1
  860. claude_mpm/validation/agent_validator.py +214 -108
  861. claude_mpm/validation/frontmatter_validator.py +252 -0
  862. claude_mpm-5.4.55.dist-info/METADATA +999 -0
  863. claude_mpm-5.4.55.dist-info/RECORD +868 -0
  864. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.55.dist-info}/entry_points.txt +1 -3
  865. claude_mpm-5.4.55.dist-info/licenses/LICENSE +94 -0
  866. claude_mpm-5.4.55.dist-info/licenses/LICENSE-FAQ.md +153 -0
  867. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -88
  868. claude_mpm/agents/INSTRUCTIONS.md +0 -352
  869. claude_mpm/agents/backups/INSTRUCTIONS.md +0 -352
  870. claude_mpm/agents/base_agent_loader.py +0 -529
  871. claude_mpm/agents/schema/agent_schema.json +0 -314
  872. claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -36
  873. claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +0 -46
  874. claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +0 -45
  875. claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +0 -49
  876. claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +0 -46
  877. claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +0 -45
  878. claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +0 -49
  879. claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +0 -46
  880. claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +0 -46
  881. claude_mpm/agents/templates/data_engineer.json +0 -110
  882. claude_mpm/agents/templates/documentation.json +0 -109
  883. claude_mpm/agents/templates/engineer.json +0 -113
  884. claude_mpm/agents/templates/ops.json +0 -109
  885. claude_mpm/agents/templates/pm.json +0 -25
  886. claude_mpm/agents/templates/qa.json +0 -111
  887. claude_mpm/agents/templates/research.json +0 -65
  888. claude_mpm/agents/templates/security.json +0 -113
  889. claude_mpm/agents/templates/test_integration.json +0 -112
  890. claude_mpm/agents/templates/version_control.json +0 -107
  891. claude_mpm/cli/commands/ui.py +0 -57
  892. claude_mpm/core/simple_runner.py +0 -1046
  893. claude_mpm/dashboard/open_dashboard.py +0 -34
  894. claude_mpm/deployment_paths.py +0 -261
  895. claude_mpm/hooks/builtin/__init__.py +0 -1
  896. claude_mpm/hooks/builtin/logging_hook_example.py +0 -165
  897. claude_mpm/hooks/builtin/memory_hooks_example.py +0 -67
  898. claude_mpm/hooks/builtin/mpm_command_hook.py +0 -125
  899. claude_mpm/hooks/builtin/post_delegation_hook_example.py +0 -124
  900. claude_mpm/hooks/builtin/pre_delegation_hook_example.py +0 -125
  901. claude_mpm/hooks/builtin/submit_hook_example.py +0 -100
  902. claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +0 -237
  903. claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +0 -240
  904. claude_mpm/hooks/builtin/workflow_start_hook.py +0 -181
  905. claude_mpm/orchestration/__init__.py +0 -6
  906. claude_mpm/orchestration/archive/direct_orchestrator.py +0 -195
  907. claude_mpm/orchestration/archive/factory.py +0 -215
  908. claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +0 -188
  909. claude_mpm/orchestration/archive/hook_integration_example.py +0 -178
  910. claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +0 -826
  911. claude_mpm/orchestration/archive/orchestrator.py +0 -501
  912. claude_mpm/orchestration/archive/pexpect_orchestrator.py +0 -252
  913. claude_mpm/orchestration/archive/pty_orchestrator.py +0 -270
  914. claude_mpm/orchestration/archive/simple_orchestrator.py +0 -82
  915. claude_mpm/orchestration/archive/subprocess_orchestrator.py +0 -801
  916. claude_mpm/orchestration/archive/system_prompt_orchestrator.py +0 -278
  917. claude_mpm/orchestration/archive/wrapper_orchestrator.py +0 -187
  918. claude_mpm/schemas/workflow_validator.py +0 -411
  919. claude_mpm/services/agent_deployment.py +0 -1534
  920. claude_mpm/services/agent_lifecycle_manager.py +0 -1169
  921. claude_mpm/services/agent_memory_manager.py +0 -1415
  922. claude_mpm/services/agent_registry.py +0 -676
  923. claude_mpm/services/deployed_agent_discovery.py +0 -226
  924. claude_mpm/services/framework_agent_loader.py +0 -337
  925. claude_mpm/services/framework_claude_md_generator.py +0 -621
  926. claude_mpm/services/health_monitor.py +0 -892
  927. claude_mpm/services/memory_router.py +0 -538
  928. claude_mpm/services/parent_directory_manager/__init__.py +0 -577
  929. claude_mpm/services/parent_directory_manager/backup_manager.py +0 -258
  930. claude_mpm/services/parent_directory_manager/config_manager.py +0 -210
  931. claude_mpm/services/parent_directory_manager/deduplication_manager.py +0 -279
  932. claude_mpm/services/parent_directory_manager/framework_protector.py +0 -143
  933. claude_mpm/services/parent_directory_manager/operations.py +0 -186
  934. claude_mpm/services/parent_directory_manager/state_manager.py +0 -624
  935. claude_mpm/services/parent_directory_manager/template_deployer.py +0 -579
  936. claude_mpm/services/parent_directory_manager/validation_manager.py +0 -378
  937. claude_mpm/services/parent_directory_manager/version_control_helper.py +0 -339
  938. claude_mpm/services/parent_directory_manager/version_manager.py +0 -222
  939. claude_mpm/services/standalone_socketio_server.py +0 -1300
  940. claude_mpm/services/ticket_manager_di.py +0 -318
  941. claude_mpm/services/ticketing_service_original.py +0 -508
  942. claude_mpm/ui/__init__.py +0 -1
  943. claude_mpm/ui/rich_terminal_ui.py +0 -295
  944. claude_mpm/ui/terminal_ui.py +0 -328
  945. claude_mpm/utils/paths.py +0 -289
  946. claude_mpm-3.4.10.dist-info/METADATA +0 -183
  947. claude_mpm-3.4.10.dist-info/RECORD +0 -201
  948. claude_mpm-3.4.10.dist-info/licenses/LICENSE +0 -21
  949. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.55.dist-info}/WHEEL +0 -0
  950. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.55.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,862 @@
1
+ """Service for discovering and converting remote Markdown agents to JSON format.
2
+
3
+ This service handles the 4th tier of agent discovery: remote agents cached from GitHub.
4
+ Remote agents are stored as Markdown files with YAML frontmatter and need to be converted
5
+ to the JSON template format expected by the deployment system.
6
+
7
+ WHY: Remote agents from GitHub are cached as Markdown but the deployment system expects
8
+ JSON templates. This service bridges that gap and integrates remote agents into the
9
+ multi-tier discovery system.
10
+ """
11
+
12
+ import json
13
+ import re
14
+ from dataclasses import dataclass
15
+ from pathlib import Path
16
+ from typing import Any, Dict, List, Optional
17
+
18
+ import yaml
19
+
20
+ from claude_mpm.core.logging_config import get_logger
21
+
22
+ logger = get_logger(__name__)
23
+
24
+
25
+ @dataclass
26
+ class RemoteAgentMetadata:
27
+ """Metadata extracted from remote agent Markdown file."""
28
+
29
+ name: str
30
+ description: str
31
+ model: str
32
+ routing_keywords: List[str]
33
+ routing_paths: List[str]
34
+ routing_priority: int
35
+ source_file: Path
36
+ version: str # SHA-256 hash from cache metadata
37
+ collection_id: Optional[str] = None # Format: owner/repo-name
38
+ source_path: Optional[str] = None # Relative path in repo
39
+ canonical_id: Optional[str] = None # Format: collection_id:agent_id
40
+
41
+
42
+ class RemoteAgentDiscoveryService:
43
+ """Discovers and converts remote Markdown agents to JSON format.
44
+
45
+ Remote agents are discovered from the cache directory (~/.claude-mpm/cache/agents/)
46
+ where they are stored as Markdown files. This service:
47
+ 1. Discovers all *.md files in the remote agents cache
48
+ 2. Parses Markdown frontmatter and content to extract metadata
49
+ 3. Converts to JSON template format for deployment
50
+ 4. Retrieves version (SHA-256 hash) from cache metadata
51
+
52
+ Design Decision: Markdown Parsing Strategy
53
+ - Use regex for simple frontmatter extraction (fast, no dependencies)
54
+ - Parse key-value pairs from Configuration section
55
+ - Extract routing info from Routing section
56
+ - Fallback to sensible defaults when sections are missing
57
+
58
+ Trade-offs:
59
+ - Performance: Regex parsing is fast for our simple format
60
+ - Maintainability: Clear regex patterns are easy to understand
61
+ - Flexibility: Supports optional sections with defaults
62
+ """
63
+
64
+ def __init__(self, agents_cache_dir: Path):
65
+ """Initialize the remote agent discovery service.
66
+
67
+ Args:
68
+ agents_cache_dir: Directory containing cached agent Markdown files
69
+ """
70
+ self.agents_cache_dir = agents_cache_dir
71
+ self.logger = get_logger(__name__)
72
+
73
+ def _extract_collection_id_from_path(self, file_path: Path) -> Optional[str]:
74
+ """Extract collection_id from repository path structure.
75
+
76
+ Collection ID is derived from the repository path structure:
77
+ ~/.claude-mpm/cache/agents/{owner}/{repo}/agents/...
78
+
79
+ Args:
80
+ file_path: Absolute path to agent Markdown file
81
+
82
+ Returns:
83
+ Collection ID in format "owner/repo-name" or None if not found
84
+
85
+ Example:
86
+ Input: ~/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents/agents/pm.md
87
+ Output: "bobmatnyc/claude-mpm-agents"
88
+ """
89
+ try:
90
+ # Find "agents" cache directory in the path (looking for .claude-mpm/cache/agents)
91
+ path_parts = file_path.parts
92
+ agents_cache_idx = -1
93
+
94
+ for i, part in enumerate(path_parts):
95
+ # Look for cache/agents pattern
96
+ if part == "agents" and i > 0 and path_parts[i - 1] == "cache":
97
+ agents_cache_idx = i
98
+ break
99
+
100
+ if agents_cache_idx == -1 or agents_cache_idx + 2 >= len(path_parts):
101
+ self.logger.debug(
102
+ f"Could not extract collection_id from path: {file_path}"
103
+ )
104
+ return None
105
+
106
+ # Extract owner and repo (next two parts after "cache/agents")
107
+ owner = path_parts[agents_cache_idx + 1]
108
+ repo = path_parts[agents_cache_idx + 2]
109
+
110
+ collection_id = f"{owner}/{repo}"
111
+ self.logger.debug(f"Extracted collection_id: {collection_id}")
112
+ return collection_id
113
+
114
+ except Exception as e:
115
+ self.logger.warning(
116
+ f"Failed to extract collection_id from {file_path}: {e}"
117
+ )
118
+ return None
119
+
120
+ def _extract_source_path_from_file(self, file_path: Path) -> Optional[str]:
121
+ """Extract relative source path within repository.
122
+
123
+ Source path is relative to the repository root (not the agents subdirectory).
124
+
125
+ Args:
126
+ file_path: Absolute path to agent Markdown file
127
+
128
+ Returns:
129
+ Relative path from repo root, or None if not found
130
+
131
+ Example:
132
+ Input: ~/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents/agents/pm.md
133
+ Output: "agents/pm.md"
134
+ """
135
+ try:
136
+ # Find "agents" cache directory in the path
137
+ path_parts = file_path.parts
138
+ agents_cache_idx = -1
139
+
140
+ for i, part in enumerate(path_parts):
141
+ # Look for cache/agents pattern
142
+ if part == "agents" and i > 0 and path_parts[i - 1] == "cache":
143
+ agents_cache_idx = i
144
+ break
145
+
146
+ if agents_cache_idx == -1 or agents_cache_idx + 3 >= len(path_parts):
147
+ return None
148
+
149
+ # Path after owner/repo is the source path
150
+ # cache/agents/{owner}/{repo}/{source_path}
151
+ repo_root_idx = agents_cache_idx + 3
152
+ source_parts = path_parts[repo_root_idx:]
153
+
154
+ return "/".join(source_parts)
155
+
156
+ except Exception as e:
157
+ self.logger.warning(f"Failed to extract source_path from {file_path}: {e}")
158
+ return None
159
+
160
+ def _parse_yaml_frontmatter(self, content: str) -> Optional[Dict[str, Any]]:
161
+ """Parse YAML frontmatter from Markdown content.
162
+
163
+ Extracts YAML frontmatter delimited by --- markers at the start of the file.
164
+ Uses a tolerant approach: attempts full YAML parsing first, falls back to
165
+ simple key-value extraction for malformed YAML.
166
+
167
+ Design Decision: Tolerant YAML Parsing
168
+
169
+ Rationale: Some agent markdown files have malformed YAML (incorrect indentation
170
+ in nested structures). Rather than failing completely, we:
171
+ 1. Try full YAML parsing first (handles well-formed YAML)
172
+ 2. Fall back to regex extraction for critical fields (agent_id, name, etc.)
173
+ 3. Log warnings but continue processing
174
+
175
+ This ensures we can still extract agent_id even if complex nested structures
176
+ (like template_changelog) have indentation issues.
177
+
178
+ Args:
179
+ content: Full Markdown file content
180
+
181
+ Returns:
182
+ Dictionary of parsed YAML frontmatter, or None if not found
183
+
184
+ Example:
185
+ Input:
186
+ ---
187
+ agent_id: python-engineer
188
+ name: Python Engineer
189
+ version: 2.3.0
190
+ ---
191
+ # Agent content...
192
+
193
+ Output:
194
+ {"agent_id": "python-engineer", "name": "Python Engineer", "version": "2.3.0"}
195
+ """
196
+ try:
197
+ # Check if content starts with YAML frontmatter
198
+ if not content.startswith("---"):
199
+ self.logger.debug("No YAML frontmatter found (doesn't start with ---)")
200
+ return None
201
+
202
+ # Extract frontmatter content between --- markers
203
+ frontmatter_match = re.match(r"^---\n(.*?)\n---\s*\n", content, re.DOTALL)
204
+ if not frontmatter_match:
205
+ self.logger.debug("No closing --- marker found for YAML frontmatter")
206
+ return None
207
+
208
+ yaml_content = frontmatter_match.group(1)
209
+
210
+ # Try full YAML parsing first
211
+ try:
212
+ parsed = yaml.safe_load(yaml_content)
213
+ if isinstance(parsed, dict):
214
+ return parsed
215
+ self.logger.warning(
216
+ f"YAML frontmatter is not a dictionary: {type(parsed)}"
217
+ )
218
+ except yaml.YAMLError as e:
219
+ # Malformed YAML (e.g., indentation errors) - fall back to regex extraction
220
+ self.logger.debug(
221
+ f"Full YAML parse failed, using fallback extraction: {e}"
222
+ )
223
+
224
+ # Extract key fields using regex (tolerant of malformed nested structures)
225
+ result = {}
226
+
227
+ # Extract simple key-value pairs (no nested structures)
228
+ simple_keys = [
229
+ "agent_id",
230
+ "name",
231
+ "description",
232
+ "version",
233
+ "model",
234
+ "agent_type",
235
+ "category",
236
+ "author",
237
+ "schema_version",
238
+ ]
239
+
240
+ for key in simple_keys:
241
+ # Match key: value on a line (not indented, so it's top-level)
242
+ pattern = rf"^{key}:\s*(.+?)$"
243
+ match = re.search(pattern, yaml_content, re.MULTILINE)
244
+ if match:
245
+ value = match.group(1).strip()
246
+ # Remove quotes if present
247
+ if value.startswith(("'", '"')) and value.endswith(("'", '"')):
248
+ value = value[1:-1]
249
+ result[key] = value
250
+
251
+ if result:
252
+ self.logger.debug(
253
+ f"Extracted {len(result)} fields using fallback method"
254
+ )
255
+ return result
256
+ return None
257
+
258
+ except Exception as e:
259
+ self.logger.warning(f"Unexpected error parsing frontmatter: {e}")
260
+ return None
261
+
262
+ return None
263
+
264
+ def _generate_hierarchical_id(self, file_path: Path) -> str:
265
+ """Generate hierarchical agent ID from file path.
266
+
267
+ Converts file path relative to agents subdirectory into hierarchical ID.
268
+
269
+ Design Decision: Path-based IDs for hierarchy preservation
270
+
271
+ Rationale: Agent IDs must reflect directory hierarchy to enable:
272
+ - Category-based filtering (engineer/backend/python-engineer)
273
+ - Preset matching against AUTO-DEPLOY-INDEX.md
274
+ - Multi-level organization without name collisions
275
+
276
+ Supports both cache structures:
277
+ 1. Git repo: Calculate relative to /agents/ subdirectory
278
+ 2. Flattened cache: Calculate relative to agents_cache_dir directly
279
+
280
+ Example (Git repo):
281
+ Input: /cache/bobmatnyc/claude-mpm-agents/agents/engineer/backend/python-engineer.md
282
+ Root: /cache/bobmatnyc/claude-mpm-agents/agents
283
+ Output: engineer/backend/python-engineer
284
+
285
+ Example (Flattened cache):
286
+ Input: /cache/agents/engineer/python-engineer.md
287
+ Root: /cache/agents
288
+ Output: engineer/python-engineer
289
+
290
+ Args:
291
+ file_path: Absolute path to agent Markdown file
292
+
293
+ Returns:
294
+ Hierarchical agent ID with forward slashes
295
+ """
296
+ try:
297
+ # Try git repo structure first: /agents/ subdirectory
298
+ agents_dir = self.agents_cache_dir / "agents"
299
+ if agents_dir.exists():
300
+ try:
301
+ relative_path = file_path.relative_to(agents_dir)
302
+ return str(relative_path.with_suffix("")).replace("\\", "/")
303
+ except ValueError:
304
+ pass # Not under agents_dir, try flattened structure
305
+
306
+ # Try flattened cache structure: calculate relative to agents_cache_dir
307
+ try:
308
+ relative_path = file_path.relative_to(self.agents_cache_dir)
309
+ return str(relative_path.with_suffix("")).replace("\\", "/")
310
+ except ValueError:
311
+ pass # Not under agents_cache_dir either
312
+
313
+ # Fall back to filename
314
+ self.logger.warning(
315
+ f"File {file_path} not under expected directories, using filename"
316
+ )
317
+ return file_path.stem
318
+ except Exception as e:
319
+ self.logger.warning(
320
+ f"Error generating hierarchical ID for {file_path}: {e}"
321
+ )
322
+ return file_path.stem
323
+
324
+ def _detect_category_from_path(self, file_path: Path) -> str:
325
+ """Detect category from file path hierarchy.
326
+
327
+ Extracts category from directory structure. Category is the path
328
+ from agents subdirectory to the file, excluding the filename.
329
+
330
+ Supports both cache structures:
331
+ 1. Git repo: Calculate relative to /agents/ subdirectory
332
+ 2. Flattened cache: Calculate relative to agents_cache_dir directly
333
+
334
+ Example (Git repo):
335
+ Input: /cache/bobmatnyc/claude-mpm-agents/agents/engineer/backend/python-engineer.md
336
+ Root: /cache/bobmatnyc/claude-mpm-agents/agents
337
+ Output: engineer/backend
338
+
339
+ Example (Flattened cache):
340
+ Input: /cache/agents/engineer/python-engineer.md
341
+ Root: /cache/agents
342
+ Output: engineer
343
+
344
+ Args:
345
+ file_path: Absolute path to agent Markdown file
346
+
347
+ Returns:
348
+ Category path with forward slashes, or "universal" if in root
349
+ """
350
+ try:
351
+ # Try git repo structure first: /agents/ subdirectory
352
+ agents_dir = self.agents_cache_dir / "agents"
353
+ if agents_dir.exists():
354
+ try:
355
+ relative_path = file_path.relative_to(agents_dir)
356
+ parts = relative_path.parts[:-1] # Exclude filename
357
+ return "/".join(parts) if parts else "universal"
358
+ except ValueError:
359
+ pass # Not under agents_dir, try flattened structure
360
+
361
+ # Try flattened cache structure: calculate relative to agents_cache_dir
362
+ try:
363
+ relative_path = file_path.relative_to(self.agents_cache_dir)
364
+ parts = relative_path.parts[:-1] # Exclude filename
365
+ return "/".join(parts) if parts else "universal"
366
+ except ValueError:
367
+ pass # Not under agents_cache_dir either
368
+
369
+ return "universal"
370
+ except Exception:
371
+ return "universal"
372
+
373
+ def discover_remote_agents(self) -> List[Dict[str, Any]]:
374
+ """Discover all remote agents from cache directory.
375
+
376
+ Scans the remote agents directory for *.md files recursively and converts each
377
+ to JSON template format. Skips files that can't be parsed.
378
+
379
+ Supports two cache structures:
380
+ 1. Git repo path: {path}/agents/ - has /agents/ subdirectory
381
+ 2. Flattened cache: {path}/ - directly contains category directories
382
+
383
+ Bug #4 Fix: Only scan /agents/ subdirectory when it exists to prevent
384
+ README.md, CHANGELOG.md, etc. from being treated as agents.
385
+
386
+ Returns:
387
+ List of agent dictionaries in JSON template format
388
+
389
+ Example:
390
+ >>> service = RemoteAgentDiscoveryService(Path("~/.claude-mpm/cache/agents"))
391
+ >>> agents = service.discover_remote_agents()
392
+ >>> len(agents)
393
+ 5
394
+ >>> agents[0]['name']
395
+ 'Security Scanner Agent'
396
+ """
397
+ agents = []
398
+
399
+ if not self.agents_cache_dir.exists():
400
+ self.logger.debug(
401
+ f"Agents cache directory does not exist: {self.agents_cache_dir}"
402
+ )
403
+ return agents
404
+
405
+ # Support four cache structures (PRIORITY ORDER):
406
+ # 1. Built output: {path}/dist/agents/ - PREFERRED (built with BASE-AGENT composition)
407
+ # 2. Git repo path: {path}/agents/ - source files (fallback)
408
+ # 3. Owner/repo structure: {path}/{owner}/{repo}/agents/ - GitHub sync structure
409
+ # 4. Flattened cache: {path}/ - directly contains category directories (legacy)
410
+
411
+ # Priority 1: Check for dist/agents/ (built output with BASE-AGENT composition)
412
+ dist_agents_dir = self.agents_cache_dir / "dist" / "agents"
413
+ agents_dir = self.agents_cache_dir / "agents"
414
+
415
+ if dist_agents_dir.exists():
416
+ # PREFERRED: Use built agents from dist/agents/
417
+ # These have BASE-AGENT.md files properly composed by build-agent.py
418
+ self.logger.debug(f"Using built agents from dist: {dist_agents_dir}")
419
+ scan_dir = dist_agents_dir
420
+ elif agents_dir.exists():
421
+ # FALLBACK: Git repo structure - scan /agents/ subdirectory (source files)
422
+ # This path is used when dist/agents/ hasn't been built yet
423
+ self.logger.debug(f"Using source agents (no dist/ found): {agents_dir}")
424
+ scan_dir = agents_dir
425
+ else:
426
+ # Priority 3: Check for {owner}/{repo}/agents/ structure (GitHub sync)
427
+ # e.g., ~/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents/agents/
428
+ owner_repo_agents_dir = None
429
+ for owner_dir in self.agents_cache_dir.iterdir():
430
+ if owner_dir.is_dir() and not owner_dir.name.startswith("."):
431
+ for repo_dir in owner_dir.iterdir():
432
+ if repo_dir.is_dir():
433
+ potential_agents = repo_dir / "agents"
434
+ if potential_agents.exists():
435
+ owner_repo_agents_dir = potential_agents
436
+ self.logger.debug(
437
+ f"Using GitHub sync structure: {owner_repo_agents_dir}"
438
+ )
439
+ break
440
+ if owner_repo_agents_dir:
441
+ break
442
+
443
+ if owner_repo_agents_dir:
444
+ scan_dir = owner_repo_agents_dir
445
+ else:
446
+ # LEGACY: Flattened cache structure - scan root directly
447
+ # Check if this looks like the flattened cache (has category subdirectories)
448
+ category_dirs = [
449
+ "universal",
450
+ "engineer",
451
+ "ops",
452
+ "qa",
453
+ "security",
454
+ "documentation",
455
+ ]
456
+ has_categories = any(
457
+ (self.agents_cache_dir / cat).exists() for cat in category_dirs
458
+ )
459
+
460
+ if has_categories:
461
+ self.logger.debug(
462
+ f"Using flattened cache structure: {self.agents_cache_dir}"
463
+ )
464
+ scan_dir = self.agents_cache_dir
465
+ else:
466
+ self.logger.warning(
467
+ f"No agent directories found. Checked: {dist_agents_dir}, {agents_dir}, "
468
+ f"owner/repo/agents/ structure, and category directories in {self.agents_cache_dir}. "
469
+ "Expected agents in /dist/agents/, /agents/, owner/repo/agents/, or category directories."
470
+ )
471
+ return agents
472
+
473
+ # Find all Markdown files recursively
474
+ md_files = list(scan_dir.rglob("*.md"))
475
+
476
+ # Filter out non-agent files and git repository files
477
+ excluded_files = {
478
+ "README.md",
479
+ "CHANGELOG.md",
480
+ "CONTRIBUTING.md",
481
+ "LICENSE.md",
482
+ "BASE-AGENT.md",
483
+ "SUMMARY.md",
484
+ "IMPLEMENTATION-SUMMARY.md",
485
+ "REFACTORING_REPORT.md",
486
+ "REORGANIZATION-PLAN.md",
487
+ "AUTO-DEPLOY-INDEX.md",
488
+ "PHASE1_COMPLETE.md",
489
+ "AGENTS.md",
490
+ # Skill-related files (should not be treated as agents)
491
+ "SKILL.md",
492
+ "SKILLS.md",
493
+ "skill-template.md",
494
+ }
495
+ md_files = [f for f in md_files if f.name not in excluded_files]
496
+
497
+ # Filter out files from skills-related directories
498
+ # Skills are not agents and should not be discovered here
499
+ excluded_directory_patterns = {"references", "examples", "claude-mpm-skills"}
500
+ md_files = [
501
+ f
502
+ for f in md_files
503
+ if not any(excluded in f.parts for excluded in excluded_directory_patterns)
504
+ ]
505
+
506
+ # In flattened cache mode, also exclude files from git repository subdirectories
507
+ # (files under directories that contain .git folder)
508
+ if scan_dir == self.agents_cache_dir:
509
+ filtered_files = []
510
+ for f in md_files:
511
+ # Check if this file is inside a git repository (has .git in path)
512
+ # Git repos are at {agents_cache_dir}/{owner}/{repo}/.git
513
+ path_parts = f.relative_to(self.agents_cache_dir).parts
514
+ if len(path_parts) >= 2:
515
+ # Check if this looks like a git repo path (owner/repo)
516
+ potential_repo = (
517
+ self.agents_cache_dir / path_parts[0] / path_parts[1]
518
+ )
519
+ if (potential_repo / ".git").exists():
520
+ # This file is in a git repo, skip it (we'll handle git repos separately)
521
+ self.logger.debug(f"Skipping file in git repo: {f}")
522
+ continue
523
+ filtered_files.append(f)
524
+ md_files = filtered_files
525
+
526
+ self.logger.debug(f"Found {len(md_files)} Markdown files in {scan_dir}")
527
+
528
+ for md_file in md_files:
529
+ try:
530
+ agent_dict = self._parse_markdown_agent(md_file)
531
+ if agent_dict:
532
+ agents.append(agent_dict)
533
+ self.logger.debug(
534
+ f"Successfully parsed remote agent: {md_file.name}"
535
+ )
536
+ else:
537
+ self.logger.warning(
538
+ f"Failed to parse remote agent (no name found): {md_file.name}"
539
+ )
540
+ except Exception as e:
541
+ self.logger.warning(f"Failed to parse remote agent {md_file.name}: {e}")
542
+
543
+ self.logger.info(
544
+ f"Discovered {len(agents)} remote agents from {self.agents_cache_dir.name}"
545
+ )
546
+ return agents
547
+
548
+ def _parse_markdown_agent(self, md_file: Path) -> Optional[Dict[str, Any]]:
549
+ """Parse Markdown agent file and convert to JSON template format.
550
+
551
+ Expected Markdown format with YAML frontmatter:
552
+ ```markdown
553
+ ---
554
+ agent_id: python-engineer
555
+ name: Python Engineer
556
+ version: 2.3.0
557
+ model: sonnet
558
+ ---
559
+ # Agent Name
560
+
561
+ Description paragraph (first paragraph after heading)
562
+
563
+ ## Configuration
564
+ - Model: sonnet
565
+ - Priority: 100
566
+
567
+ ## Routing
568
+ - Keywords: keyword1, keyword2
569
+ - Paths: /path1/, /path2/
570
+ ```
571
+
572
+ Agent ID Priority (Mismatch Fix):
573
+ 1. Use agent_id from YAML frontmatter if present (e.g., "python-engineer")
574
+ 2. Fall back to leaf filename if no YAML frontmatter (e.g., "python-engineer.md" -> "python-engineer")
575
+ 3. Store hierarchical path separately as category_path for categorization
576
+
577
+ Args:
578
+ md_file: Path to Markdown agent file
579
+
580
+ Returns:
581
+ Agent dictionary in JSON template format, or None if parsing fails
582
+
583
+ Error Handling:
584
+ - Returns None if agent name (first heading) is missing
585
+ - Uses defaults for missing sections (model=sonnet, priority=50)
586
+ - Empty routing keywords/paths if Routing section missing
587
+ """
588
+ try:
589
+ content = md_file.read_text(encoding="utf-8")
590
+ except Exception as e:
591
+ self.logger.error(f"Failed to read file {md_file}: {e}")
592
+ return None
593
+
594
+ # MISMATCH FIX: Parse YAML frontmatter to extract agent_id
595
+ frontmatter = self._parse_yaml_frontmatter(content)
596
+
597
+ # MISMATCH FIX: Use agent_id from YAML frontmatter if present, otherwise fall back to filename
598
+ if frontmatter and "agent_id" in frontmatter:
599
+ agent_id = frontmatter["agent_id"]
600
+ self.logger.debug(f"Using agent_id from YAML frontmatter: {agent_id}")
601
+ else:
602
+ # Fallback: Use leaf filename without extension
603
+ agent_id = md_file.stem
604
+ self.logger.debug(f"No agent_id in YAML, using filename: {agent_id}")
605
+
606
+ # Store hierarchical path separately for categorization (not as primary ID)
607
+ hierarchical_path = self._generate_hierarchical_id(md_file)
608
+
609
+ # Extract agent name - prioritize frontmatter over markdown heading
610
+ # Frontmatter is intentional metadata, headings may be arbitrary content
611
+ if frontmatter and "name" in frontmatter:
612
+ name = frontmatter["name"]
613
+ else:
614
+ # Fallback to first heading or filename
615
+ name_match = re.search(r"^#\s+(.+?)$", content, re.MULTILINE)
616
+ if name_match:
617
+ name = name_match.group(1).strip()
618
+ else:
619
+ # Last resort: derive from filename
620
+ name = md_file.stem.replace("-", " ").replace("_", " ").title()
621
+
622
+ # Extract description - prioritize frontmatter over markdown content
623
+ # Frontmatter is intentional metadata, paragraphs may be arbitrary content
624
+ if frontmatter and "description" in frontmatter:
625
+ description = frontmatter["description"]
626
+ else:
627
+ # Fallback to first paragraph after heading
628
+ desc_match = re.search(
629
+ r"^#.+?\n\n(.+?)(?:\n\n##|\Z)", content, re.DOTALL | re.MULTILINE
630
+ )
631
+ if desc_match:
632
+ description = desc_match.group(1).strip()
633
+ else:
634
+ description = ""
635
+
636
+ # Extract model from YAML frontmatter or Configuration section
637
+ if frontmatter and "model" in frontmatter:
638
+ model = frontmatter["model"]
639
+ else:
640
+ model_match = re.search(r"Model:\s*(\w+)", content, re.IGNORECASE)
641
+ model = model_match.group(1) if model_match else "sonnet"
642
+
643
+ # Extract priority from Configuration section
644
+ priority_match = re.search(r"Priority:\s*(\d+)", content, re.IGNORECASE)
645
+ priority = int(priority_match.group(1)) if priority_match else 50
646
+
647
+ # Extract routing keywords
648
+ keywords_match = re.search(r"Keywords:\s*(.+?)(?:\n|$)", content, re.IGNORECASE)
649
+ keywords = []
650
+ if keywords_match:
651
+ keywords = [k.strip() for k in keywords_match.group(1).split(",")]
652
+
653
+ # Extract routing paths
654
+ paths_match = re.search(r"Paths:\s*(.+?)(?:\n|$)", content, re.IGNORECASE)
655
+ paths = []
656
+ if paths_match:
657
+ paths = [p.strip() for p in paths_match.group(1).split(",")]
658
+
659
+ # Get version (SHA-256 hash) from cache metadata or YAML frontmatter
660
+ if frontmatter and "version" in frontmatter:
661
+ version = frontmatter["version"]
662
+ else:
663
+ version = self._get_agent_version(md_file)
664
+
665
+ # Bug #1 fix: Detect category from directory path
666
+ category = self._detect_category_from_path(md_file)
667
+
668
+ # NEW: Extract collection metadata from path
669
+ collection_id = self._extract_collection_id_from_path(md_file)
670
+ source_path = self._extract_source_path_from_file(md_file)
671
+
672
+ # NEW: Generate canonical_id (collection_id:agent_id)
673
+ # Use leaf agent_id (not hierarchical path) for canonical_id
674
+ if collection_id:
675
+ canonical_id = f"{collection_id}:{agent_id}"
676
+ else:
677
+ # Fallback for legacy agents without collection
678
+ canonical_id = f"legacy:{agent_id}"
679
+
680
+ # Convert to JSON template format and return
681
+ # IMPORTANT: Include 'path' field for compatibility with deployment validation (ticket 1M-480)
682
+ # Git-sourced agents must have 'path' field to match structure from AgentDiscoveryService
683
+ return {
684
+ "agent_id": agent_id, # MISMATCH FIX: Use leaf name from YAML, not hierarchical path
685
+ "hierarchical_path": hierarchical_path, # Store hierarchical path separately
686
+ "canonical_id": canonical_id, # NEW: Primary matching key (uses leaf agent_id)
687
+ "collection_id": collection_id, # NEW: Collection identifier
688
+ "source_path": source_path, # NEW: Path within repository
689
+ "metadata": {
690
+ "name": name,
691
+ "description": description,
692
+ "version": version,
693
+ "author": "remote", # Mark as remote agent
694
+ "category": category, # Use detected category from path
695
+ "hierarchical_path": hierarchical_path, # For categorization/filtering
696
+ "collection_id": collection_id, # NEW: Also in metadata
697
+ "source_path": source_path, # NEW: Also in metadata
698
+ "canonical_id": canonical_id, # NEW: Also in metadata
699
+ },
700
+ "model": model,
701
+ "source": "remote", # Mark as remote agent
702
+ "source_file": str(md_file),
703
+ "path": str(
704
+ md_file
705
+ ), # Add 'path' field for deployment compatibility (1M-480)
706
+ "file_path": str(md_file), # Keep for backward compatibility
707
+ "version": version, # Include at root level for version comparison
708
+ "category": category, # Add category at root level for filtering
709
+ "routing": {"keywords": keywords, "paths": paths, "priority": priority},
710
+ }
711
+
712
+ def _get_agent_version(self, md_file: Path) -> str:
713
+ """Get version (SHA-256 hash) from cache metadata.
714
+
715
+ Looks for corresponding .meta.json file in cache directory that contains
716
+ the SHA-256 hash of the agent content.
717
+
718
+ Args:
719
+ md_file: Path to Markdown agent file
720
+
721
+ Returns:
722
+ SHA-256 hash from metadata, or 'unknown' if not found
723
+
724
+ Example metadata file:
725
+ {
726
+ "content_hash": "abc123...",
727
+ "etag": "W/\"abc123\"",
728
+ "last_modified": "2025-11-30T10:00:00Z"
729
+ }
730
+ """
731
+ # Look for .meta.json file
732
+ meta_file = md_file.with_suffix(".md.meta.json")
733
+
734
+ if not meta_file.exists():
735
+ self.logger.debug(f"No metadata file found for {md_file.name}")
736
+ return "unknown"
737
+
738
+ try:
739
+ meta_data = json.loads(meta_file.read_text(encoding="utf-8"))
740
+ content_hash = meta_data.get("content_hash", "unknown")
741
+ self.logger.debug(
742
+ f"Retrieved version {content_hash[:8]}... for {md_file.name}"
743
+ )
744
+ return content_hash
745
+ except Exception as e:
746
+ self.logger.warning(f"Failed to read metadata for {md_file.name}: {e}")
747
+ return "unknown"
748
+
749
+ def get_remote_agent_metadata(
750
+ self, agent_name: str
751
+ ) -> Optional[RemoteAgentMetadata]:
752
+ """Get metadata for a specific remote agent.
753
+
754
+ Args:
755
+ agent_name: Name of the agent to retrieve
756
+
757
+ Returns:
758
+ RemoteAgentMetadata if found, None otherwise
759
+ """
760
+ # Bug #4 fix: Search in /agents/ subdirectory, not root directory
761
+ agents_dir = self.agents_cache_dir / "agents"
762
+ if not agents_dir.exists():
763
+ return None
764
+
765
+ for md_file in agents_dir.rglob("*.md"):
766
+ agent_dict = self._parse_markdown_agent(md_file)
767
+ if agent_dict and agent_dict["metadata"]["name"] == agent_name:
768
+ return RemoteAgentMetadata(
769
+ name=agent_dict["metadata"]["name"],
770
+ description=agent_dict["metadata"]["description"],
771
+ model=agent_dict["model"],
772
+ routing_keywords=agent_dict["routing"]["keywords"],
773
+ routing_paths=agent_dict["routing"]["paths"],
774
+ routing_priority=agent_dict["routing"]["priority"],
775
+ source_file=Path(agent_dict["source_file"]),
776
+ version=agent_dict["version"],
777
+ collection_id=agent_dict.get("collection_id"),
778
+ source_path=agent_dict.get("source_path"),
779
+ canonical_id=agent_dict.get("canonical_id"),
780
+ )
781
+ return None
782
+
783
+ def get_agents_by_collection(self, collection_id: str) -> List[Dict[str, Any]]:
784
+ """Get all agents belonging to a specific collection.
785
+
786
+ Args:
787
+ collection_id: Collection identifier in format "owner/repo-name"
788
+
789
+ Returns:
790
+ List of agent dictionaries from the specified collection
791
+
792
+ Example:
793
+ >>> service = RemoteAgentDiscoveryService(Path("~/.claude-mpm/cache/agents"))
794
+ >>> agents = service.get_agents_by_collection("bobmatnyc/claude-mpm-agents")
795
+ >>> len(agents)
796
+ 45
797
+ """
798
+ all_agents = self.discover_remote_agents()
799
+
800
+ # Filter by collection_id
801
+ collection_agents = [
802
+ agent for agent in all_agents if agent.get("collection_id") == collection_id
803
+ ]
804
+
805
+ self.logger.info(
806
+ f"Found {len(collection_agents)} agents in collection '{collection_id}'"
807
+ )
808
+
809
+ return collection_agents
810
+
811
+ def list_collections(self) -> List[Dict[str, Any]]:
812
+ """List all available collections with agent counts.
813
+
814
+ Returns:
815
+ List of collection info dictionaries with:
816
+ - collection_id: Collection identifier
817
+ - agent_count: Number of agents in collection
818
+ - agents: List of agent IDs in collection
819
+
820
+ Example:
821
+ >>> service = RemoteAgentDiscoveryService(Path("~/.claude-mpm/cache/agents"))
822
+ >>> collections = service.list_collections()
823
+ >>> collections
824
+ [
825
+ {
826
+ "collection_id": "bobmatnyc/claude-mpm-agents",
827
+ "agent_count": 45,
828
+ "agents": ["pm", "engineer", "qa", ...]
829
+ }
830
+ ]
831
+ """
832
+ all_agents = self.discover_remote_agents()
833
+
834
+ # Group by collection_id
835
+ collections_map: Dict[str, List[str]] = {}
836
+
837
+ for agent in all_agents:
838
+ collection_id = agent.get("collection_id")
839
+ if not collection_id:
840
+ # Skip agents without collection (legacy)
841
+ continue
842
+
843
+ if collection_id not in collections_map:
844
+ collections_map[collection_id] = []
845
+
846
+ agent_id = agent.get("agent_id", agent.get("metadata", {}).get("name"))
847
+ if agent_id:
848
+ collections_map[collection_id].append(agent_id)
849
+
850
+ # Convert to list format
851
+ collections = [
852
+ {
853
+ "collection_id": coll_id,
854
+ "agent_count": len(agent_ids),
855
+ "agents": sorted(agent_ids),
856
+ }
857
+ for coll_id, agent_ids in collections_map.items()
858
+ ]
859
+
860
+ self.logger.info(f"Found {len(collections)} collections")
861
+
862
+ return collections