claude-mpm 3.4.10__py3-none-any.whl → 5.4.85__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1062) hide show
  1. claude_mpm/BUILD_NUMBER +1 -0
  2. claude_mpm/VERSION +1 -0
  3. claude_mpm/__init__.py +50 -12
  4. claude_mpm/__main__.py +7 -2
  5. claude_mpm/agents/BASE_AGENT.md +164 -0
  6. claude_mpm/agents/BASE_ENGINEER.md +658 -0
  7. claude_mpm/agents/CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md +405 -0
  8. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +112 -0
  9. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +186 -0
  10. claude_mpm/agents/MEMORY.md +72 -0
  11. claude_mpm/agents/PM_INSTRUCTIONS.md +1429 -0
  12. claude_mpm/agents/WORKFLOW.md +111 -0
  13. claude_mpm/agents/__init__.py +92 -80
  14. claude_mpm/agents/agent-template.yaml +83 -0
  15. claude_mpm/agents/agent_loader.py +560 -745
  16. claude_mpm/agents/agent_loader_integration.py +53 -55
  17. claude_mpm/agents/agents_metadata.py +186 -27
  18. claude_mpm/agents/async_agent_loader.py +436 -0
  19. claude_mpm/agents/base_agent.json +8 -4
  20. claude_mpm/agents/frontmatter_validator.py +754 -0
  21. claude_mpm/agents/system_agent_config.py +222 -155
  22. claude_mpm/agents/templates/README.md +465 -0
  23. claude_mpm/agents/templates/__init__.py +17 -13
  24. claude_mpm/agents/templates/circuit-breakers.md +1391 -0
  25. claude_mpm/agents/templates/context-management-examples.md +544 -0
  26. claude_mpm/agents/templates/git-file-tracking.md +584 -0
  27. claude_mpm/agents/templates/pm-examples.md +474 -0
  28. claude_mpm/agents/templates/pm-red-flags.md +310 -0
  29. claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
  30. claude_mpm/agents/templates/research-gate-examples.md +669 -0
  31. claude_mpm/agents/templates/response-format.md +583 -0
  32. claude_mpm/agents/templates/structured-questions-examples.md +615 -0
  33. claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
  34. claude_mpm/agents/templates/ticketing-examples.md +277 -0
  35. claude_mpm/agents/templates/validation-templates.md +312 -0
  36. claude_mpm/cli/__init__.py +94 -128
  37. claude_mpm/cli/__main__.py +33 -0
  38. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  39. claude_mpm/cli/commands/__init__.py +36 -12
  40. claude_mpm/cli/commands/agent_manager.py +1403 -0
  41. claude_mpm/cli/commands/agent_source.py +774 -0
  42. claude_mpm/cli/commands/agent_state_manager.py +335 -0
  43. claude_mpm/cli/commands/agents.py +2501 -168
  44. claude_mpm/cli/commands/agents_cleanup.py +210 -0
  45. claude_mpm/cli/commands/agents_discover.py +338 -0
  46. claude_mpm/cli/commands/agents_reconcile.py +197 -0
  47. claude_mpm/cli/commands/aggregate.py +540 -0
  48. claude_mpm/cli/commands/analyze.py +553 -0
  49. claude_mpm/cli/commands/analyze_code.py +528 -0
  50. claude_mpm/cli/commands/auto_configure.py +1053 -0
  51. claude_mpm/cli/commands/cleanup.py +588 -0
  52. claude_mpm/cli/commands/cleanup_orphaned_agents.py +150 -0
  53. claude_mpm/cli/commands/config.py +586 -0
  54. claude_mpm/cli/commands/configure.py +3253 -0
  55. claude_mpm/cli/commands/configure_agent_display.py +282 -0
  56. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  57. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  58. claude_mpm/cli/commands/configure_models.py +18 -0
  59. claude_mpm/cli/commands/configure_navigation.py +184 -0
  60. claude_mpm/cli/commands/configure_paths.py +104 -0
  61. claude_mpm/cli/commands/configure_persistence.py +254 -0
  62. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  63. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  64. claude_mpm/cli/commands/configure_validators.py +73 -0
  65. claude_mpm/cli/commands/dashboard.py +286 -0
  66. claude_mpm/cli/commands/debug.py +1386 -0
  67. claude_mpm/cli/commands/doctor.py +243 -0
  68. claude_mpm/cli/commands/hook_errors.py +277 -0
  69. claude_mpm/cli/commands/info.py +195 -74
  70. claude_mpm/cli/commands/local_deploy.py +534 -0
  71. claude_mpm/cli/commands/mcp.py +205 -0
  72. claude_mpm/cli/commands/mcp_command_router.py +161 -0
  73. claude_mpm/cli/commands/mcp_config.py +154 -0
  74. claude_mpm/cli/commands/mcp_config_commands.py +20 -0
  75. claude_mpm/cli/commands/mcp_external_commands.py +249 -0
  76. claude_mpm/cli/commands/mcp_install_commands.py +346 -0
  77. claude_mpm/cli/commands/mcp_pipx_config.py +208 -0
  78. claude_mpm/cli/commands/mcp_server_commands.py +155 -0
  79. claude_mpm/cli/commands/mcp_setup_external.py +868 -0
  80. claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
  81. claude_mpm/cli/commands/memory.py +585 -846
  82. claude_mpm/cli/commands/monitor.py +228 -310
  83. claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
  84. claude_mpm/cli/commands/mpm_init/core.py +759 -0
  85. claude_mpm/cli/commands/mpm_init/display.py +341 -0
  86. claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
  87. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  88. claude_mpm/cli/commands/mpm_init/modes.py +397 -0
  89. claude_mpm/cli/commands/mpm_init/prompts.py +722 -0
  90. claude_mpm/cli/commands/mpm_init_cli.py +396 -0
  91. claude_mpm/cli/commands/mpm_init_handler.py +195 -0
  92. claude_mpm/cli/commands/postmortem.py +401 -0
  93. claude_mpm/cli/commands/profile.py +276 -0
  94. claude_mpm/cli/commands/run.py +910 -488
  95. claude_mpm/cli/commands/search.py +458 -0
  96. claude_mpm/cli/commands/skill_source.py +694 -0
  97. claude_mpm/cli/commands/skills.py +1398 -0
  98. claude_mpm/cli/commands/summarize.py +413 -0
  99. claude_mpm/cli/commands/tickets.py +536 -53
  100. claude_mpm/cli/commands/uninstall.py +176 -0
  101. claude_mpm/cli/commands/upgrade.py +152 -0
  102. claude_mpm/cli/commands/verify.py +119 -0
  103. claude_mpm/cli/executor.py +298 -0
  104. claude_mpm/cli/helpers.py +105 -0
  105. claude_mpm/cli/interactive/__init__.py +31 -0
  106. claude_mpm/cli/interactive/agent_wizard.py +1927 -0
  107. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  108. claude_mpm/cli/interactive/skill_selector.py +481 -0
  109. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  110. claude_mpm/cli/parser.py +87 -563
  111. claude_mpm/cli/parsers/__init__.py +35 -0
  112. claude_mpm/cli/parsers/agent_manager_parser.py +393 -0
  113. claude_mpm/cli/parsers/agent_source_parser.py +171 -0
  114. claude_mpm/cli/parsers/agents_parser.py +575 -0
  115. claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
  116. claude_mpm/cli/parsers/analyze_parser.py +135 -0
  117. claude_mpm/cli/parsers/auto_configure_parser.py +120 -0
  118. claude_mpm/cli/parsers/base_parser.py +649 -0
  119. claude_mpm/cli/parsers/config_parser.py +208 -0
  120. claude_mpm/cli/parsers/configure_parser.py +138 -0
  121. claude_mpm/cli/parsers/dashboard_parser.py +113 -0
  122. claude_mpm/cli/parsers/debug_parser.py +319 -0
  123. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  124. claude_mpm/cli/parsers/mcp_parser.py +195 -0
  125. claude_mpm/cli/parsers/memory_parser.py +138 -0
  126. claude_mpm/cli/parsers/monitor_parser.py +142 -0
  127. claude_mpm/cli/parsers/mpm_init_parser.py +311 -0
  128. claude_mpm/cli/parsers/profile_parser.py +147 -0
  129. claude_mpm/cli/parsers/run_parser.py +157 -0
  130. claude_mpm/cli/parsers/search_parser.py +245 -0
  131. claude_mpm/cli/parsers/skill_source_parser.py +169 -0
  132. claude_mpm/cli/parsers/skills_parser.py +277 -0
  133. claude_mpm/cli/parsers/source_parser.py +138 -0
  134. claude_mpm/cli/parsers/tickets_parser.py +203 -0
  135. claude_mpm/cli/shared/__init__.py +40 -0
  136. claude_mpm/cli/shared/argument_patterns.py +205 -0
  137. claude_mpm/cli/shared/base_command.py +242 -0
  138. claude_mpm/cli/shared/error_handling.py +242 -0
  139. claude_mpm/cli/shared/output_formatters.py +241 -0
  140. claude_mpm/cli/startup.py +1578 -0
  141. claude_mpm/cli/startup_display.py +480 -0
  142. claude_mpm/cli/startup_logging.py +839 -0
  143. claude_mpm/cli/utils.py +136 -47
  144. claude_mpm/cli_module/__init__.py +6 -6
  145. claude_mpm/cli_module/args.py +188 -140
  146. claude_mpm/cli_module/commands.py +79 -70
  147. claude_mpm/cli_module/migration_example.py +42 -64
  148. claude_mpm/commands/__init__.py +14 -0
  149. claude_mpm/commands/mpm-config.md +28 -0
  150. claude_mpm/commands/mpm-doctor.md +20 -0
  151. claude_mpm/commands/mpm-help.md +20 -0
  152. claude_mpm/commands/mpm-init.md +120 -0
  153. claude_mpm/commands/mpm-monitor.md +31 -0
  154. claude_mpm/commands/mpm-organize.md +120 -0
  155. claude_mpm/commands/mpm-postmortem.md +21 -0
  156. claude_mpm/commands/mpm-session-resume.md +30 -0
  157. claude_mpm/commands/mpm-status.md +20 -0
  158. claude_mpm/commands/mpm-ticket-view.md +109 -0
  159. claude_mpm/commands/mpm-version.md +20 -0
  160. claude_mpm/commands/mpm.md +31 -0
  161. claude_mpm/config/__init__.py +42 -2
  162. claude_mpm/config/agent_config.py +402 -0
  163. claude_mpm/config/agent_presets.py +488 -0
  164. claude_mpm/config/agent_sources.py +352 -0
  165. claude_mpm/config/experimental_features.py +217 -0
  166. claude_mpm/config/model_config.py +428 -0
  167. claude_mpm/config/paths.py +258 -0
  168. claude_mpm/config/skill_presets.py +392 -0
  169. claude_mpm/config/skill_sources.py +590 -0
  170. claude_mpm/config/socketio_config.py +125 -83
  171. claude_mpm/constants.py +133 -22
  172. claude_mpm/core/__init__.py +62 -36
  173. claude_mpm/core/agent_name_normalizer.py +71 -73
  174. claude_mpm/core/agent_registry.py +385 -492
  175. claude_mpm/core/agent_session_manager.py +81 -70
  176. claude_mpm/core/api_validator.py +330 -0
  177. claude_mpm/core/base_service.py +159 -122
  178. claude_mpm/core/cache.py +560 -0
  179. claude_mpm/core/claude_runner.py +696 -916
  180. claude_mpm/core/config.py +613 -122
  181. claude_mpm/core/config_aliases.py +74 -73
  182. claude_mpm/core/config_constants.py +314 -0
  183. claude_mpm/core/constants.py +361 -0
  184. claude_mpm/core/container.py +646 -104
  185. claude_mpm/core/enums.py +452 -0
  186. claude_mpm/core/error_handler.py +623 -0
  187. claude_mpm/core/exceptions.py +536 -0
  188. claude_mpm/core/factories.py +105 -109
  189. claude_mpm/core/file_utils.py +764 -0
  190. claude_mpm/core/framework/__init__.py +25 -0
  191. claude_mpm/core/framework/formatters/__init__.py +11 -0
  192. claude_mpm/core/framework/formatters/capability_generator.py +367 -0
  193. claude_mpm/core/framework/formatters/content_formatter.py +278 -0
  194. claude_mpm/core/framework/formatters/context_generator.py +185 -0
  195. claude_mpm/core/framework/loaders/__init__.py +13 -0
  196. claude_mpm/core/framework/loaders/agent_loader.py +213 -0
  197. claude_mpm/core/framework/loaders/file_loader.py +176 -0
  198. claude_mpm/core/framework/loaders/instruction_loader.py +222 -0
  199. claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
  200. claude_mpm/core/framework/processors/__init__.py +11 -0
  201. claude_mpm/core/framework/processors/memory_processor.py +230 -0
  202. claude_mpm/core/framework/processors/metadata_processor.py +146 -0
  203. claude_mpm/core/framework/processors/template_processor.py +244 -0
  204. claude_mpm/core/framework_loader.py +485 -414
  205. claude_mpm/core/hook_error_memory.py +381 -0
  206. claude_mpm/core/hook_manager.py +246 -86
  207. claude_mpm/core/hook_performance_config.py +147 -0
  208. claude_mpm/core/injectable_service.py +72 -63
  209. claude_mpm/core/instruction_reinforcement_hook.py +267 -0
  210. claude_mpm/core/interactive_session.py +670 -0
  211. claude_mpm/core/interfaces.py +570 -164
  212. claude_mpm/core/lazy.py +467 -0
  213. claude_mpm/core/log_manager.py +707 -0
  214. claude_mpm/core/logger.py +295 -134
  215. claude_mpm/core/logging_config.py +474 -0
  216. claude_mpm/core/logging_utils.py +520 -0
  217. claude_mpm/core/minimal_framework_loader.py +24 -22
  218. claude_mpm/core/mixins.py +30 -29
  219. claude_mpm/core/oneshot_session.py +594 -0
  220. claude_mpm/core/optimized_agent_loader.py +479 -0
  221. claude_mpm/core/optimized_startup.py +554 -0
  222. claude_mpm/core/output_style_manager.py +491 -0
  223. claude_mpm/core/pm_hook_interceptor.py +197 -82
  224. claude_mpm/core/protocols/__init__.py +23 -0
  225. claude_mpm/core/protocols/runner_protocol.py +103 -0
  226. claude_mpm/core/protocols/session_protocol.py +131 -0
  227. claude_mpm/core/service_registry.py +153 -116
  228. claude_mpm/core/session_manager.py +179 -64
  229. claude_mpm/core/shared/__init__.py +17 -0
  230. claude_mpm/core/shared/config_loader.py +326 -0
  231. claude_mpm/core/shared/path_resolver.py +281 -0
  232. claude_mpm/core/shared/singleton_manager.py +221 -0
  233. claude_mpm/core/socketio_pool.py +400 -137
  234. claude_mpm/core/system_context.py +38 -0
  235. claude_mpm/core/tool_access_control.py +64 -57
  236. claude_mpm/core/types.py +307 -0
  237. claude_mpm/core/typing_utils.py +553 -0
  238. claude_mpm/core/unified_agent_registry.py +969 -0
  239. claude_mpm/core/unified_config.py +612 -0
  240. claude_mpm/core/unified_paths.py +958 -0
  241. claude_mpm/dashboard/__init__.py +12 -0
  242. claude_mpm/dashboard/api/simple_directory.py +261 -0
  243. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  244. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +1 -0
  245. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +1 -0
  246. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +1 -0
  247. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +24 -0
  248. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B0uc0UOD.js +36 -0
  249. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7RN905-.js +1 -0
  250. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7xVLGWV.js +2 -0
  251. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BIF9m_hv.js +61 -0
  252. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +1 -0
  253. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BPYeabCQ.js +1 -0
  254. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  255. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
  256. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Be7GpZd6.js +7 -0
  257. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bh0LDWpI.js +145 -0
  258. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BofRWZRR.js +10 -0
  259. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BovzEFCE.js +30 -0
  260. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C30mlcqg.js +165 -0
  261. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4B-KCzX.js +1 -0
  262. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4JcI4KD.js +122 -0
  263. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CBBdVcY8.js +1 -0
  264. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CDuw-vjf.js +1 -0
  265. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C_Usid8X.js +15 -0
  266. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cfqx1Qun.js +10 -0
  267. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CiIAseT4.js +128 -0
  268. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  269. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CnA0NrzZ.js +1 -0
  270. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cs_tUR18.js +24 -0
  271. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  272. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CyWMqx4W.js +43 -0
  273. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzZX-COe.js +220 -0
  274. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzeYkLYB.js +65 -0
  275. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D3k0OPJN.js +4 -0
  276. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9lljYKQ.js +1 -0
  277. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DGkLK5U1.js +267 -0
  278. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DI7hHRFL.js +1 -0
  279. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DLVjFsZ3.js +139 -0
  280. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUrLdbGD.js +89 -0
  281. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  282. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DY1XQ8fi.js +2 -0
  283. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DZX00Y4g.js +1 -0
  284. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +1 -0
  285. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DaimHw_p.js +68 -0
  286. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +323 -0
  287. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dhb8PKl3.js +1 -0
  288. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dle-35c7.js +64 -0
  289. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DmxopI1J.js +1 -0
  290. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DwBR2MJi.js +60 -0
  291. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/GYwsonyD.js +1 -0
  292. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  293. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
  294. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/RJiighC3.js +1 -0
  295. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Vzk33B_K.js +2 -0
  296. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ZGh7QtNv.js +7 -0
  297. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bT1r9zLR.js +1 -0
  298. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bTOqqlTd.js +1 -0
  299. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/eNVUfhuA.js +1 -0
  300. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/iEWssX7S.js +162 -0
  301. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/sQeU3Y1z.js +1 -0
  302. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uuIeMWc-.js +1 -0
  303. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.D6-I5TpK.js +2 -0
  304. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +1 -0
  305. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.m1gL8KXf.js +1 -0
  306. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.CgNOuw-d.js +1 -0
  307. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +1 -0
  308. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  309. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  310. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  311. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  312. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  313. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  314. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  315. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  316. claude_mpm/experimental/__init__.py +10 -0
  317. claude_mpm/experimental/cli_enhancements.py +104 -89
  318. claude_mpm/generators/__init__.py +1 -1
  319. claude_mpm/generators/agent_profile_generator.py +76 -66
  320. claude_mpm/hooks/__init__.py +37 -1
  321. claude_mpm/hooks/base_hook.py +37 -32
  322. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  323. claude_mpm/hooks/claude_hooks/connection_pool.py +250 -0
  324. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  325. claude_mpm/hooks/claude_hooks/event_handlers.py +888 -0
  326. claude_mpm/hooks/claude_hooks/hook_handler.py +652 -875
  327. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +10 -7
  328. claude_mpm/hooks/claude_hooks/installer.py +806 -0
  329. claude_mpm/hooks/claude_hooks/memory_integration.py +249 -0
  330. claude_mpm/hooks/claude_hooks/response_tracking.py +412 -0
  331. claude_mpm/hooks/claude_hooks/services/__init__.py +15 -0
  332. claude_mpm/hooks/claude_hooks/services/connection_manager.py +229 -0
  333. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +254 -0
  334. claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
  335. claude_mpm/hooks/claude_hooks/services/state_manager.py +284 -0
  336. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
  337. claude_mpm/hooks/claude_hooks/tool_analysis.py +224 -0
  338. claude_mpm/hooks/failure_learning/__init__.py +54 -0
  339. claude_mpm/hooks/failure_learning/failure_detection_hook.py +230 -0
  340. claude_mpm/hooks/failure_learning/fix_detection_hook.py +212 -0
  341. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +281 -0
  342. claude_mpm/hooks/instruction_reinforcement.py +301 -0
  343. claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
  344. claude_mpm/hooks/kuzu_memory_hook.py +386 -0
  345. claude_mpm/hooks/kuzu_response_hook.py +179 -0
  346. claude_mpm/hooks/memory_integration_hook.py +201 -107
  347. claude_mpm/hooks/session_resume_hook.py +121 -0
  348. claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
  349. claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
  350. claude_mpm/hooks/tool_call_interceptor.py +92 -76
  351. claude_mpm/hooks/validation_hooks.py +62 -54
  352. claude_mpm/init.py +518 -83
  353. claude_mpm/models/__init__.py +9 -9
  354. claude_mpm/models/agent_definition.py +40 -23
  355. claude_mpm/models/agent_session.py +538 -0
  356. claude_mpm/models/git_repository.py +198 -0
  357. claude_mpm/models/resume_log.py +340 -0
  358. claude_mpm/schemas/__init__.py +12 -0
  359. claude_mpm/scripts/__init__.py +15 -0
  360. claude_mpm/scripts/claude-hook-handler.sh +227 -0
  361. claude_mpm/scripts/launch_monitor.py +165 -0
  362. claude_mpm/scripts/mpm_doctor.py +322 -0
  363. claude_mpm/scripts/socketio_daemon.py +189 -200
  364. claude_mpm/scripts/start_activity_logging.py +91 -0
  365. claude_mpm/services/__init__.py +208 -39
  366. claude_mpm/services/agent_capabilities_service.py +266 -0
  367. claude_mpm/services/agents/__init__.py +89 -0
  368. claude_mpm/services/agents/agent_builder.py +514 -0
  369. claude_mpm/services/agents/agent_preset_service.py +238 -0
  370. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  371. claude_mpm/services/agents/agent_review_service.py +280 -0
  372. claude_mpm/services/agents/agent_selection_service.py +484 -0
  373. claude_mpm/services/agents/auto_config_manager.py +796 -0
  374. claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
  375. claude_mpm/services/agents/cache_git_manager.py +621 -0
  376. claude_mpm/services/agents/deployment/__init__.py +21 -0
  377. claude_mpm/services/agents/deployment/agent_config_provider.py +410 -0
  378. claude_mpm/services/agents/deployment/agent_configuration_manager.py +358 -0
  379. claude_mpm/services/agents/deployment/agent_definition_factory.py +80 -0
  380. claude_mpm/services/agents/deployment/agent_deployment.py +1037 -0
  381. claude_mpm/services/agents/deployment/agent_discovery_service.py +546 -0
  382. claude_mpm/services/agents/deployment/agent_environment_manager.py +288 -0
  383. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +383 -0
  384. claude_mpm/services/agents/deployment/agent_format_converter.py +505 -0
  385. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +160 -0
  386. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +957 -0
  387. claude_mpm/services/agents/deployment/agent_metrics_collector.py +273 -0
  388. claude_mpm/services/agents/deployment/agent_operation_service.py +573 -0
  389. claude_mpm/services/agents/deployment/agent_record_service.py +418 -0
  390. claude_mpm/services/agents/deployment/agent_restore_handler.py +84 -0
  391. claude_mpm/services/agents/deployment/agent_state_service.py +381 -0
  392. claude_mpm/services/agents/deployment/agent_template_builder.py +1377 -0
  393. claude_mpm/services/agents/deployment/agent_validator.py +376 -0
  394. claude_mpm/services/agents/deployment/agent_version_manager.py +322 -0
  395. claude_mpm/services/{agent_versioning.py → agents/deployment/agent_versioning.py} +10 -13
  396. claude_mpm/services/agents/deployment/agents_directory_resolver.py +149 -0
  397. claude_mpm/services/agents/deployment/async_agent_deployment.py +768 -0
  398. claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
  399. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  400. claude_mpm/services/agents/deployment/config/deployment_config.py +181 -0
  401. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  402. claude_mpm/services/agents/deployment/deployment_config_loader.py +178 -0
  403. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  404. claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
  405. claude_mpm/services/agents/deployment/deployment_type_detector.py +120 -0
  406. claude_mpm/services/agents/deployment/deployment_wrapper.py +129 -0
  407. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  408. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  409. claude_mpm/services/agents/deployment/facade/deployment_executor.py +70 -0
  410. claude_mpm/services/agents/deployment/facade/deployment_facade.py +269 -0
  411. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  412. claude_mpm/services/agents/deployment/interface_adapter.py +226 -0
  413. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  414. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  415. claude_mpm/services/agents/deployment/local_template_deployment.py +362 -0
  416. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +1478 -0
  417. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  418. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  419. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +162 -0
  420. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  421. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  422. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +240 -0
  423. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +110 -0
  424. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +80 -0
  425. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +92 -0
  426. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +101 -0
  427. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  428. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +102 -0
  429. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  430. claude_mpm/services/agents/deployment/processors/agent_processor.py +269 -0
  431. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +311 -0
  432. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +862 -0
  433. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  434. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  435. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  436. claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
  437. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  438. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  439. claude_mpm/services/agents/deployment/strategies/base_strategy.py +113 -0
  440. claude_mpm/services/agents/deployment/strategies/project_strategy.py +148 -0
  441. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  442. claude_mpm/services/agents/deployment/strategies/system_strategy.py +131 -0
  443. claude_mpm/services/agents/deployment/strategies/user_strategy.py +130 -0
  444. claude_mpm/services/agents/deployment/system_instructions_deployer.py +228 -0
  445. claude_mpm/services/agents/deployment/validation/__init__.py +21 -0
  446. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  447. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  448. claude_mpm/services/agents/deployment/validation/template_validator.py +319 -0
  449. claude_mpm/services/agents/deployment/validation/validation_result.py +214 -0
  450. claude_mpm/services/agents/git_source_manager.py +682 -0
  451. claude_mpm/services/agents/loading/__init__.py +11 -0
  452. claude_mpm/services/{agent_profile_loader.py → agents/loading/agent_profile_loader.py} +306 -228
  453. claude_mpm/services/{base_agent_manager.py → agents/loading/base_agent_manager.py} +106 -91
  454. claude_mpm/services/agents/loading/framework_agent_loader.py +433 -0
  455. claude_mpm/services/agents/local_template_manager.py +784 -0
  456. claude_mpm/services/agents/management/__init__.py +9 -0
  457. claude_mpm/services/{agent_capabilities_generator.py → agents/management/agent_capabilities_generator.py} +92 -69
  458. claude_mpm/services/{agent_management_service.py → agents/management/agent_management_service.py} +219 -168
  459. claude_mpm/services/agents/memory/__init__.py +22 -0
  460. claude_mpm/services/agents/memory/agent_memory_manager.py +784 -0
  461. claude_mpm/services/{agent_persistence_service.py → agents/memory/agent_persistence_service.py} +20 -18
  462. claude_mpm/services/agents/memory/content_manager.py +470 -0
  463. claude_mpm/services/agents/memory/memory_categorization_service.py +167 -0
  464. claude_mpm/services/agents/memory/memory_file_service.py +129 -0
  465. claude_mpm/services/agents/memory/memory_format_service.py +201 -0
  466. claude_mpm/services/agents/memory/memory_limits_service.py +101 -0
  467. claude_mpm/services/agents/memory/template_generator.py +83 -0
  468. claude_mpm/services/agents/observers.py +547 -0
  469. claude_mpm/services/agents/recommender.py +617 -0
  470. claude_mpm/services/agents/registry/__init__.py +30 -0
  471. claude_mpm/services/agents/registry/deployed_agent_discovery.py +273 -0
  472. claude_mpm/services/{agent_modification_tracker.py → agents/registry/modification_tracker.py} +370 -295
  473. claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
  474. claude_mpm/services/agents/sources/__init__.py +13 -0
  475. claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
  476. claude_mpm/services/agents/sources/git_source_sync_service.py +1205 -0
  477. claude_mpm/services/agents/startup_sync.py +262 -0
  478. claude_mpm/services/agents/toolchain_detector.py +478 -0
  479. claude_mpm/services/analysis/__init__.py +35 -0
  480. claude_mpm/services/analysis/clone_detector.py +1030 -0
  481. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  482. claude_mpm/services/analysis/postmortem_service.py +765 -0
  483. claude_mpm/services/async_session_logger.py +665 -0
  484. claude_mpm/services/claude_session_logger.py +321 -0
  485. claude_mpm/services/cli/__init__.py +18 -0
  486. claude_mpm/services/cli/agent_cleanup_service.py +408 -0
  487. claude_mpm/services/cli/agent_dependency_service.py +395 -0
  488. claude_mpm/services/cli/agent_listing_service.py +463 -0
  489. claude_mpm/services/cli/agent_output_formatter.py +605 -0
  490. claude_mpm/services/cli/agent_validation_service.py +590 -0
  491. claude_mpm/services/cli/memory_crud_service.py +622 -0
  492. claude_mpm/services/cli/memory_output_formatter.py +604 -0
  493. claude_mpm/services/cli/resume_service.py +617 -0
  494. claude_mpm/services/cli/session_manager.py +604 -0
  495. claude_mpm/services/cli/session_pause_manager.py +504 -0
  496. claude_mpm/services/cli/session_resume_helper.py +372 -0
  497. claude_mpm/services/cli/startup_checker.py +362 -0
  498. claude_mpm/services/cli/unified_dashboard_manager.py +439 -0
  499. claude_mpm/services/command_deployment_service.py +446 -0
  500. claude_mpm/services/command_handler_service.py +221 -0
  501. claude_mpm/services/communication/__init__.py +22 -0
  502. claude_mpm/services/core/__init__.py +108 -0
  503. claude_mpm/services/core/base.py +269 -0
  504. claude_mpm/services/core/cache_manager.py +309 -0
  505. claude_mpm/services/core/interfaces/__init__.py +273 -0
  506. claude_mpm/services/core/interfaces/agent.py +514 -0
  507. claude_mpm/services/core/interfaces/communication.py +316 -0
  508. claude_mpm/services/core/interfaces/health.py +169 -0
  509. claude_mpm/services/core/interfaces/infrastructure.py +357 -0
  510. claude_mpm/services/core/interfaces/model.py +281 -0
  511. claude_mpm/services/core/interfaces/process.py +372 -0
  512. claude_mpm/services/core/interfaces/project.py +121 -0
  513. claude_mpm/services/core/interfaces/restart.py +307 -0
  514. claude_mpm/services/core/interfaces/service.py +405 -0
  515. claude_mpm/services/core/interfaces/stability.py +260 -0
  516. claude_mpm/services/core/interfaces.py +81 -0
  517. claude_mpm/services/core/memory_manager.py +682 -0
  518. claude_mpm/services/core/models/__init__.py +70 -0
  519. claude_mpm/services/core/models/agent_config.py +384 -0
  520. claude_mpm/services/core/models/health.py +162 -0
  521. claude_mpm/services/core/models/process.py +239 -0
  522. claude_mpm/services/core/models/restart.py +302 -0
  523. claude_mpm/services/core/models/stability.py +264 -0
  524. claude_mpm/services/core/models/toolchain.py +306 -0
  525. claude_mpm/services/core/path_resolver.py +517 -0
  526. claude_mpm/services/core/service_container.py +520 -0
  527. claude_mpm/services/core/service_interfaces.py +436 -0
  528. claude_mpm/services/diagnostics/__init__.py +18 -0
  529. claude_mpm/services/diagnostics/checks/__init__.py +38 -0
  530. claude_mpm/services/diagnostics/checks/agent_check.py +370 -0
  531. claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
  532. claude_mpm/services/diagnostics/checks/base_check.py +60 -0
  533. claude_mpm/services/diagnostics/checks/claude_code_check.py +270 -0
  534. claude_mpm/services/diagnostics/checks/common_issues_check.py +363 -0
  535. claude_mpm/services/diagnostics/checks/configuration_check.py +306 -0
  536. claude_mpm/services/diagnostics/checks/filesystem_check.py +233 -0
  537. claude_mpm/services/diagnostics/checks/installation_check.py +520 -0
  538. claude_mpm/services/diagnostics/checks/instructions_check.py +415 -0
  539. claude_mpm/services/diagnostics/checks/mcp_check.py +330 -0
  540. claude_mpm/services/diagnostics/checks/mcp_services_check.py +1058 -0
  541. claude_mpm/services/diagnostics/checks/monitor_check.py +281 -0
  542. claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
  543. claude_mpm/services/diagnostics/checks/startup_log_check.py +319 -0
  544. claude_mpm/services/diagnostics/diagnostic_runner.py +286 -0
  545. claude_mpm/services/diagnostics/doctor_reporter.py +578 -0
  546. claude_mpm/services/diagnostics/models.py +138 -0
  547. claude_mpm/services/event_aggregator.py +582 -0
  548. claude_mpm/services/event_bus/__init__.py +18 -0
  549. claude_mpm/services/event_bus/config.py +186 -0
  550. claude_mpm/services/event_bus/direct_relay.py +312 -0
  551. claude_mpm/services/event_bus/event_bus.py +396 -0
  552. claude_mpm/services/event_bus/relay.py +326 -0
  553. claude_mpm/services/events/__init__.py +44 -0
  554. claude_mpm/services/events/consumers/__init__.py +18 -0
  555. claude_mpm/services/events/consumers/dead_letter.py +306 -0
  556. claude_mpm/services/events/consumers/logging.py +184 -0
  557. claude_mpm/services/events/consumers/metrics.py +241 -0
  558. claude_mpm/services/events/consumers/socketio.py +377 -0
  559. claude_mpm/services/events/core.py +480 -0
  560. claude_mpm/services/events/interfaces.py +214 -0
  561. claude_mpm/services/events/producers/__init__.py +14 -0
  562. claude_mpm/services/events/producers/hook.py +269 -0
  563. claude_mpm/services/events/producers/system.py +329 -0
  564. claude_mpm/services/exceptions.py +433 -353
  565. claude_mpm/services/framework_claude_md_generator/__init__.py +81 -80
  566. claude_mpm/services/framework_claude_md_generator/content_assembler.py +74 -67
  567. claude_mpm/services/framework_claude_md_generator/content_validator.py +66 -62
  568. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +82 -60
  569. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +36 -37
  570. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +41 -40
  571. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +15 -15
  572. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +5 -4
  573. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  574. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  575. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  576. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  577. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +5 -4
  578. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  579. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  580. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +26 -30
  581. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +6 -5
  582. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  583. claude_mpm/services/framework_claude_md_generator/version_manager.py +31 -30
  584. claude_mpm/services/git/__init__.py +21 -0
  585. claude_mpm/services/git/git_operations_service.py +579 -0
  586. claude_mpm/services/github/__init__.py +21 -0
  587. claude_mpm/services/github/github_cli_service.py +397 -0
  588. claude_mpm/services/hook_installer_service.py +506 -0
  589. claude_mpm/services/hook_service.py +159 -111
  590. claude_mpm/services/infrastructure/__init__.py +52 -0
  591. claude_mpm/services/infrastructure/context_preservation.py +569 -0
  592. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  593. claude_mpm/services/infrastructure/logging.py +209 -0
  594. claude_mpm/services/infrastructure/monitoring/__init__.py +39 -0
  595. claude_mpm/services/infrastructure/monitoring/aggregator.py +432 -0
  596. claude_mpm/services/infrastructure/monitoring/base.py +122 -0
  597. claude_mpm/services/infrastructure/monitoring/legacy.py +203 -0
  598. claude_mpm/services/infrastructure/monitoring/network.py +219 -0
  599. claude_mpm/services/infrastructure/monitoring/process.py +343 -0
  600. claude_mpm/services/infrastructure/monitoring/resources.py +244 -0
  601. claude_mpm/services/infrastructure/monitoring/service.py +368 -0
  602. claude_mpm/services/infrastructure/monitoring.py +71 -0
  603. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  604. claude_mpm/services/instructions/__init__.py +9 -0
  605. claude_mpm/services/instructions/instruction_cache_service.py +374 -0
  606. claude_mpm/services/local_ops/__init__.py +155 -0
  607. claude_mpm/services/local_ops/crash_detector.py +257 -0
  608. claude_mpm/services/local_ops/health_checks/__init__.py +26 -0
  609. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  610. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  611. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  612. claude_mpm/services/local_ops/health_manager.py +427 -0
  613. claude_mpm/services/local_ops/log_monitor.py +396 -0
  614. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  615. claude_mpm/services/local_ops/process_manager.py +595 -0
  616. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  617. claude_mpm/services/local_ops/restart_manager.py +401 -0
  618. claude_mpm/services/local_ops/restart_policy.py +387 -0
  619. claude_mpm/services/local_ops/state_manager.py +372 -0
  620. claude_mpm/services/local_ops/unified_manager.py +600 -0
  621. claude_mpm/services/mcp_config_manager.py +1542 -0
  622. claude_mpm/services/mcp_service_verifier.py +732 -0
  623. claude_mpm/services/memory/__init__.py +19 -0
  624. claude_mpm/services/{memory_builder.py → memory/builder.py} +465 -373
  625. claude_mpm/services/memory/cache/__init__.py +14 -0
  626. claude_mpm/services/{shared_prompt_cache.py → memory/cache/shared_prompt_cache.py} +237 -200
  627. claude_mpm/services/memory/cache/simple_cache.py +331 -0
  628. claude_mpm/services/memory/failure_tracker.py +578 -0
  629. claude_mpm/services/memory/indexed_memory.py +648 -0
  630. claude_mpm/services/{memory_optimizer.py → memory/optimizer.py} +272 -243
  631. claude_mpm/services/memory/router.py +951 -0
  632. claude_mpm/services/memory_hook_service.py +470 -0
  633. claude_mpm/services/model/__init__.py +147 -0
  634. claude_mpm/services/model/base_provider.py +365 -0
  635. claude_mpm/services/model/claude_provider.py +412 -0
  636. claude_mpm/services/model/model_router.py +452 -0
  637. claude_mpm/services/model/ollama_provider.py +415 -0
  638. claude_mpm/services/monitor/__init__.py +20 -0
  639. claude_mpm/services/monitor/daemon.py +698 -0
  640. claude_mpm/services/monitor/daemon_manager.py +1076 -0
  641. claude_mpm/services/monitor/event_emitter.py +350 -0
  642. claude_mpm/services/monitor/handlers/__init__.py +21 -0
  643. claude_mpm/services/monitor/handlers/code_analysis.py +332 -0
  644. claude_mpm/services/monitor/handlers/dashboard.py +299 -0
  645. claude_mpm/services/monitor/handlers/file.py +264 -0
  646. claude_mpm/services/monitor/handlers/hooks.py +512 -0
  647. claude_mpm/services/monitor/management/__init__.py +18 -0
  648. claude_mpm/services/monitor/management/health.py +124 -0
  649. claude_mpm/services/monitor/management/lifecycle.py +730 -0
  650. claude_mpm/services/monitor/server.py +1493 -0
  651. claude_mpm/services/monitor_build_service.py +349 -0
  652. claude_mpm/services/native_agent_converter.py +356 -0
  653. claude_mpm/services/orphan_detection.py +786 -0
  654. claude_mpm/services/pm_skills_deployer.py +711 -0
  655. claude_mpm/services/port_manager.py +597 -0
  656. claude_mpm/services/pr/__init__.py +14 -0
  657. claude_mpm/services/pr/pr_template_service.py +329 -0
  658. claude_mpm/services/profile_manager.py +337 -0
  659. claude_mpm/services/project/__init__.py +44 -0
  660. claude_mpm/services/{project_analyzer.py → project/analyzer.py} +541 -291
  661. claude_mpm/services/project/analyzer_v2.py +566 -0
  662. claude_mpm/services/project/architecture_analyzer.py +461 -0
  663. claude_mpm/services/project/archive_manager.py +1045 -0
  664. claude_mpm/services/project/dependency_analyzer.py +462 -0
  665. claude_mpm/services/project/detection_strategies.py +719 -0
  666. claude_mpm/services/project/documentation_manager.py +554 -0
  667. claude_mpm/services/project/enhanced_analyzer.py +572 -0
  668. claude_mpm/services/project/language_analyzer.py +265 -0
  669. claude_mpm/services/project/metrics_collector.py +407 -0
  670. claude_mpm/services/project/project_organizer.py +1009 -0
  671. claude_mpm/services/project/registry.py +636 -0
  672. claude_mpm/services/project/toolchain_analyzer.py +583 -0
  673. claude_mpm/services/project_port_allocator.py +596 -0
  674. claude_mpm/services/recovery_manager.py +293 -240
  675. claude_mpm/services/response_tracker.py +267 -0
  676. claude_mpm/services/runner_configuration_service.py +605 -0
  677. claude_mpm/services/self_upgrade_service.py +608 -0
  678. claude_mpm/services/session_management_service.py +314 -0
  679. claude_mpm/services/session_manager.py +380 -0
  680. claude_mpm/services/shared/__init__.py +21 -0
  681. claude_mpm/services/shared/async_service_base.py +216 -0
  682. claude_mpm/services/shared/config_service_base.py +301 -0
  683. claude_mpm/services/shared/lifecycle_service_base.py +308 -0
  684. claude_mpm/services/shared/manager_base.py +315 -0
  685. claude_mpm/services/shared/service_factory.py +309 -0
  686. claude_mpm/services/skills/__init__.py +21 -0
  687. claude_mpm/services/skills/git_skill_source_manager.py +1340 -0
  688. claude_mpm/services/skills/selective_skill_deployer.py +743 -0
  689. claude_mpm/services/skills/skill_discovery_service.py +568 -0
  690. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  691. claude_mpm/services/skills_config.py +547 -0
  692. claude_mpm/services/skills_deployer.py +1168 -0
  693. claude_mpm/services/socketio/__init__.py +25 -0
  694. claude_mpm/services/socketio/client_proxy.py +229 -0
  695. claude_mpm/services/socketio/dashboard_server.py +362 -0
  696. claude_mpm/services/socketio/event_normalizer.py +798 -0
  697. claude_mpm/services/socketio/handlers/__init__.py +30 -0
  698. claude_mpm/services/socketio/handlers/base.py +136 -0
  699. claude_mpm/services/socketio/handlers/code_analysis.py +682 -0
  700. claude_mpm/services/socketio/handlers/connection.py +643 -0
  701. claude_mpm/services/socketio/handlers/connection_handler.py +333 -0
  702. claude_mpm/services/socketio/handlers/file.py +263 -0
  703. claude_mpm/services/socketio/handlers/git.py +962 -0
  704. claude_mpm/services/socketio/handlers/hook.py +211 -0
  705. claude_mpm/services/socketio/handlers/memory.py +26 -0
  706. claude_mpm/services/socketio/handlers/project.py +24 -0
  707. claude_mpm/services/socketio/handlers/registry.py +214 -0
  708. claude_mpm/services/socketio/migration_utils.py +343 -0
  709. claude_mpm/services/socketio/monitor_client.py +364 -0
  710. claude_mpm/services/socketio/server/__init__.py +18 -0
  711. claude_mpm/services/socketio/server/broadcaster.py +569 -0
  712. claude_mpm/services/socketio/server/connection_manager.py +579 -0
  713. claude_mpm/services/socketio/server/core.py +1079 -0
  714. claude_mpm/services/socketio/server/eventbus_integration.py +245 -0
  715. claude_mpm/services/socketio/server/main.py +501 -0
  716. claude_mpm/services/socketio_client_manager.py +173 -143
  717. claude_mpm/services/socketio_server.py +38 -1657
  718. claude_mpm/services/subprocess_launcher_service.py +322 -0
  719. claude_mpm/services/system_instructions_service.py +270 -0
  720. claude_mpm/services/ticket_manager.py +25 -209
  721. claude_mpm/services/ticket_services/__init__.py +26 -0
  722. claude_mpm/services/ticket_services/crud_service.py +328 -0
  723. claude_mpm/services/ticket_services/formatter_service.py +290 -0
  724. claude_mpm/services/ticket_services/search_service.py +324 -0
  725. claude_mpm/services/ticket_services/validation_service.py +303 -0
  726. claude_mpm/services/ticket_services/workflow_service.py +244 -0
  727. claude_mpm/services/unified/__init__.py +65 -0
  728. claude_mpm/services/unified/analyzer_strategies/__init__.py +44 -0
  729. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +518 -0
  730. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +680 -0
  731. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +900 -0
  732. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +745 -0
  733. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +733 -0
  734. claude_mpm/services/unified/config_strategies/__init__.py +175 -0
  735. claude_mpm/services/unified/config_strategies/config_schema.py +731 -0
  736. claude_mpm/services/unified/config_strategies/context_strategy.py +747 -0
  737. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1005 -0
  738. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +881 -0
  739. claude_mpm/services/unified/config_strategies/unified_config_service.py +823 -0
  740. claude_mpm/services/unified/config_strategies/validation_strategy.py +1148 -0
  741. claude_mpm/services/unified/deployment_strategies/__init__.py +97 -0
  742. claude_mpm/services/unified/deployment_strategies/base.py +553 -0
  743. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +573 -0
  744. claude_mpm/services/unified/deployment_strategies/local.py +607 -0
  745. claude_mpm/services/unified/deployment_strategies/utils.py +667 -0
  746. claude_mpm/services/unified/deployment_strategies/vercel.py +471 -0
  747. claude_mpm/services/unified/interfaces.py +475 -0
  748. claude_mpm/services/unified/migration.py +509 -0
  749. claude_mpm/services/unified/strategies.py +534 -0
  750. claude_mpm/services/unified/unified_analyzer.py +542 -0
  751. claude_mpm/services/unified/unified_config.py +691 -0
  752. claude_mpm/services/unified/unified_deployment.py +466 -0
  753. claude_mpm/services/utility_service.py +280 -0
  754. claude_mpm/services/version_control/__init__.py +34 -37
  755. claude_mpm/services/version_control/branch_strategy.py +26 -17
  756. claude_mpm/services/version_control/conflict_resolution.py +52 -36
  757. claude_mpm/services/version_control/git_operations.py +183 -49
  758. claude_mpm/services/version_control/semantic_versioning.py +172 -61
  759. claude_mpm/services/version_control/version_parser.py +546 -0
  760. claude_mpm/services/version_service.py +379 -0
  761. claude_mpm/services/visualization/__init__.py +15 -0
  762. claude_mpm/services/visualization/mermaid_generator.py +937 -0
  763. claude_mpm/skills/__init__.py +42 -0
  764. claude_mpm/skills/agent_skills_injector.py +324 -0
  765. claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
  766. claude_mpm/skills/bundled/__init__.py +6 -0
  767. claude_mpm/skills/bundled/api-documentation.md +393 -0
  768. claude_mpm/skills/bundled/async-testing.md +571 -0
  769. claude_mpm/skills/bundled/code-review.md +143 -0
  770. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  771. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  772. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  773. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  774. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  775. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  776. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  777. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  778. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  779. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  780. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  781. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  782. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  783. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  784. claude_mpm/skills/bundled/database-migration.md +199 -0
  785. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  786. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  787. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  788. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  789. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  790. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  791. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  792. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  793. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  794. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  795. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  796. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  797. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  798. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  799. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  800. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  801. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  802. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  803. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  804. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  805. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  806. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  807. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  808. claude_mpm/skills/bundled/git-workflow.md +414 -0
  809. claude_mpm/skills/bundled/imagemagick.md +204 -0
  810. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  811. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  812. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  813. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  814. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  815. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  816. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  817. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  818. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  819. claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
  820. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  821. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  822. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  823. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  824. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  825. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  826. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  827. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  828. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  829. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  830. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  831. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  832. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  833. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  834. claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
  835. claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
  836. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  837. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  838. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  839. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  840. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  841. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  842. claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
  843. claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
  844. claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -0
  845. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  846. claude_mpm/skills/bundled/pdf.md +141 -0
  847. claude_mpm/skills/bundled/performance-profiling.md +573 -0
  848. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  849. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  850. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  851. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  852. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  853. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  854. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  855. claude_mpm/skills/bundled/pm/pm-bug-reporting/pm-bug-reporting.md +248 -0
  856. claude_mpm/skills/bundled/pm/pm-delegation-patterns/SKILL.md +167 -0
  857. claude_mpm/skills/bundled/pm/pm-git-file-tracking/SKILL.md +113 -0
  858. claude_mpm/skills/bundled/pm/pm-pr-workflow/SKILL.md +124 -0
  859. claude_mpm/skills/bundled/pm/pm-teaching-mode/SKILL.md +657 -0
  860. claude_mpm/skills/bundled/pm/pm-ticketing-integration/SKILL.md +154 -0
  861. claude_mpm/skills/bundled/pm/pm-verification-protocols/SKILL.md +198 -0
  862. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  863. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  864. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  865. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  866. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  867. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  868. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  869. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  870. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  871. claude_mpm/skills/bundled/security-scanning.md +439 -0
  872. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  873. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  874. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  875. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  876. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  877. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  878. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  879. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  880. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  881. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  882. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  883. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  884. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  885. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  886. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  887. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  888. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  889. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  890. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  891. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  892. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  893. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  894. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  895. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  896. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  897. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  898. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  899. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  900. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  901. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  902. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  903. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  904. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  905. claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
  906. claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
  907. claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
  908. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  909. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  910. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
  911. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  912. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  913. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  914. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  915. claude_mpm/skills/bundled/xlsx.md +157 -0
  916. claude_mpm/skills/registry.py +286 -0
  917. claude_mpm/skills/skill_manager.py +405 -0
  918. claude_mpm/skills/skills_registry.py +347 -0
  919. claude_mpm/skills/skills_service.py +739 -0
  920. claude_mpm/storage/__init__.py +9 -0
  921. claude_mpm/storage/state_storage.py +546 -0
  922. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  923. claude_mpm/templates/questions/__init__.py +38 -0
  924. claude_mpm/templates/questions/base.py +193 -0
  925. claude_mpm/templates/questions/pr_strategy.py +311 -0
  926. claude_mpm/templates/questions/project_init.py +385 -0
  927. claude_mpm/templates/questions/ticket_mgmt.py +394 -0
  928. claude_mpm/ticket_wrapper.py +2 -2
  929. claude_mpm/tools/__init__.py +10 -0
  930. claude_mpm/tools/__main__.py +208 -0
  931. claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
  932. claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
  933. claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
  934. claude_mpm/tools/code_tree_analyzer/core.py +380 -0
  935. claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
  936. claude_mpm/tools/code_tree_analyzer/events.py +168 -0
  937. claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
  938. claude_mpm/tools/code_tree_analyzer/models.py +39 -0
  939. claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
  940. claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
  941. claude_mpm/tools/code_tree_builder.py +631 -0
  942. claude_mpm/tools/code_tree_events.py +420 -0
  943. claude_mpm/tools/socketio_debug.py +671 -0
  944. claude_mpm/utils/__init__.py +8 -8
  945. claude_mpm/utils/agent_dependency_loader.py +1189 -0
  946. claude_mpm/utils/agent_filters.py +261 -0
  947. claude_mpm/utils/common.py +544 -0
  948. claude_mpm/utils/config_manager.py +168 -126
  949. claude_mpm/utils/console.py +11 -0
  950. claude_mpm/utils/database_connector.py +298 -0
  951. claude_mpm/utils/dependency_cache.py +373 -0
  952. claude_mpm/utils/dependency_manager.py +60 -59
  953. claude_mpm/utils/dependency_strategies.py +381 -0
  954. claude_mpm/utils/display_helper.py +260 -0
  955. claude_mpm/utils/environment_context.py +313 -0
  956. claude_mpm/utils/error_handler.py +78 -66
  957. claude_mpm/utils/file_utils.py +305 -0
  958. claude_mpm/utils/framework_detection.py +12 -11
  959. claude_mpm/utils/git_analyzer.py +407 -0
  960. claude_mpm/utils/gitignore.py +244 -0
  961. claude_mpm/utils/import_migration_example.py +12 -60
  962. claude_mpm/utils/imports.py +48 -45
  963. claude_mpm/utils/log_cleanup.py +627 -0
  964. claude_mpm/utils/migration.py +372 -0
  965. claude_mpm/utils/path_operations.py +110 -104
  966. claude_mpm/utils/progress.py +387 -0
  967. claude_mpm/utils/robust_installer.py +844 -0
  968. claude_mpm/utils/session_logging.py +121 -0
  969. claude_mpm/utils/structured_questions.py +619 -0
  970. claude_mpm/utils/subprocess_utils.py +343 -0
  971. claude_mpm/validation/__init__.py +1 -1
  972. claude_mpm/validation/agent_validator.py +214 -108
  973. claude_mpm/validation/frontmatter_validator.py +252 -0
  974. claude_mpm-5.4.85.dist-info/METADATA +1023 -0
  975. claude_mpm-5.4.85.dist-info/RECORD +980 -0
  976. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.85.dist-info}/entry_points.txt +1 -3
  977. claude_mpm-5.4.85.dist-info/licenses/LICENSE +94 -0
  978. claude_mpm-5.4.85.dist-info/licenses/LICENSE-FAQ.md +153 -0
  979. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -88
  980. claude_mpm/agents/INSTRUCTIONS.md +0 -352
  981. claude_mpm/agents/backups/INSTRUCTIONS.md +0 -352
  982. claude_mpm/agents/base_agent_loader.py +0 -529
  983. claude_mpm/agents/schema/agent_schema.json +0 -314
  984. claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -36
  985. claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +0 -46
  986. claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +0 -45
  987. claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +0 -49
  988. claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +0 -46
  989. claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +0 -45
  990. claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +0 -49
  991. claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +0 -46
  992. claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +0 -46
  993. claude_mpm/agents/templates/data_engineer.json +0 -110
  994. claude_mpm/agents/templates/documentation.json +0 -109
  995. claude_mpm/agents/templates/engineer.json +0 -113
  996. claude_mpm/agents/templates/ops.json +0 -109
  997. claude_mpm/agents/templates/pm.json +0 -25
  998. claude_mpm/agents/templates/qa.json +0 -111
  999. claude_mpm/agents/templates/research.json +0 -65
  1000. claude_mpm/agents/templates/security.json +0 -113
  1001. claude_mpm/agents/templates/test_integration.json +0 -112
  1002. claude_mpm/agents/templates/version_control.json +0 -107
  1003. claude_mpm/cli/commands/ui.py +0 -57
  1004. claude_mpm/core/simple_runner.py +0 -1046
  1005. claude_mpm/dashboard/open_dashboard.py +0 -34
  1006. claude_mpm/deployment_paths.py +0 -261
  1007. claude_mpm/hooks/builtin/__init__.py +0 -1
  1008. claude_mpm/hooks/builtin/logging_hook_example.py +0 -165
  1009. claude_mpm/hooks/builtin/memory_hooks_example.py +0 -67
  1010. claude_mpm/hooks/builtin/mpm_command_hook.py +0 -125
  1011. claude_mpm/hooks/builtin/post_delegation_hook_example.py +0 -124
  1012. claude_mpm/hooks/builtin/pre_delegation_hook_example.py +0 -125
  1013. claude_mpm/hooks/builtin/submit_hook_example.py +0 -100
  1014. claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +0 -237
  1015. claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +0 -240
  1016. claude_mpm/hooks/builtin/workflow_start_hook.py +0 -181
  1017. claude_mpm/orchestration/__init__.py +0 -6
  1018. claude_mpm/orchestration/archive/direct_orchestrator.py +0 -195
  1019. claude_mpm/orchestration/archive/factory.py +0 -215
  1020. claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +0 -188
  1021. claude_mpm/orchestration/archive/hook_integration_example.py +0 -178
  1022. claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +0 -826
  1023. claude_mpm/orchestration/archive/orchestrator.py +0 -501
  1024. claude_mpm/orchestration/archive/pexpect_orchestrator.py +0 -252
  1025. claude_mpm/orchestration/archive/pty_orchestrator.py +0 -270
  1026. claude_mpm/orchestration/archive/simple_orchestrator.py +0 -82
  1027. claude_mpm/orchestration/archive/subprocess_orchestrator.py +0 -801
  1028. claude_mpm/orchestration/archive/system_prompt_orchestrator.py +0 -278
  1029. claude_mpm/orchestration/archive/wrapper_orchestrator.py +0 -187
  1030. claude_mpm/schemas/workflow_validator.py +0 -411
  1031. claude_mpm/services/agent_deployment.py +0 -1534
  1032. claude_mpm/services/agent_lifecycle_manager.py +0 -1169
  1033. claude_mpm/services/agent_memory_manager.py +0 -1415
  1034. claude_mpm/services/agent_registry.py +0 -676
  1035. claude_mpm/services/deployed_agent_discovery.py +0 -226
  1036. claude_mpm/services/framework_agent_loader.py +0 -337
  1037. claude_mpm/services/framework_claude_md_generator.py +0 -621
  1038. claude_mpm/services/health_monitor.py +0 -892
  1039. claude_mpm/services/memory_router.py +0 -538
  1040. claude_mpm/services/parent_directory_manager/__init__.py +0 -577
  1041. claude_mpm/services/parent_directory_manager/backup_manager.py +0 -258
  1042. claude_mpm/services/parent_directory_manager/config_manager.py +0 -210
  1043. claude_mpm/services/parent_directory_manager/deduplication_manager.py +0 -279
  1044. claude_mpm/services/parent_directory_manager/framework_protector.py +0 -143
  1045. claude_mpm/services/parent_directory_manager/operations.py +0 -186
  1046. claude_mpm/services/parent_directory_manager/state_manager.py +0 -624
  1047. claude_mpm/services/parent_directory_manager/template_deployer.py +0 -579
  1048. claude_mpm/services/parent_directory_manager/validation_manager.py +0 -378
  1049. claude_mpm/services/parent_directory_manager/version_control_helper.py +0 -339
  1050. claude_mpm/services/parent_directory_manager/version_manager.py +0 -222
  1051. claude_mpm/services/standalone_socketio_server.py +0 -1300
  1052. claude_mpm/services/ticket_manager_di.py +0 -318
  1053. claude_mpm/services/ticketing_service_original.py +0 -508
  1054. claude_mpm/ui/__init__.py +0 -1
  1055. claude_mpm/ui/rich_terminal_ui.py +0 -295
  1056. claude_mpm/ui/terminal_ui.py +0 -328
  1057. claude_mpm/utils/paths.py +0 -289
  1058. claude_mpm-3.4.10.dist-info/METADATA +0 -183
  1059. claude_mpm-3.4.10.dist-info/RECORD +0 -201
  1060. claude_mpm-3.4.10.dist-info/licenses/LICENSE +0 -21
  1061. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.85.dist-info}/WHEEL +0 -0
  1062. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.85.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1205 @@
1
+ """Git Source Sync Service for agent templates.
2
+
3
+ Syncs agent markdown files from remote Git repositories (GitHub) using
4
+ ETag-based caching and SQLite state tracking for efficient updates.
5
+ Implements Stage 1 of the three-stage sync algorithm:
6
+ - Check repository for updates using ETag headers
7
+ - Download agent files via raw.githubusercontent.com URLs
8
+ - Track content with SHA-256 hashes and sync history in SQLite
9
+ """
10
+
11
+ import json
12
+ import logging
13
+ import time
14
+ from datetime import datetime, timezone
15
+ from pathlib import Path
16
+ from typing import Any, Dict, List, Optional, Set, Tuple
17
+
18
+ import requests
19
+
20
+ from claude_mpm.core.file_utils import get_file_hash
21
+
22
+ # Import normalize function for exclusion filtering
23
+ from claude_mpm.services.agents.deployment.multi_source_deployment_service import (
24
+ _normalize_agent_name,
25
+ )
26
+ from claude_mpm.services.agents.sources.agent_sync_state import AgentSyncState
27
+ from claude_mpm.utils.progress import create_progress_bar
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+
32
+ class GitSyncError(Exception):
33
+ """Base exception for git sync errors."""
34
+
35
+
36
+ class NetworkError(GitSyncError):
37
+ """Network/HTTP errors."""
38
+
39
+
40
+ class CacheError(GitSyncError):
41
+ """Cache read/write errors."""
42
+
43
+
44
+ class ETagCache:
45
+ """Manages ETag storage for efficient HTTP caching.
46
+
47
+ Design Decision: Simple JSON file-based cache for ETag storage
48
+
49
+ Rationale: ETags are small text strings that change infrequently.
50
+ JSON provides human-readable format for debugging and is sufficient
51
+ for this use case. Rejected SQLite as it adds complexity without
52
+ significant benefits for this simple key-value storage.
53
+
54
+ Trade-offs:
55
+ - Simplicity: JSON is simple and debuggable
56
+ - Performance: File I/O is fast enough for <100 ETags
57
+ - Scalability: Limited to ~1000s of ETags before performance degrades
58
+
59
+ Extension Points: Can be replaced with SQLite if ETag count exceeds
60
+ performance threshold (>1000 agents syncing).
61
+ """
62
+
63
+ def __init__(self, cache_file: Path):
64
+ """Initialize ETag cache.
65
+
66
+ Args:
67
+ cache_file: Path to JSON file storing ETags
68
+ """
69
+ self._cache_file = cache_file
70
+ self._cache: Dict[str, Dict[str, Any]] = self._load_cache()
71
+
72
+ def get_etag(self, url: str) -> Optional[str]:
73
+ """Retrieve stored ETag for URL.
74
+
75
+ Args:
76
+ url: URL to look up ETag for
77
+
78
+ Returns:
79
+ ETag string or None if not found
80
+ """
81
+ entry = self._cache.get(url, {})
82
+ return entry.get("etag")
83
+
84
+ def set_etag(self, url: str, etag: str, file_size: Optional[int] = None):
85
+ """Store ETag for URL.
86
+
87
+ Args:
88
+ url: URL to store ETag for
89
+ etag: ETag value to store
90
+ file_size: Optional file size in bytes
91
+ """
92
+ self._cache[url] = {
93
+ "etag": etag,
94
+ "last_modified": datetime.now(timezone.utc).isoformat(),
95
+ "file_size": file_size,
96
+ }
97
+ self._save_cache()
98
+
99
+ def _load_cache(self) -> Dict[str, Dict[str, Any]]:
100
+ """Load ETag cache from JSON file.
101
+
102
+ Returns:
103
+ Dictionary mapping URLs to ETag metadata
104
+
105
+ Error Handling:
106
+ - FileNotFoundError: Returns empty dict (first run)
107
+ - JSONDecodeError: Logs warning and returns empty dict
108
+ - PermissionError: Logs error and returns empty dict
109
+ """
110
+ if not self._cache_file.exists():
111
+ return {}
112
+
113
+ try:
114
+ with self._cache_file.open() as f:
115
+ return json.load(f)
116
+ except json.JSONDecodeError:
117
+ logger.warning(f"Invalid ETag cache file: {self._cache_file}, resetting")
118
+ return {}
119
+ except PermissionError as e:
120
+ logger.error(f"Permission denied reading ETag cache: {e}")
121
+ return {}
122
+ except Exception as e:
123
+ logger.error(f"Error loading ETag cache: {e}")
124
+ return {}
125
+
126
+ def _save_cache(self):
127
+ """Persist ETag cache to JSON file.
128
+
129
+ Error Handling:
130
+ - PermissionError: Logs error but doesn't raise (cache is optional)
131
+ - IOError: Logs error but doesn't raise (graceful degradation)
132
+
133
+ Failure Mode: If cache write fails, next sync will re-download
134
+ all files (inefficient but correct behavior).
135
+ """
136
+ try:
137
+ # Ensure parent directory exists
138
+ self._cache_file.parent.mkdir(parents=True, exist_ok=True)
139
+
140
+ with self._cache_file.open("w") as f:
141
+ json.dump(self._cache, f, indent=2)
142
+ except PermissionError as e:
143
+ logger.error(f"Permission denied writing ETag cache: {e}")
144
+ except OSError as e:
145
+ logger.error(f"IO error writing ETag cache: {e}")
146
+ except Exception as e:
147
+ logger.error(f"Error saving ETag cache: {e}")
148
+
149
+
150
+ class GitSourceSyncService:
151
+ """Service for syncing agent templates from remote Git repositories.
152
+
153
+ Design Decision: Use raw.githubusercontent.com URLs instead of Git API
154
+
155
+ Rationale: Raw URLs bypass GitHub API rate limits (60/hour unauthenticated,
156
+ 5000/hour authenticated). For agent files, direct raw access is sufficient
157
+ and more reliable. Rejected Git API because it requires base64 decoding
158
+ and consumes rate limit unnecessarily.
159
+
160
+ Trade-offs:
161
+ - Performance: Raw URLs have no rate limit, instant access
162
+ - Simplicity: Direct HTTP GET, no JSON parsing or base64 decoding
163
+ - Discovery: Cannot auto-discover agent list (requires manifest or hardcoded)
164
+ - Metadata: No commit info, file size, or last modified date
165
+
166
+ Optimization Opportunities:
167
+ 1. Async Downloads: Use aiohttp for parallel agent downloads
168
+ - Estimated speedup: 5-10x for initial sync (10 agents)
169
+ - Effort: 4-6 hours, medium complexity
170
+ - Threshold: Implement when agent count >20
171
+
172
+ 2. Manifest File: Add agents.json to repository for auto-discovery
173
+ - Removes hardcoded agent list
174
+ - Effort: 2 hours
175
+ - Blocks: Requires repository write access
176
+
177
+ Performance:
178
+ - Time Complexity: O(n) where n = number of agents
179
+ - Space Complexity: O(n) for in-memory agent content during sync
180
+ - Expected Performance:
181
+ * First sync (10 agents): ~5-10 seconds
182
+ * Subsequent sync (no changes): ~1-2 seconds (ETag checks only)
183
+ * Partial update (2 of 10 changed): ~2-3 seconds
184
+ """
185
+
186
+ def __init__(
187
+ self,
188
+ source_url: str = "https://raw.githubusercontent.com/bobmatnyc/claude-mpm-agents/main/agents",
189
+ cache_dir: Optional[Path] = None,
190
+ source_id: str = "github-remote",
191
+ ):
192
+ """Initialize Git source sync service.
193
+
194
+ Args:
195
+ source_url: Base URL for raw files (without trailing slash)
196
+ cache_dir: Local cache directory (defaults to ~/.claude-mpm/cache/agents/)
197
+ source_id: Unique identifier for this source (for multi-source support)
198
+
199
+ Design Decision: Cache to ~/.claude-mpm/cache/agents/ (canonical location)
200
+
201
+ Rationale: Separates cached repository structure from deployed agents.
202
+ This allows preserving nested directory structure in cache while
203
+ flattening for deployment. Enables multiple deployment targets
204
+ (user, project) from single cache source.
205
+
206
+ Trade-offs:
207
+ - Storage: Uses 2x disk space (cache + deployment)
208
+ - Performance: Copy operation on deployment (~10ms for 50 agents)
209
+ - Flexibility: Supports project-specific deployments
210
+ - Migration: Requires one-time migration from old cache location
211
+ """
212
+ self.source_url = source_url.rstrip("/")
213
+ self.source_id = source_id
214
+
215
+ # Setup cache directory (canonical: ~/.claude-mpm/cache/agents/)
216
+ if cache_dir:
217
+ self.cache_dir = Path(cache_dir)
218
+ else:
219
+ # Default to ~/.claude-mpm/cache/agents/ (canonical cache location)
220
+ home = Path.home()
221
+ self.cache_dir = home / ".claude-mpm" / "cache" / "agents"
222
+
223
+ self.cache_dir.mkdir(parents=True, exist_ok=True)
224
+
225
+ # Setup HTTP session with connection pooling
226
+ self.session = requests.Session()
227
+ self.session.headers["Accept"] = "text/plain"
228
+
229
+ # Initialize SQLite state tracking (NEW)
230
+ self.sync_state = AgentSyncState()
231
+
232
+ # Register this source
233
+ self.sync_state.register_source(
234
+ source_id=self.source_id, url=self.source_url, enabled=True
235
+ )
236
+
237
+ # Initialize ETag cache (DEPRECATED - kept for backward compatibility)
238
+ etag_cache_file = self.cache_dir / ".etag-cache.json"
239
+ self.etag_cache = ETagCache(etag_cache_file)
240
+
241
+ # Migrate old ETag cache to SQLite if it exists
242
+ if etag_cache_file.exists():
243
+ self._migrate_etag_cache(etag_cache_file)
244
+
245
+ # NEW: Initialize git manager for cache (Phase 1 integration)
246
+ from claude_mpm.services.agents.cache_git_manager import CacheGitManager
247
+
248
+ self.git_manager = CacheGitManager(self.cache_dir)
249
+
250
+ def sync_agents(
251
+ self,
252
+ force_refresh: bool = False,
253
+ show_progress: bool = True,
254
+ progress_prefix: str = "Syncing agents",
255
+ progress_suffix: str = "agents",
256
+ ) -> Dict[str, Any]:
257
+ """Sync agents from remote Git repository with SQLite state tracking.
258
+
259
+ Args:
260
+ force_refresh: Force download even if cache is fresh (bypasses ETag)
261
+ show_progress: Show ASCII progress bar during sync (default: True, auto-detects TTY)
262
+ progress_prefix: Custom prefix for progress bar (default: "Syncing agents")
263
+ progress_suffix: Custom suffix for completion message (default: "agents")
264
+
265
+ Returns:
266
+ Dictionary with sync results:
267
+ {
268
+ "synced": ["agent1.md", "agent2.md"], # New downloads
269
+ "cached": ["agent3.md"], # ETag 304 responses
270
+ "failed": [], # Failed downloads
271
+ "total_downloaded": 2,
272
+ "cache_hits": 1
273
+ }
274
+
275
+ Error Handling:
276
+ - Network errors: Individual agent failures don't stop sync
277
+ - Failed agents added to "failed" list
278
+ - Returns partial success if some agents sync successfully
279
+ """
280
+ logger.info(f"Starting agent sync from {self.source_url}")
281
+ logger.debug(f"Cache directory: {self.cache_dir}")
282
+ logger.debug(f"Force refresh: {force_refresh}")
283
+
284
+ start_time = time.time()
285
+
286
+ # NEW: Pre-sync git operations (Phase 1 integration)
287
+ if self.git_manager.is_git_repo():
288
+ logger.debug("Cache is a git repository, checking for updates...")
289
+
290
+ # Warn about uncommitted changes
291
+ if self.git_manager.has_uncommitted_changes():
292
+ uncommitted_count = len(
293
+ self.git_manager.get_status().get("uncommitted", [])
294
+ )
295
+ logger.warning(
296
+ f"Cache has {uncommitted_count} uncommitted change(s). "
297
+ "These will be preserved, but consider committing them."
298
+ )
299
+
300
+ # Pull latest if online (non-blocking)
301
+ try:
302
+ success, msg = self.git_manager.pull_latest()
303
+ if success:
304
+ logger.info(f"✅ Git pull: {msg}")
305
+ else:
306
+ logger.warning(f"⚠️ Git pull failed: {msg}")
307
+ logger.info("Continuing with HTTP sync as fallback")
308
+ except Exception as e:
309
+ logger.warning(f"Git pull error (continuing with HTTP sync): {e}")
310
+ else:
311
+ logger.debug("Cache is not a git repository, skipping git operations")
312
+
313
+ results = {
314
+ "synced": [],
315
+ "cached": [],
316
+ "failed": [],
317
+ "total_downloaded": 0,
318
+ "cache_hits": 0,
319
+ }
320
+
321
+ # Get list of agents to sync
322
+ agent_list = self._get_agent_list()
323
+
324
+ # Create progress bar if enabled
325
+ progress_bar = None
326
+ if show_progress:
327
+ progress_bar = create_progress_bar(
328
+ total=len(agent_list), prefix=progress_prefix
329
+ )
330
+
331
+ for idx, agent_filename in enumerate(agent_list, start=1):
332
+ try:
333
+ # Update progress bar with current file
334
+ if progress_bar:
335
+ progress_bar.update(idx, message=agent_filename)
336
+
337
+ url = f"{self.source_url}/{agent_filename}"
338
+ content, status = self._fetch_with_etag(url, force_refresh)
339
+
340
+ if status == 200:
341
+ # New content downloaded - save and track
342
+ self._save_to_cache(agent_filename, content)
343
+
344
+ # Track file with content hash in SQLite
345
+ cache_file = self.cache_dir / agent_filename
346
+ content_sha = get_file_hash(cache_file, algorithm="sha256")
347
+ if content_sha:
348
+ self.sync_state.track_file(
349
+ source_id=self.source_id,
350
+ file_path=agent_filename,
351
+ content_sha=content_sha,
352
+ local_path=str(cache_file),
353
+ file_size=len(content.encode("utf-8")),
354
+ )
355
+
356
+ results["synced"].append(agent_filename)
357
+ results["total_downloaded"] += 1
358
+ logger.debug(f"Downloaded: {agent_filename}")
359
+
360
+ elif status == 304:
361
+ # Not modified - verify hash
362
+ cache_file = self.cache_dir / agent_filename
363
+ if cache_file.exists():
364
+ current_sha = get_file_hash(cache_file, algorithm="sha256")
365
+ if current_sha and self.sync_state.has_file_changed(
366
+ self.source_id, agent_filename, current_sha
367
+ ):
368
+ # Hash mismatch - re-download
369
+ logger.warning(
370
+ f"Hash mismatch for {agent_filename}, re-downloading"
371
+ )
372
+ content, _ = self._fetch_with_etag(url, force_refresh=True)
373
+ if content:
374
+ self._save_to_cache(agent_filename, content)
375
+ # Re-calculate and track hash
376
+ new_sha = get_file_hash(cache_file, algorithm="sha256")
377
+ if new_sha:
378
+ self.sync_state.track_file(
379
+ source_id=self.source_id,
380
+ file_path=agent_filename,
381
+ content_sha=new_sha,
382
+ local_path=str(cache_file),
383
+ file_size=len(content.encode("utf-8")),
384
+ )
385
+ results["synced"].append(agent_filename)
386
+ results["total_downloaded"] += 1
387
+ else:
388
+ results["failed"].append(agent_filename)
389
+ else:
390
+ # Hash matches - true cache hit
391
+ results["cached"].append(agent_filename)
392
+ results["cache_hits"] += 1
393
+ logger.debug(f"Cache hit: {agent_filename}")
394
+ else:
395
+ # Cache file missing - re-download
396
+ logger.warning(
397
+ f"Cache file missing for {agent_filename}, re-downloading"
398
+ )
399
+ content, _ = self._fetch_with_etag(url, force_refresh=True)
400
+ if content:
401
+ self._save_to_cache(agent_filename, content)
402
+ # Track hash
403
+ current_sha = get_file_hash(cache_file, algorithm="sha256")
404
+ if current_sha:
405
+ self.sync_state.track_file(
406
+ source_id=self.source_id,
407
+ file_path=agent_filename,
408
+ content_sha=current_sha,
409
+ local_path=str(cache_file),
410
+ file_size=len(content.encode("utf-8")),
411
+ )
412
+ results["synced"].append(agent_filename)
413
+ results["total_downloaded"] += 1
414
+ else:
415
+ results["failed"].append(agent_filename)
416
+
417
+ else:
418
+ # Error status
419
+ logger.warning(f"Unexpected status {status} for {agent_filename}")
420
+ results["failed"].append(agent_filename)
421
+
422
+ except requests.RequestException as e:
423
+ logger.error(f"Network error downloading {agent_filename}: {e}")
424
+ results["failed"].append(agent_filename)
425
+ # Continue with other agents
426
+ except Exception as e:
427
+ logger.error(f"Unexpected error for {agent_filename}: {e}")
428
+ results["failed"].append(agent_filename)
429
+
430
+ # Record sync result in history
431
+ duration_ms = int((time.time() - start_time) * 1000)
432
+ status = (
433
+ "success"
434
+ if not results["failed"]
435
+ else ("partial" if results["synced"] or results["cached"] else "error")
436
+ )
437
+
438
+ self.sync_state.record_sync_result(
439
+ source_id=self.source_id,
440
+ status=status,
441
+ files_synced=results["total_downloaded"],
442
+ files_cached=results["cache_hits"],
443
+ files_failed=len(results["failed"]),
444
+ duration_ms=duration_ms,
445
+ )
446
+
447
+ # Update source metadata
448
+ self.sync_state.update_source_sync_metadata(source_id=self.source_id)
449
+
450
+ # Finish progress bar with clear breakdown
451
+ if progress_bar:
452
+ downloaded = results["total_downloaded"]
453
+ cached = results["cache_hits"]
454
+ total = downloaded + cached
455
+ failed_count = len(results["failed"])
456
+
457
+ if failed_count > 0:
458
+ progress_bar.finish(
459
+ message=f"Complete: {downloaded} downloaded, {cached} cached, {failed_count} failed ({total} total)"
460
+ )
461
+ # Show breakdown to clarify only changed files were downloaded
462
+ elif cached > 0:
463
+ progress_bar.finish(
464
+ message=f"Complete: {downloaded} downloaded, {cached} cached ({total} total)"
465
+ )
466
+ else:
467
+ # All new downloads (first sync)
468
+ progress_bar.finish(
469
+ message=f"Complete: {downloaded} {progress_suffix} downloaded"
470
+ )
471
+
472
+ # Log summary
473
+ logger.info(
474
+ f"Sync complete: {results['total_downloaded']} downloaded, "
475
+ f"{results['cache_hits']} from cache, {len(results['failed'])} failed"
476
+ )
477
+
478
+ return results
479
+
480
+ def check_for_updates(self) -> Dict[str, bool]:
481
+ """Check if remote repository has updates using ETag.
482
+
483
+ Uses HEAD requests to check ETags without downloading content.
484
+
485
+ Returns:
486
+ Dictionary mapping agent filenames to update status:
487
+ {
488
+ "research.md": True, # Has updates
489
+ "engineer.md": False, # No updates (ETag matches)
490
+ }
491
+
492
+ Performance: ~1-2 seconds for 10 agents (HEAD requests only)
493
+ """
494
+ logger.info("Checking for agent updates")
495
+ updates = {}
496
+
497
+ agent_list = self._get_agent_list()
498
+
499
+ for agent_filename in agent_list:
500
+ try:
501
+ url = f"{self.source_url}/{agent_filename}"
502
+ cached_etag = self.etag_cache.get_etag(url)
503
+
504
+ # Use HEAD request to check ETag without downloading
505
+ response = self.session.head(url, timeout=30)
506
+
507
+ if response.status_code == 200:
508
+ remote_etag = response.headers.get("ETag")
509
+ has_update = remote_etag != cached_etag
510
+ updates[agent_filename] = has_update
511
+
512
+ if has_update:
513
+ logger.info(f"Update available: {agent_filename}")
514
+ else:
515
+ logger.warning(
516
+ f"Could not check {agent_filename}: HTTP {response.status_code}"
517
+ )
518
+ updates[agent_filename] = False
519
+
520
+ except requests.RequestException as e:
521
+ logger.error(f"Network error checking {agent_filename}: {e}")
522
+ updates[agent_filename] = False
523
+
524
+ return updates
525
+
526
+ def download_agent_file(self, filename: str) -> Optional[str]:
527
+ """Download single agent file with ETag caching.
528
+
529
+ Args:
530
+ filename: Agent filename (e.g., "research.md")
531
+
532
+ Returns:
533
+ Agent content as string, or None if download fails
534
+
535
+ Error Handling:
536
+ - Network errors: Returns None, logs error
537
+ - 404 Not Found: Returns None, logs warning
538
+ - Cache fallback: Attempts to load from cache on error
539
+ """
540
+ url = f"{self.source_url}/{filename}"
541
+
542
+ try:
543
+ content, status = self._fetch_with_etag(url)
544
+
545
+ if status == 200:
546
+ self._save_to_cache(filename, content)
547
+ return content
548
+ if status == 304:
549
+ # Load from cache
550
+ return self._load_from_cache(filename)
551
+ logger.warning(f"HTTP {status} for {filename}")
552
+ return None
553
+
554
+ except requests.RequestException as e:
555
+ logger.error(f"Network error downloading {filename}: {e}")
556
+ # Try cache fallback
557
+ return self._load_from_cache(filename)
558
+
559
+ def _fetch_with_etag(
560
+ self, url: str, force_refresh: bool = False
561
+ ) -> Tuple[Optional[str], int]:
562
+ """Fetch URL with ETag caching.
563
+
564
+ Design Decision: Use If-None-Match header for conditional requests
565
+
566
+ Rationale: ETag-based caching is standard HTTP pattern that GitHub
567
+ supports. Reduces bandwidth by 95%+ for unchanged files. Alternative
568
+ was Last-Modified timestamps, but ETags are more reliable for Git
569
+ content (commit hash based).
570
+
571
+ Args:
572
+ url: URL to fetch
573
+ force_refresh: Skip ETag check and force download
574
+
575
+ Returns:
576
+ Tuple of (content, status_code) where:
577
+ - status_code 200: New content downloaded
578
+ - status_code 304: Not modified (use cached)
579
+ - content is None on 304
580
+
581
+ Error Handling:
582
+ - Timeout: 30 second timeout, raises requests.Timeout
583
+ - Connection errors: Raises requests.ConnectionError
584
+ - HTTP errors (4xx, 5xx): Returns (None, status_code)
585
+ """
586
+ headers = {}
587
+
588
+ # Add ETag header if we have cached version and not forcing refresh
589
+ if not force_refresh:
590
+ cached_etag = self.etag_cache.get_etag(url)
591
+ if cached_etag:
592
+ headers["If-None-Match"] = cached_etag
593
+
594
+ response = self.session.get(url, headers=headers, timeout=30)
595
+
596
+ if response.status_code == 304:
597
+ # Not modified - use cached version
598
+ return None, 304
599
+
600
+ if response.status_code == 200:
601
+ # New content - update cache
602
+ content = response.text
603
+ etag = response.headers.get("ETag")
604
+ if etag:
605
+ file_size = len(content.encode("utf-8"))
606
+ self.etag_cache.set_etag(url, etag, file_size)
607
+ return content, 200
608
+
609
+ # Error status
610
+ return None, response.status_code
611
+
612
+ def _save_to_cache(self, filename: str, content: str):
613
+ """Save agent file to cache (Phase 1: preserves nested directory structure).
614
+
615
+ Design Decision: Preserve nested directory structure in cache
616
+
617
+ Rationale: Cache mirrors remote repository structure, allowing
618
+ proper organization and future features (e.g., category browsing).
619
+ Deployment layer flattens to .claude-mpm/agents/ for backward
620
+ compatibility.
621
+
622
+ Args:
623
+ filename: Agent file path (may include directories, e.g., "engineer/core/engineer.md")
624
+ content: File content
625
+
626
+ Error Handling:
627
+ - PermissionError: Logs error but doesn't raise
628
+ - IOError: Logs error but doesn't raise
629
+
630
+ Failure Mode: If cache write fails, agent is still synced in memory
631
+ but will need re-download on next sync (graceful degradation).
632
+ """
633
+ try:
634
+ cache_file = self.cache_dir / filename
635
+ # Create parent directories for nested structure
636
+ cache_file.parent.mkdir(parents=True, exist_ok=True)
637
+ cache_file.write_text(content, encoding="utf-8")
638
+ logger.debug(f"Saved to cache: {filename}")
639
+ except PermissionError as e:
640
+ logger.error(f"Permission denied writing {filename}: {e}")
641
+ except OSError as e:
642
+ logger.error(f"IO error writing {filename}: {e}")
643
+ except Exception as e:
644
+ logger.error(f"Error saving {filename} to cache: {e}")
645
+
646
+ def _load_from_cache(self, filename: str) -> Optional[str]:
647
+ """Load agent file from cache.
648
+
649
+ Args:
650
+ filename: Agent filename
651
+
652
+ Returns:
653
+ Cached content or None if not found
654
+
655
+ Error Handling:
656
+ - FileNotFoundError: Returns None (not in cache)
657
+ - PermissionError: Logs error, returns None
658
+ - IOError: Logs error, returns None
659
+ """
660
+ cache_file = self.cache_dir / filename
661
+
662
+ if not cache_file.exists():
663
+ logger.debug(f"No cached version of {filename}")
664
+ return None
665
+
666
+ try:
667
+ content = cache_file.read_text(encoding="utf-8")
668
+ logger.debug(f"Loaded from cache: {filename}")
669
+ return content
670
+ except PermissionError as e:
671
+ logger.error(f"Permission denied reading {filename}: {e}")
672
+ return None
673
+ except OSError as e:
674
+ logger.error(f"IO error reading {filename}: {e}")
675
+ return None
676
+ except Exception as e:
677
+ logger.error(f"Error loading {filename} from cache: {e}")
678
+ return None
679
+
680
+ def _get_agent_list(self) -> List[str]:
681
+ """Get list of agent file paths to sync (including nested directories).
682
+
683
+ Design Decision: Use Git Tree API instead of Contents API (Phase 1 fix)
684
+
685
+ Rationale: Git Tree API with recursive=1 discovers entire repository
686
+ structure in a single request, solving the "1 agent discovered" issue.
687
+ Contents API only shows top-level files, missing nested directories.
688
+
689
+ Trade-offs:
690
+ - Performance: Single API call vs. 10-50+ recursive calls
691
+ - Rate Limits: 1 request vs. dozens (avoids 403 errors)
692
+ - Discovery: Finds ALL files in nested structure (50+ agents)
693
+ - API Complexity: Requires commit SHA lookup before tree fetch
694
+
695
+ Alternatives Considered:
696
+ 1. Contents API with recursion: 50+ API calls, hits rate limits
697
+ 2. Hardcoded nested paths: Misses new agents, unmaintainable
698
+ 3. Manifest file: Requires repository write access
699
+
700
+ Error Handling:
701
+ - Network errors: Falls back to static list
702
+ - Rate limit exceeded: Falls back to static list
703
+ - JSON parse errors: Falls back to static list
704
+
705
+ Returns:
706
+ List of agent file paths with directory structure
707
+ (e.g., ["research.md", "engineer/core/engineer.md", ...])
708
+ """
709
+ # Extract repository info from source URL
710
+ # URL format: https://raw.githubusercontent.com/owner/repo/branch/path
711
+ try:
712
+ # Parse GitHub URL to extract owner/repo/branch
713
+ url_parts = self.source_url.replace(
714
+ "https://raw.githubusercontent.com/", ""
715
+ ).split("/")
716
+
717
+ if len(url_parts) >= 3:
718
+ owner = url_parts[0]
719
+ repo = url_parts[1]
720
+ branch = url_parts[2]
721
+ base_path = "/".join(url_parts[3:]) if len(url_parts) > 3 else ""
722
+
723
+ logger.debug(
724
+ f"Discovering agents from {owner}/{repo}/{branch} via Git Tree API"
725
+ )
726
+
727
+ # Use Git Tree API for recursive discovery
728
+ agent_files = self._discover_agents_via_tree_api(
729
+ owner, repo, branch, base_path
730
+ )
731
+
732
+ if agent_files:
733
+ logger.info(
734
+ f"Discovered {len(agent_files)} agents via Git Tree API"
735
+ )
736
+ return sorted(agent_files)
737
+
738
+ logger.warning("No agent files found via Tree API, using fallback list")
739
+
740
+ except requests.RequestException as e:
741
+ logger.warning(
742
+ f"Network error fetching agent list from API: {e}, using fallback list"
743
+ )
744
+ except (json.JSONDecodeError, KeyError, ValueError) as e:
745
+ logger.warning(
746
+ f"Error parsing GitHub API response: {e}, using fallback list"
747
+ )
748
+ except Exception as e:
749
+ logger.warning(
750
+ f"Unexpected error fetching agent list: {e}, using fallback list"
751
+ )
752
+
753
+ # Fallback to known agent list if API fails
754
+ logger.debug("Using fallback agent list")
755
+ return [
756
+ "research.md",
757
+ "engineer.md",
758
+ "qa.md",
759
+ "documentation.md",
760
+ "security.md",
761
+ "ops.md",
762
+ "ticketing.md",
763
+ "product_owner.md",
764
+ "version_control.md",
765
+ "project_organizer.md",
766
+ ]
767
+
768
+ def _discover_agents_via_tree_api(
769
+ self, owner: str, repo: str, branch: str, base_path: str = ""
770
+ ) -> List[str]:
771
+ """Discover all agent files using GitHub Git Tree API with recursion.
772
+
773
+ Design Decision: Two-step Tree API pattern (commit SHA → tree)
774
+
775
+ Rationale: Git Tree API requires commit SHA, not branch name.
776
+ Step 1 resolves branch to SHA, Step 2 fetches recursive tree.
777
+ This pattern is standard for GitHub API and handles branch
778
+ references correctly.
779
+
780
+ Algorithm:
781
+ 1. GET /repos/{owner}/{repo}/git/refs/heads/{branch} → commit SHA
782
+ 2. GET /repos/{owner}/{repo}/git/trees/{sha}?recursive=1 → all files
783
+ 3. Filter for .md/.json files in agents/ directory
784
+ 4. Exclude README.md and .gitignore
785
+
786
+ Args:
787
+ owner: GitHub owner (e.g., "bobmatnyc")
788
+ repo: Repository name (e.g., "claude-mpm-agents")
789
+ branch: Branch name (e.g., "main")
790
+ base_path: Base path prefix to filter (e.g., "agents")
791
+
792
+ Returns:
793
+ List of agent file paths relative to base_path
794
+ (e.g., ["research.md", "engineer/core/engineer.md"])
795
+
796
+ Error Handling:
797
+ - HTTP 404: Branch or repo not found, raises RequestException
798
+ - HTTP 403: Rate limit exceeded, raises RequestException
799
+ - Timeout: 30 second timeout, raises RequestException
800
+ - Empty tree: Returns empty list (logged as warning)
801
+
802
+ Performance:
803
+ - Time: ~500-800ms for 50+ agents (2 API calls)
804
+ - Rate Limit: Consumes 2 API calls per sync
805
+ - Scalability: Handles repositories with 1000s of files
806
+ """
807
+ # Step 1: Get commit SHA for branch
808
+ refs_url = (
809
+ f"https://api.github.com/repos/{owner}/{repo}/git/refs/heads/{branch}"
810
+ )
811
+ logger.debug(f"Fetching commit SHA from {refs_url}")
812
+
813
+ refs_response = self.session.get(
814
+ refs_url, headers={"Accept": "application/vnd.github+json"}, timeout=30
815
+ )
816
+
817
+ if refs_response.status_code == 403:
818
+ logger.warning(
819
+ "GitHub API rate limit exceeded (HTTP 403). "
820
+ "Consider setting GITHUB_TOKEN environment variable."
821
+ )
822
+ raise requests.RequestException("Rate limit exceeded")
823
+
824
+ refs_response.raise_for_status()
825
+ commit_sha = refs_response.json()["object"]["sha"]
826
+ logger.debug(f"Resolved {branch} to commit {commit_sha[:8]}")
827
+
828
+ # Step 2: Get recursive tree for commit
829
+ tree_url = f"https://api.github.com/repos/{owner}/{repo}/git/trees/{commit_sha}"
830
+ params = {"recursive": "1"} # Recursively fetch all files
831
+
832
+ logger.debug(f"Fetching recursive tree from {tree_url}")
833
+ tree_response = self.session.get(
834
+ tree_url,
835
+ headers={"Accept": "application/vnd.github+json"},
836
+ params=params,
837
+ timeout=30,
838
+ )
839
+ tree_response.raise_for_status()
840
+
841
+ tree_data = tree_response.json()
842
+ all_items = tree_data.get("tree", [])
843
+
844
+ logger.debug(f"Tree API returned {len(all_items)} total items")
845
+
846
+ # Step 3: Filter for agent files
847
+ agent_files = []
848
+ for item in all_items:
849
+ # Only process files (blobs), not directories (trees)
850
+ if item["type"] != "blob":
851
+ continue
852
+
853
+ path = item["path"]
854
+
855
+ # Filter for files in base_path (e.g., "agents/")
856
+ if base_path and not path.startswith(base_path + "/"):
857
+ continue
858
+
859
+ # Exclude build/dist directories (prevents double-counting)
860
+ # e.g., both "agents/engineer.md" and "dist/agents/engineer.md"
861
+ path_parts = path.split("/")
862
+ if any(excluded in path_parts for excluded in ["dist", "build", ".cache"]):
863
+ continue
864
+
865
+ # Remove base_path prefix for relative paths
866
+ if base_path:
867
+ relative_path = path[len(base_path) + 1 :]
868
+ else:
869
+ relative_path = path
870
+
871
+ # Filter for .md or .json files, exclude README and .gitignore
872
+ if (
873
+ relative_path.endswith(".md") or relative_path.endswith(".json")
874
+ ) and relative_path not in ["README.md", ".gitignore"]:
875
+ agent_files.append(relative_path)
876
+
877
+ logger.debug(f"Filtered to {len(agent_files)} agent files")
878
+ return agent_files
879
+
880
+ def _migrate_etag_cache(self, cache_file: Path):
881
+ """Migrate old ETag cache to SQLite (one-time operation).
882
+
883
+ Args:
884
+ cache_file: Path to old JSON ETag cache file
885
+
886
+ Error Handling:
887
+ - Migration failures are logged but don't stop initialization
888
+ - Old cache is renamed to .migrated to prevent re-migration
889
+ """
890
+ try:
891
+ with cache_file.open() as f:
892
+ old_cache = json.load(f)
893
+
894
+ logger.info(f"Migrating {len(old_cache)} ETag entries to SQLite...")
895
+
896
+ migrated = 0
897
+ for url, metadata in old_cache.items():
898
+ try:
899
+ etag = metadata.get("etag")
900
+ if etag:
901
+ # Store in new system
902
+ self.sync_state.update_source_sync_metadata(
903
+ source_id=self.source_id, etag=etag
904
+ )
905
+ migrated += 1
906
+ except Exception as e:
907
+ logger.error(f"Failed to migrate {url}: {e}")
908
+
909
+ # Rename old cache to prevent re-migration
910
+ backup_file = cache_file.with_suffix(".json.migrated")
911
+ cache_file.rename(backup_file)
912
+
913
+ logger.info(
914
+ f"ETag cache migration complete: {migrated} entries migrated, "
915
+ f"old cache backed up to {backup_file.name}"
916
+ )
917
+
918
+ except json.JSONDecodeError as e:
919
+ logger.error(f"Invalid JSON in ETag cache, skipping migration: {e}")
920
+ except Exception as e:
921
+ logger.error(f"Failed to migrate ETag cache: {e}")
922
+
923
+ def get_cached_agents_dir(self) -> Path:
924
+ """Get directory containing cached agent files.
925
+
926
+ Returns:
927
+ Path to cache directory for integration with MultiSourceAgentDeploymentService
928
+ """
929
+ return self.cache_dir
930
+
931
+ def _cleanup_excluded_agents(
932
+ self,
933
+ deployment_dir: Path,
934
+ excluded_set: Set[str],
935
+ ) -> Dict[str, List[str]]:
936
+ """Remove excluded agents from deployment directory.
937
+
938
+ Removes any agents in the deployment directory whose normalized
939
+ names match the exclusion list. This ensures that excluded agents
940
+ are cleaned up from previous deployments.
941
+
942
+ Args:
943
+ deployment_dir: Directory containing deployed agents
944
+ excluded_set: Set of normalized agent names to exclude
945
+
946
+ Returns:
947
+ Dictionary with cleanup results:
948
+ - removed: List of agent names that were removed
949
+ """
950
+ cleanup_results: Dict[str, List[str]] = {"removed": []}
951
+
952
+ if not deployment_dir.exists():
953
+ logger.debug("Deployment directory does not exist, no cleanup needed")
954
+ return cleanup_results
955
+
956
+ for item in deployment_dir.iterdir():
957
+ # Only process .md files
958
+ if not item.is_file() or item.suffix != ".md":
959
+ continue
960
+
961
+ # Skip hidden files
962
+ if item.name.startswith("."):
963
+ continue
964
+
965
+ # Normalize agent name for comparison
966
+ agent_name = _normalize_agent_name(item.stem)
967
+
968
+ # Check if this agent is excluded
969
+ if agent_name in excluded_set:
970
+ try:
971
+ item.unlink()
972
+ cleanup_results["removed"].append(item.stem)
973
+ logger.info(f"Removed excluded agent: {item.stem}")
974
+ except PermissionError as e:
975
+ logger.error(f"Permission denied removing {item.stem}: {e}")
976
+ except Exception as e:
977
+ logger.error(f"Failed to remove {item.stem}: {e}")
978
+
979
+ # Log summary
980
+ if cleanup_results["removed"]:
981
+ logger.info(
982
+ f"Cleanup complete: removed {len(cleanup_results['removed'])} excluded agents"
983
+ )
984
+
985
+ return cleanup_results
986
+
987
+ def deploy_agents_to_project(
988
+ self,
989
+ project_dir: Path,
990
+ agent_list: Optional[List[str]] = None,
991
+ force: bool = False,
992
+ ) -> Dict[str, Any]:
993
+ """Deploy agents from cache to project directory (Phase 1 deployment).
994
+
995
+ Design Decision: Copy from cache to project-specific deployment directory
996
+
997
+ Rationale: Separates syncing (cache) from deployment (project-local).
998
+ Allows multiple projects to use same cache with different agent
999
+ configurations. Flattens nested structure for backward compatibility.
1000
+
1001
+ Trade-offs:
1002
+ - Storage: 2x disk usage (cache + deployments)
1003
+ - Performance: Copy operation ~10ms for 50 agents
1004
+ - Isolation: Each project has independent agent set
1005
+ - Flexibility: Can deploy subset of cached agents per project
1006
+
1007
+ Algorithm:
1008
+ 1. Create deployment directory (.claude-mpm/agents/)
1009
+ 2. Discover cached agents if list not provided
1010
+ 3. For each agent, flatten path and copy to deployment
1011
+ 4. Track deployment results (new, updated, skipped)
1012
+
1013
+ Args:
1014
+ project_dir: Project root directory (e.g., /path/to/project)
1015
+ agent_list: Optional list of agent paths to deploy (uses all if None)
1016
+ force: Force redeployment even if up-to-date
1017
+
1018
+ Returns:
1019
+ Dictionary with deployment results:
1020
+ {
1021
+ "deployed": ["engineer.md"], # Newly deployed
1022
+ "updated": ["research.md"], # Updated existing
1023
+ "skipped": ["qa.md"], # Already up-to-date
1024
+ "failed": ["broken.md"], # Copy failures
1025
+ "deployment_dir": "/path/.claude-mpm/agents"
1026
+ }
1027
+
1028
+ Error Handling:
1029
+ - Missing cache files: Logged and added to "failed" list
1030
+ - Permission errors: Individual failures don't stop deployment
1031
+ - Directory creation: Creates deployment directory if missing
1032
+
1033
+ Example:
1034
+ >>> service = GitSourceSyncService()
1035
+ >>> service.sync_agents() # Sync to cache first
1036
+ >>> result = service.deploy_agents_to_project(Path("/my/project"))
1037
+ >>> print(f"Deployed {len(result['deployed'])} agents")
1038
+ """
1039
+ import shutil
1040
+
1041
+ from claude_mpm.core.config import Config
1042
+
1043
+ # Deploy to .claude/agents/ where Claude Code expects them
1044
+ deployment_dir = project_dir / ".claude" / "agents"
1045
+ deployment_dir.mkdir(parents=True, exist_ok=True)
1046
+
1047
+ results = {
1048
+ "deployed": [],
1049
+ "updated": [],
1050
+ "skipped": [],
1051
+ "failed": [],
1052
+ "deployment_dir": str(deployment_dir),
1053
+ }
1054
+
1055
+ # Load project config to get exclusion list
1056
+ config_file = project_dir / ".claude-mpm" / "configuration.yaml"
1057
+ if config_file.exists():
1058
+ config = Config(config_file=config_file)
1059
+ excluded_agents = config.get("excluded_agents", [])
1060
+ else:
1061
+ # No project config, no exclusions
1062
+ excluded_agents = []
1063
+
1064
+ # Create normalized exclusion set
1065
+ excluded_set: Set[str] = (
1066
+ {_normalize_agent_name(name) for name in excluded_agents}
1067
+ if excluded_agents
1068
+ else set()
1069
+ )
1070
+
1071
+ if excluded_set:
1072
+ logger.info(
1073
+ f"Applying exclusions: {', '.join(sorted(excluded_agents))} "
1074
+ f"(normalized: {', '.join(sorted(excluded_set))})"
1075
+ )
1076
+
1077
+ # Get agents from cache or use provided list
1078
+ if agent_list is None:
1079
+ agent_list = self._discover_cached_agents()
1080
+
1081
+ # Filter out excluded agents
1082
+ if excluded_set:
1083
+ original_count = len(agent_list)
1084
+ agent_list = [
1085
+ agent_path
1086
+ for agent_path in agent_list
1087
+ if _normalize_agent_name(Path(agent_path).stem) not in excluded_set
1088
+ ]
1089
+ filtered_count = original_count - len(agent_list)
1090
+ if filtered_count > 0:
1091
+ logger.info(f"Filtered out {filtered_count} excluded agents")
1092
+
1093
+ # Clean up any previously deployed excluded agents
1094
+ if excluded_set:
1095
+ cleanup_results = self._cleanup_excluded_agents(
1096
+ deployment_dir, excluded_set
1097
+ )
1098
+ if cleanup_results["removed"]:
1099
+ logger.info(
1100
+ f"Cleaned up {len(cleanup_results['removed'])} excluded agents: "
1101
+ f"{', '.join(cleanup_results['removed'])}"
1102
+ )
1103
+
1104
+ logger.info(
1105
+ f"Deploying {len(agent_list)} agents from cache to {deployment_dir}"
1106
+ )
1107
+
1108
+ for agent_path in agent_list:
1109
+ try:
1110
+ cache_file = self.cache_dir / agent_path
1111
+
1112
+ if not cache_file.exists():
1113
+ logger.warning(f"Cache file not found: {agent_path}")
1114
+ results["failed"].append(agent_path)
1115
+ continue
1116
+
1117
+ # Flatten nested path for deployment (engineer/core/engineer.md → engineer.md)
1118
+ deploy_filename = Path(agent_path).name
1119
+ deploy_file = deployment_dir / deploy_filename
1120
+
1121
+ # Check if update needed (compare content, not just mtime)
1122
+ # DESIGN: Use content hash comparison for reliable change detection
1123
+ # Mtime comparison can fail when cache downloads have older timestamps
1124
+ should_deploy = force
1125
+ was_existing = deploy_file.exists()
1126
+
1127
+ if not force and was_existing:
1128
+ # Compare file contents using hash
1129
+ cache_content = cache_file.read_bytes()
1130
+ deploy_content = deploy_file.read_bytes()
1131
+ should_deploy = cache_content != deploy_content
1132
+
1133
+ if not should_deploy and was_existing:
1134
+ results["skipped"].append(deploy_filename)
1135
+ logger.debug(f"Skipped (up-to-date): {deploy_filename}")
1136
+ continue
1137
+
1138
+ # Copy from cache to deployment
1139
+ shutil.copy2(cache_file, deploy_file)
1140
+
1141
+ # Track result
1142
+ if deploy_file.exists():
1143
+ if was_existing:
1144
+ results["updated"].append(deploy_filename)
1145
+ logger.info(f"Updated: {deploy_filename}")
1146
+ else:
1147
+ results["deployed"].append(deploy_filename)
1148
+ logger.info(f"Deployed: {deploy_filename}")
1149
+ else:
1150
+ results["failed"].append(deploy_filename)
1151
+ logger.error(f"Failed to deploy: {deploy_filename}")
1152
+
1153
+ except PermissionError as e:
1154
+ logger.error(f"Permission denied deploying {agent_path}: {e}")
1155
+ results["failed"].append(Path(agent_path).name)
1156
+ except OSError as e:
1157
+ logger.error(f"IO error deploying {agent_path}: {e}")
1158
+ results["failed"].append(Path(agent_path).name)
1159
+ except Exception as e:
1160
+ logger.error(f"Unexpected error deploying {agent_path}: {e}")
1161
+ results["failed"].append(Path(agent_path).name)
1162
+
1163
+ # Log summary
1164
+ total_success = len(results["deployed"]) + len(results["updated"])
1165
+ logger.info(
1166
+ f"Deployment complete: {total_success} deployed/updated, "
1167
+ f"{len(results['skipped'])} skipped, {len(results['failed'])} failed"
1168
+ )
1169
+
1170
+ return results
1171
+
1172
+ def _discover_cached_agents(self) -> List[str]:
1173
+ """Discover all agent files currently in cache.
1174
+
1175
+ Scans cache directory for .md and .json files, preserving
1176
+ nested directory structure in returned paths.
1177
+
1178
+ Returns:
1179
+ List of agent file paths relative to cache directory
1180
+ (e.g., ["research.md", "engineer/core/engineer.md"])
1181
+
1182
+ Algorithm:
1183
+ 1. Walk cache directory recursively
1184
+ 2. Find all .md and .json files
1185
+ 3. Convert to paths relative to cache root
1186
+ 4. Filter out README.md and .gitignore
1187
+ """
1188
+ cached_agents = []
1189
+
1190
+ if not self.cache_dir.exists():
1191
+ logger.warning(f"Cache directory does not exist: {self.cache_dir}")
1192
+ return []
1193
+
1194
+ for file_path in self.cache_dir.rglob("*"):
1195
+ if file_path.is_file() and file_path.suffix in {".md", ".json"}:
1196
+ # Get relative path from cache directory
1197
+ relative_path = file_path.relative_to(self.cache_dir)
1198
+ relative_str = str(relative_path)
1199
+
1200
+ # Exclude README and .gitignore
1201
+ if relative_str not in ["README.md", ".gitignore"]:
1202
+ cached_agents.append(relative_str)
1203
+
1204
+ logger.debug(f"Discovered {len(cached_agents)} cached agents")
1205
+ return sorted(cached_agents)