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.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

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,1340 @@
1
+ """Git source manager for multi-repository skill sync and discovery.
2
+
3
+ This module manages multiple Git-based skill sources with priority resolution.
4
+ It orchestrates syncing, caching, and discovery of skills from multiple repositories,
5
+ applying priority-based conflict resolution when skills have the same ID.
6
+
7
+ Design Decision: Reuse GitSourceSyncService for all Git operations
8
+
9
+ Rationale: The GitSourceSyncService provides robust ETag-based caching and
10
+ incremental updates for Git repositories. Rather than duplicating this logic,
11
+ we compose it and adapt for skills-specific discovery.
12
+
13
+ Trade-offs:
14
+ - Code Reuse: Leverage proven sync infrastructure
15
+ - Maintainability: Single source of truth for Git operations
16
+ - Flexibility: Easy to extend with skills-specific features
17
+ """
18
+
19
+ from concurrent.futures import ThreadPoolExecutor, as_completed
20
+ from datetime import datetime, timezone
21
+ from pathlib import Path
22
+ from threading import Lock
23
+ from typing import Any, Dict, List, Optional, Set, Tuple
24
+
25
+ from claude_mpm.config.skill_sources import SkillSource, SkillSourceConfiguration
26
+ from claude_mpm.core.logging_config import get_logger
27
+ from claude_mpm.services.agents.sources.git_source_sync_service import (
28
+ GitSourceSyncService,
29
+ )
30
+ from claude_mpm.services.skills.skill_discovery_service import SkillDiscoveryService
31
+
32
+ logger = get_logger(__name__)
33
+
34
+
35
+ class GitSkillSourceManager:
36
+ """Manages multiple Git-based skill sources with priority resolution.
37
+
38
+ Responsibilities:
39
+ - Coordinate syncing of multiple skill repositories
40
+ - Apply priority-based resolution for duplicate skills
41
+ - Provide unified catalog of available skills
42
+ - Handle caching and updates
43
+
44
+ Priority Resolution:
45
+ - Lower priority number = higher precedence
46
+ - Priority 0 reserved for system repository
47
+ - Skills with same ID: lowest priority wins
48
+
49
+ Design Pattern: Orchestrator with Dependency Injection
50
+
51
+ This class orchestrates multiple services (sync, discovery) without
52
+ reimplementing their logic. Services can be injected for testing.
53
+
54
+ Example:
55
+ >>> config = SkillSourceConfiguration()
56
+ >>> manager = GitSkillSourceManager(config)
57
+ >>> results = manager.sync_all_sources()
58
+ >>> skills = manager.get_all_skills()
59
+ """
60
+
61
+ def __init__(
62
+ self,
63
+ config: SkillSourceConfiguration,
64
+ cache_dir: Optional[Path] = None,
65
+ sync_service: Optional[GitSourceSyncService] = None,
66
+ ):
67
+ """Initialize skill source manager.
68
+
69
+ Args:
70
+ config: Skill source configuration
71
+ cache_dir: Cache directory (defaults to ~/.claude-mpm/cache/skills/)
72
+ sync_service: Git sync service (injected for testing)
73
+ """
74
+ if cache_dir is None:
75
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "skills"
76
+
77
+ self.config = config
78
+ self.cache_dir = cache_dir
79
+ self.cache_dir.mkdir(parents=True, exist_ok=True)
80
+ self.sync_service = sync_service # Use injected if provided
81
+ self.logger = get_logger(__name__)
82
+ self._etag_cache_lock = Lock() # Thread-safe ETag cache operations
83
+
84
+ self.logger.info(
85
+ f"GitSkillSourceManager initialized with cache: {self.cache_dir}"
86
+ )
87
+
88
+ def sync_all_sources(
89
+ self, force: bool = False, progress_callback=None
90
+ ) -> Dict[str, Any]:
91
+ """Sync all enabled skill sources.
92
+
93
+ Syncs sources in priority order (lower priority first). Individual
94
+ failures don't stop overall sync.
95
+
96
+ Args:
97
+ force: Force re-download even if cached
98
+ progress_callback: Optional callback(increment: int) called for each file synced
99
+
100
+ Returns:
101
+ Dict with sync results for each source:
102
+ {
103
+ "synced_count": int,
104
+ "failed_count": int,
105
+ "total_files_updated": int,
106
+ "total_files_cached": int,
107
+ "sources": {
108
+ "source_id": {
109
+ "synced": bool,
110
+ "files_updated": int,
111
+ "skills_discovered": int,
112
+ "error": str (if failed)
113
+ }
114
+ },
115
+ "timestamp": str
116
+ }
117
+
118
+ Example:
119
+ >>> manager = GitSkillSourceManager(config)
120
+ >>> results = manager.sync_all_sources()
121
+ >>> print(f"Synced {results['synced_count']} sources")
122
+ """
123
+ sources = self.config.get_enabled_sources()
124
+ self.logger.info(f"Syncing {len(sources)} enabled skill sources")
125
+
126
+ results = {
127
+ "synced_count": 0,
128
+ "failed_count": 0,
129
+ "total_files_updated": 0,
130
+ "total_files_cached": 0,
131
+ "sources": {},
132
+ "timestamp": datetime.now(timezone.utc).isoformat(),
133
+ }
134
+
135
+ for source in sources:
136
+ try:
137
+ result = self.sync_source(
138
+ source.id, force=force, progress_callback=progress_callback
139
+ )
140
+ results["sources"][source.id] = result
141
+
142
+ if result.get("synced"):
143
+ results["synced_count"] += 1
144
+ results["total_files_updated"] += result.get("files_updated", 0)
145
+ results["total_files_cached"] += result.get("files_cached", 0)
146
+ else:
147
+ results["failed_count"] += 1
148
+
149
+ except Exception as e:
150
+ self.logger.error(f"Exception syncing source {source.id}: {e}")
151
+ results["sources"][source.id] = {"synced": False, "error": str(e)}
152
+ results["failed_count"] += 1
153
+
154
+ self.logger.info(
155
+ f"Sync complete: {results['synced_count']} succeeded, "
156
+ f"{results['failed_count']} failed"
157
+ )
158
+
159
+ return results
160
+
161
+ def sync_source(
162
+ self, source_id: str, force: bool = False, progress_callback=None
163
+ ) -> Dict[str, Any]:
164
+ """Sync a specific skill source.
165
+
166
+ Design Decision: Recursive GitHub directory download for skills
167
+
168
+ Rationale: Skills use nested directory structures (e.g., universal/collaboration/SKILL.md)
169
+ unlike agents which are flat .md files. We need to recursively download the entire
170
+ repository structure to discover all SKILL.md files.
171
+
172
+ Approach: Use GitHub API to recursively discover all files, then download each via
173
+ raw.githubusercontent.com with ETag caching for efficiency.
174
+
175
+ Args:
176
+ source_id: ID of source to sync
177
+ force: Force re-download
178
+ progress_callback: Optional callback(increment: int) called for each file synced
179
+
180
+ Returns:
181
+ Sync result dict:
182
+ {
183
+ "synced": bool,
184
+ "files_updated": int,
185
+ "files_cached": int,
186
+ "skills_discovered": int,
187
+ "timestamp": str,
188
+ "error": str (if failed)
189
+ }
190
+
191
+ Raises:
192
+ ValueError: If source_id not found
193
+
194
+ Example:
195
+ >>> manager = GitSkillSourceManager(config)
196
+ >>> result = manager.sync_source("system")
197
+ >>> print(f"Updated {result['files_updated']} files")
198
+ """
199
+ source = self.config.get_source(source_id)
200
+ if not source:
201
+ raise ValueError(f"Source not found: {source_id}")
202
+
203
+ if not source.enabled:
204
+ self.logger.warning(f"Source is disabled: {source_id}")
205
+ return {"synced": False, "error": "Source is disabled"}
206
+
207
+ self.logger.info(f"Syncing skill source: {source_id} ({source.url})")
208
+
209
+ try:
210
+ # Determine cache path for this source
211
+ cache_path = self._get_source_cache_path(source)
212
+ cache_path.mkdir(parents=True, exist_ok=True)
213
+
214
+ # Recursively sync repository structure
215
+ files_updated, files_cached = self._recursive_sync_repository(
216
+ source, cache_path, force, progress_callback
217
+ )
218
+
219
+ # Discover skills in cache
220
+ discovery_service = SkillDiscoveryService(cache_path)
221
+ discovered_skills = discovery_service.discover_skills()
222
+
223
+ # Build result
224
+ result = {
225
+ "synced": True,
226
+ "files_updated": files_updated,
227
+ "files_cached": files_cached,
228
+ "skills_discovered": len(discovered_skills),
229
+ "timestamp": datetime.now(timezone.utc).isoformat(),
230
+ }
231
+
232
+ self.logger.info(
233
+ f"Sync complete for {source_id}: {result['files_updated']} updated, "
234
+ f"{result['skills_discovered']} skills discovered"
235
+ )
236
+
237
+ return result
238
+
239
+ except Exception as e:
240
+ self.logger.error(f"Failed to sync source {source_id}: {e}")
241
+ return {
242
+ "synced": False,
243
+ "error": str(e),
244
+ "timestamp": datetime.now(timezone.utc).isoformat(),
245
+ }
246
+
247
+ def get_all_skills(self) -> List[Dict[str, Any]]:
248
+ """Get all skills from all sources with priority resolution.
249
+
250
+ Returns:
251
+ List of resolved skill dicts, each containing:
252
+ {
253
+ "skill_id": str,
254
+ "name": str,
255
+ "description": str,
256
+ "version": str,
257
+ "tags": List[str],
258
+ "agent_types": List[str],
259
+ "content": str,
260
+ "source_id": str,
261
+ "source_priority": int,
262
+ "source_file": str
263
+ }
264
+
265
+ Priority Resolution Algorithm:
266
+ 1. Load skills from all enabled sources
267
+ 2. Group by skill ID (name converted to ID)
268
+ 3. For each group, select skill with lowest priority
269
+ 4. Return deduplicated skill list
270
+
271
+ Example:
272
+ >>> manager = GitSkillSourceManager(config)
273
+ >>> skills = manager.get_all_skills()
274
+ >>> for skill in skills:
275
+ ... print(f"{skill['name']} from {skill['source_id']}")
276
+ """
277
+ sources = self.config.get_enabled_sources()
278
+
279
+ if not sources:
280
+ self.logger.warning("No enabled sources found")
281
+ return []
282
+
283
+ # Collect skills from all sources
284
+ skills_by_source = {}
285
+
286
+ for source in sources:
287
+ try:
288
+ cache_path = self._get_source_cache_path(source)
289
+ if not cache_path.exists():
290
+ self.logger.debug(f"Cache not found for source: {source.id}")
291
+ continue
292
+
293
+ discovery_service = SkillDiscoveryService(cache_path)
294
+ source_skills = discovery_service.discover_skills()
295
+
296
+ # Tag skills with source metadata
297
+ for skill in source_skills:
298
+ skill["source_id"] = source.id
299
+ skill["source_priority"] = source.priority
300
+
301
+ skills_by_source[source.id] = source_skills
302
+
303
+ except Exception as e:
304
+ self.logger.warning(f"Failed to discover skills from {source.id}: {e}")
305
+ continue
306
+
307
+ # Apply priority resolution
308
+ resolved_skills = self._apply_priority_resolution(skills_by_source)
309
+
310
+ self.logger.info(
311
+ f"Discovered {len(resolved_skills)} skills from {len(skills_by_source)} sources"
312
+ )
313
+
314
+ return resolved_skills
315
+
316
+ def get_skills_by_source(self, source_id: str) -> List[Dict[str, Any]]:
317
+ """Get skills from a specific source.
318
+
319
+ Args:
320
+ source_id: ID of source to query
321
+
322
+ Returns:
323
+ List of skill dicts from that source
324
+
325
+ Example:
326
+ >>> manager = GitSkillSourceManager(config)
327
+ >>> skills = manager.get_skills_by_source("system")
328
+ >>> print(f"Found {len(skills)} system skills")
329
+ """
330
+ source = self.config.get_source(source_id)
331
+ if not source:
332
+ self.logger.warning(f"Source not found: {source_id}")
333
+ return []
334
+
335
+ cache_path = self._get_source_cache_path(source)
336
+ if not cache_path.exists():
337
+ self.logger.debug(f"Cache not found for source: {source_id}")
338
+ return []
339
+
340
+ try:
341
+ discovery_service = SkillDiscoveryService(cache_path)
342
+ skills = discovery_service.discover_skills()
343
+
344
+ # Tag with source metadata
345
+ for skill in skills:
346
+ skill["source_id"] = source.id
347
+ skill["source_priority"] = source.priority
348
+
349
+ return skills
350
+
351
+ except Exception as e:
352
+ self.logger.error(f"Failed to discover skills from {source_id}: {e}")
353
+ return []
354
+
355
+ def _apply_priority_resolution(
356
+ self, skills_by_source: Dict[str, List[Dict[str, Any]]]
357
+ ) -> List[Dict[str, Any]]:
358
+ """Apply priority resolution to skill list.
359
+
360
+ Args:
361
+ skills_by_source: Dict mapping source_id to skill list
362
+
363
+ Returns:
364
+ Deduplicated skill list with priority resolution applied
365
+
366
+ Resolution Strategy:
367
+ - Group skills by skill_id
368
+ - For each group, select skill from source with lowest priority
369
+ - If multiple skills have same priority, use first encountered
370
+
371
+ Example:
372
+ skills_by_source = {
373
+ "system": [{"skill_id": "review", "source_priority": 0}],
374
+ "custom": [{"skill_id": "review", "source_priority": 100}]
375
+ }
376
+ # Returns: skill from "system" (priority 0 < 100)
377
+ """
378
+ # Flatten skills from all sources
379
+ all_skills = []
380
+ for skills in skills_by_source.values():
381
+ all_skills.extend(skills)
382
+
383
+ if not all_skills:
384
+ return []
385
+
386
+ # Group by skill_id
387
+ skills_by_id: Dict[str, List[Dict[str, Any]]] = {}
388
+ for skill in all_skills:
389
+ skill_id = skill.get("skill_id", skill.get("name", "unknown"))
390
+ if skill_id not in skills_by_id:
391
+ skills_by_id[skill_id] = []
392
+ skills_by_id[skill_id].append(skill)
393
+
394
+ # Select skill with lowest priority for each group
395
+ resolved_skills = []
396
+ for skill_id, skill_group in skills_by_id.items():
397
+ # Sort by priority (ascending), take first
398
+ skill_group_sorted = sorted(
399
+ skill_group, key=lambda s: s.get("source_priority", 999)
400
+ )
401
+ selected_skill = skill_group_sorted[0]
402
+
403
+ # Log if multiple versions exist
404
+ if len(skill_group) > 1:
405
+ sources = [s.get("source_id") for s in skill_group]
406
+ self.logger.debug(
407
+ f"Skill '{skill_id}' found in multiple sources {sources}, "
408
+ f"using source '{selected_skill.get('source_id')}'"
409
+ )
410
+
411
+ resolved_skills.append(selected_skill)
412
+
413
+ return resolved_skills
414
+
415
+ def _recursive_sync_repository(
416
+ self,
417
+ source: SkillSource,
418
+ cache_path: Path,
419
+ force: bool = False,
420
+ progress_callback=None,
421
+ ) -> Tuple[int, int]:
422
+ """Recursively sync entire GitHub repository structure to cache.
423
+
424
+ Design Decision: Two-phase sync architecture (Phase 2 refactoring)
425
+
426
+ Rationale: Separates syncing (to cache) from deployment (to project).
427
+ Phase 1: Download ALL repository files to cache with Git Tree API
428
+ Phase 2: Deploy selected skills from cache to project-specific locations
429
+
430
+ This refactoring follows the agent sync pattern (git_source_sync_service.py)
431
+ with cache-first architecture for multi-project support.
432
+
433
+ Trade-offs:
434
+ - Storage: 2x disk usage (cache + deployments) vs. direct deployment
435
+ - Performance: Copy operation adds ~10ms, but enables offline deployment
436
+ - Flexibility: Multiple projects can deploy from single cache
437
+ - Isolation: Projects have independent skill sets from shared cache
438
+
439
+ Args:
440
+ source: SkillSource configuration
441
+ cache_path: Local cache directory (structure preserved)
442
+ force: Force re-download even if ETag cached
443
+ progress_callback: Optional callback(absolute_position: int) for progress tracking
444
+
445
+ Returns:
446
+ Tuple of (files_updated, files_cached)
447
+
448
+ Algorithm:
449
+ 1. Parse GitHub URL to extract owner/repo
450
+ 2. Discover ALL files via Git Tree API (recursive=1, single request)
451
+ 3. Filter for relevant files (.md, .json, .gitignore)
452
+ 4. Download each file to cache with ETag caching
453
+ 5. Call progress_callback with ABSOLUTE position (not increment)
454
+ 6. Preserve nested directory structure in cache
455
+
456
+ Error Handling:
457
+ - Invalid GitHub URL: Raises ValueError
458
+ - Tree API failure: Returns 0, 0 (logged as warning)
459
+ - Individual file failures: Logged but don't stop sync
460
+ """
461
+ # Parse GitHub URL
462
+ url_parts = source.url.rstrip("/").replace(".git", "").split("github.com/")
463
+ if len(url_parts) != 2:
464
+ raise ValueError(f"Invalid GitHub URL: {source.url}")
465
+
466
+ repo_path = url_parts[1].strip("/")
467
+ owner_repo = "/".join(repo_path.split("/")[:2])
468
+
469
+ # Step 1: Discover all files via GitHub Tree API (single request)
470
+ # This discovers the COMPLETE repository structure (272 files for skills)
471
+ all_files = self._discover_repository_files_via_tree_api(
472
+ owner_repo, source.branch
473
+ )
474
+
475
+ if not all_files:
476
+ self.logger.warning(f"No files discovered in repository: {source.url}")
477
+ return 0, 0
478
+
479
+ self.logger.info(
480
+ f"Discovered {len(all_files)} files in {owner_repo}/{source.branch} via Tree API"
481
+ )
482
+
483
+ # Step 2: Filter to only download relevant files (markdown, JSON metadata)
484
+ relevant_files = [
485
+ f
486
+ for f in all_files
487
+ if f.endswith(".md") or f.endswith(".json") or f == ".gitignore"
488
+ ]
489
+
490
+ self.logger.info(
491
+ f"Filtered to {len(relevant_files)} relevant files (.md, .json, .gitignore)"
492
+ )
493
+
494
+ # Step 3: Download files to cache with ETag caching (parallel)
495
+ files_updated = 0
496
+ files_cached = 0
497
+
498
+ # Use ThreadPoolExecutor for parallel downloads (10 workers for optimal performance)
499
+ # Trade-off: 10 workers balances speed (306 files in ~3-5s) vs. GitHub rate limits
500
+ with ThreadPoolExecutor(max_workers=10) as executor:
501
+ # Submit all download tasks
502
+ future_to_file = {}
503
+ for file_path in relevant_files:
504
+ raw_url = f"https://raw.githubusercontent.com/{owner_repo}/{source.branch}/{file_path}"
505
+ cache_file = cache_path / file_path
506
+ future = executor.submit(
507
+ self._download_file_with_etag, raw_url, cache_file, force
508
+ )
509
+ future_to_file[future] = file_path
510
+
511
+ # Process completed downloads as they finish
512
+ completed = 0
513
+ for future in as_completed(future_to_file):
514
+ completed += 1
515
+ try:
516
+ updated = future.result()
517
+ if updated:
518
+ files_updated += 1
519
+ else:
520
+ files_cached += 1
521
+ except Exception as e:
522
+ file_path = future_to_file[future]
523
+ self.logger.warning(f"Failed to download {file_path}: {e}")
524
+
525
+ # Call progress callback with ABSOLUTE position
526
+ if progress_callback:
527
+ progress_callback(completed)
528
+
529
+ self.logger.info(
530
+ f"Repository sync complete: {files_updated} updated, "
531
+ f"{files_cached} cached from {len(relevant_files)} files"
532
+ )
533
+ return files_updated, files_cached
534
+
535
+ def _discover_repository_files_via_tree_api(
536
+ self, owner_repo: str, branch: str
537
+ ) -> List[str]:
538
+ """Discover all files in repository using GitHub Git Tree API.
539
+
540
+ Design Decision: Two-step Tree API pattern (Phase 2 refactoring)
541
+
542
+ Rationale: Git Tree API with recursive=1 discovers entire repository
543
+ structure in a SINGLE request, solving the "limited file discovery" issue.
544
+ This is the same pattern used successfully in agent sync (Phase 1).
545
+
546
+ Previous Issue: Contents API only showed top-level files, missing nested
547
+ directories. This caused skills sync to discover only 1-2 files instead
548
+ of 272 files in the repository.
549
+
550
+ Trade-offs:
551
+ - Performance: Single API call vs. 50+ recursive Contents API calls
552
+ - Rate Limiting: 1 request vs. dozens (avoids 403 rate limit errors)
553
+ - Discovery: Finds ALL 272 files in nested structure
554
+ - API Complexity: Requires commit SHA lookup before tree fetch
555
+
556
+ Algorithm (matches agents pattern from git_source_sync_service.py):
557
+ 1. GET /repos/{owner}/{repo}/git/refs/heads/{branch} → commit SHA
558
+ 2. GET /repos/{owner}/{repo}/git/trees/{sha}?recursive=1 → all files
559
+ 3. Filter for blobs (files), exclude trees (directories)
560
+ 4. Return complete file list
561
+
562
+ Args:
563
+ owner_repo: GitHub owner/repo (e.g., "bobmatnyc/claude-mpm-skills")
564
+ branch: Branch name (e.g., "main")
565
+
566
+ Returns:
567
+ List of all file paths in repository
568
+ (e.g., ["collections/toolchains/python/pytest.md", ...])
569
+
570
+ Error Handling:
571
+ - HTTP 404: Branch or repo not found, raises RequestException
572
+ - HTTP 403: Rate limit exceeded (warns about GITHUB_TOKEN)
573
+ - Timeout: 30 second timeout per request
574
+ - Empty tree: Returns empty list (logged as warning)
575
+
576
+ Performance:
577
+ - Expected: ~500-800ms for 272 files (2 API calls)
578
+ - Rate Limit: Consumes 2 API calls per sync
579
+ - Scalability: Handles 1000s of files without truncation
580
+
581
+ Example:
582
+ >>> files = self._discover_repository_files_via_tree_api(
583
+ ... "bobmatnyc/claude-mpm-skills", "main"
584
+ ... )
585
+ >>> print(len(files))
586
+ 272 # Complete repository (not just top-level)
587
+ """
588
+ import requests
589
+
590
+ all_files = []
591
+
592
+ try:
593
+ # Step 1: Get the latest commit SHA for the branch
594
+ refs_url = (
595
+ f"https://api.github.com/repos/{owner_repo}/git/refs/heads/{branch}"
596
+ )
597
+ self.logger.debug(f"Fetching commit SHA from {refs_url}")
598
+
599
+ refs_response = requests.get(
600
+ refs_url, headers={"Accept": "application/vnd.github+json"}, timeout=30
601
+ )
602
+
603
+ # Check for rate limiting
604
+ if refs_response.status_code == 403:
605
+ self.logger.warning(
606
+ "GitHub API rate limit exceeded (HTTP 403). "
607
+ "Consider setting GITHUB_TOKEN environment variable for higher limits."
608
+ )
609
+ raise requests.RequestException("Rate limit exceeded")
610
+
611
+ refs_response.raise_for_status()
612
+ commit_sha = refs_response.json()["object"]["sha"]
613
+ self.logger.debug(f"Resolved {branch} to commit {commit_sha[:8]}")
614
+
615
+ # Step 2: Get the tree for that commit (recursive=1 gets ALL files)
616
+ tree_url = (
617
+ f"https://api.github.com/repos/{owner_repo}/git/trees/{commit_sha}"
618
+ )
619
+ params = {"recursive": "1"} # Recursively get entire tree
620
+
621
+ self.logger.debug(f"Fetching recursive tree from {tree_url}")
622
+ tree_response = requests.get(
623
+ tree_url,
624
+ headers={"Accept": "application/vnd.github+json"},
625
+ params=params,
626
+ timeout=30,
627
+ )
628
+ tree_response.raise_for_status()
629
+
630
+ tree_data = tree_response.json()
631
+ all_items = tree_data.get("tree", [])
632
+
633
+ self.logger.debug(f"Tree API returned {len(all_items)} total items")
634
+
635
+ # Step 3: Extract file paths (filter out directories)
636
+ for item in all_items:
637
+ if item["type"] == "blob": # blob = file, tree = directory
638
+ all_files.append(item["path"])
639
+
640
+ self.logger.info(
641
+ f"Discovered {len(all_files)} files via Tree API in {owner_repo}/{branch}"
642
+ )
643
+
644
+ except requests.exceptions.RequestException as e:
645
+ self.logger.error(f"Failed to discover files via Tree API: {e}")
646
+ # Fall back to empty list (sync will fail gracefully)
647
+ return []
648
+ except (KeyError, ValueError) as e:
649
+ self.logger.error(f"Error parsing GitHub API response: {e}")
650
+ return []
651
+
652
+ return all_files
653
+
654
+ def _download_file_with_etag(
655
+ self, url: str, local_path: Path, force: bool = False
656
+ ) -> bool:
657
+ """Download file from URL with ETag caching (thread-safe).
658
+
659
+ Args:
660
+ url: Raw GitHub URL
661
+ local_path: Local file path to save to
662
+ force: Force download even if cached
663
+
664
+ Returns:
665
+ True if file was updated, False if cached
666
+ """
667
+
668
+ import json
669
+
670
+ import requests
671
+
672
+ # Create parent directory (thread-safe with exist_ok=True)
673
+ local_path.parent.mkdir(parents=True, exist_ok=True)
674
+
675
+ # Thread-safe ETag cache operations
676
+ etag_cache_file = local_path.parent / ".etag_cache.json"
677
+
678
+ # Read cached ETag (lock required for file read)
679
+ with self._etag_cache_lock:
680
+ etag_cache = {}
681
+ if etag_cache_file.exists():
682
+ try:
683
+ with open(etag_cache_file, encoding="utf-8") as f:
684
+ etag_cache = json.load(f)
685
+ except Exception:
686
+ pass
687
+
688
+ cached_etag = etag_cache.get(str(local_path))
689
+
690
+ # Make conditional request (no lock needed - independent HTTP call)
691
+ headers = {}
692
+ if cached_etag and not force:
693
+ headers["If-None-Match"] = cached_etag
694
+
695
+ try:
696
+ response = requests.get(url, headers=headers, timeout=30)
697
+
698
+ # 304 Not Modified - use cached version
699
+ if response.status_code == 304:
700
+ self.logger.debug(f"Cache hit (ETag match): {local_path.name}")
701
+ return False
702
+
703
+ response.raise_for_status()
704
+
705
+ # Download and save file (no lock needed - independent file write)
706
+ local_path.write_bytes(response.content)
707
+
708
+ # Save new ETag (lock required for cache file write)
709
+ if "ETag" in response.headers:
710
+ with self._etag_cache_lock:
711
+ # Re-read cache in case other threads updated it
712
+ if etag_cache_file.exists():
713
+ try:
714
+ with open(etag_cache_file, encoding="utf-8") as f:
715
+ etag_cache = json.load(f)
716
+ except Exception:
717
+ etag_cache = {}
718
+
719
+ etag_cache[str(local_path)] = response.headers["ETag"]
720
+ with open(etag_cache_file, "w", encoding="utf-8") as f:
721
+ json.dump(etag_cache, f, indent=2)
722
+
723
+ self.logger.debug(f"Downloaded: {local_path.name}")
724
+ return True
725
+
726
+ except requests.exceptions.RequestException as e:
727
+ self.logger.warning(f"Failed to download {url}: {e}")
728
+ return False
729
+
730
+ def _build_raw_github_url(self, source: SkillSource) -> str:
731
+ """Build raw GitHub URL for source.
732
+
733
+ Args:
734
+ source: SkillSource instance
735
+
736
+ Returns:
737
+ Raw GitHub content URL
738
+
739
+ Example:
740
+ >>> source = SkillSource(
741
+ ... id="system",
742
+ ... url="https://github.com/owner/repo",
743
+ ... branch="main"
744
+ ... )
745
+ >>> url = manager._build_raw_github_url(source)
746
+ >>> print(url)
747
+ 'https://raw.githubusercontent.com/owner/repo/main'
748
+ """
749
+ # Parse GitHub URL to extract owner/repo
750
+ url = source.url.rstrip("/")
751
+ if url.endswith(".git"):
752
+ url = url[:-4]
753
+
754
+ # Extract path components
755
+ parts = url.split("github.com/")
756
+ if len(parts) != 2:
757
+ raise ValueError(f"Invalid GitHub URL: {source.url}")
758
+
759
+ repo_path = parts[1].strip("/")
760
+ owner_repo = "/".join(repo_path.split("/")[:2])
761
+
762
+ return f"https://raw.githubusercontent.com/{owner_repo}/{source.branch}"
763
+
764
+ def _get_source_cache_path(self, source: SkillSource) -> Path:
765
+ """Get cache directory path for a source.
766
+
767
+ Args:
768
+ source: SkillSource instance
769
+
770
+ Returns:
771
+ Absolute path to cache directory
772
+
773
+ Cache Structure:
774
+ ~/.claude-mpm/cache/skills/{source_id}/
775
+
776
+ Example:
777
+ >>> source = SkillSource(id="system", ...)
778
+ >>> path = manager._get_source_cache_path(source)
779
+ >>> print(path)
780
+ Path('/Users/user/.claude-mpm/cache/skills/system')
781
+ """
782
+ return self.cache_dir / source.id
783
+
784
+ def deploy_skills_to_project(
785
+ self,
786
+ project_dir: Path,
787
+ skill_list: Optional[List[str]] = None,
788
+ force: bool = False,
789
+ ) -> Dict[str, Any]:
790
+ """Deploy skills from cache to project directory (Phase 2 deployment).
791
+
792
+ Design Decision: Deploy from cache to project-specific directory
793
+
794
+ Rationale: Follows agent deployment pattern (git_source_sync_service.py).
795
+ Separates sync (cache) from deployment (project), enabling:
796
+ - Multiple projects using same cached skills
797
+ - Offline deployment from cache
798
+ - Project-specific skill selection
799
+ - Consistent two-phase architecture
800
+
801
+ This complements deploy_skills() which deploys to global ~/.claude/skills/.
802
+ This method deploys to project-local .claude-mpm/skills/ for project-specific
803
+ skill management.
804
+
805
+ Trade-offs:
806
+ - Storage: 2x disk (cache + project deployments)
807
+ - Performance: Copy ~10ms for 50 skills (negligible)
808
+ - Flexibility: Project-specific skill sets from shared cache
809
+ - Isolation: Projects don't affect each other
810
+
811
+ Args:
812
+ project_dir: Project root directory (e.g., /path/to/myproject)
813
+ skill_list: Optional list of skill names to deploy (deploys all if None)
814
+ force: Force redeployment even if up-to-date
815
+
816
+ Returns:
817
+ Dictionary with deployment results:
818
+ {
819
+ "deployed": ["skill1"], # Newly deployed
820
+ "updated": ["skill2"], # Updated existing
821
+ "skipped": ["skill3"], # Already up-to-date
822
+ "failed": [], # Copy failures
823
+ "deployment_dir": "/path/.claude-mpm/skills"
824
+ }
825
+
826
+ Algorithm:
827
+ 1. Create .claude-mpm/skills/ in project directory
828
+ 2. Get all skills from cache (or use provided list)
829
+ 3. For each skill:
830
+ a. Check if cache file exists
831
+ b. Flatten nested path to deployment name
832
+ c. Compare modification times (skip if up-to-date)
833
+ d. Copy from cache to project
834
+ e. Track result (deployed/updated/skipped/failed)
835
+ 4. Return deployment statistics
836
+
837
+ Error Handling:
838
+ - Missing cache files: Logged and added to "failed"
839
+ - Permission errors: Individual failures don't stop deployment
840
+ - Path validation: Security check prevents directory traversal
841
+
842
+ Example:
843
+ >>> manager = GitSkillSourceManager(config)
844
+ >>> manager.sync_all_sources() # Sync to cache first
845
+ >>> result = manager.deploy_skills_to_project(Path("/my/project"))
846
+ >>> print(f"Deployed {len(result['deployed'])} skills")
847
+ """
848
+ import shutil
849
+
850
+ deployment_dir = project_dir / ".claude-mpm" / "skills"
851
+
852
+ # Try to create deployment directory
853
+ try:
854
+ deployment_dir.mkdir(parents=True, exist_ok=True)
855
+ except PermissionError as e:
856
+ self.logger.error(f"Permission denied creating deployment directory: {e}")
857
+ return {
858
+ "deployed": [],
859
+ "deployed_count": 0,
860
+ "updated": [],
861
+ "updated_count": 0,
862
+ "skipped": [],
863
+ "skipped_count": 0,
864
+ "failed": [],
865
+ "failed_count": 0,
866
+ "deployment_dir": str(deployment_dir),
867
+ }
868
+
869
+ results = {
870
+ "deployed": [],
871
+ "updated": [],
872
+ "skipped": [],
873
+ "failed": [],
874
+ "deployment_dir": str(deployment_dir),
875
+ }
876
+
877
+ # Get all skills from cache or use provided list
878
+ if skill_list is None:
879
+ all_skills = self.get_all_skills()
880
+ else:
881
+ # Filter skills by provided list
882
+ all_skills = [
883
+ s for s in self.get_all_skills() if s.get("name") in skill_list
884
+ ]
885
+
886
+ self.logger.info(
887
+ f"Deploying {len(all_skills)} skills from cache to {deployment_dir}"
888
+ )
889
+
890
+ for skill in all_skills:
891
+ skill_name = skill.get("name", "unknown")
892
+ deployment_name = skill.get("deployment_name")
893
+ source_file = skill.get("source_file")
894
+
895
+ if not deployment_name or not source_file:
896
+ self.logger.warning(
897
+ f"Skill {skill_name} missing deployment_name or source_file, skipping"
898
+ )
899
+ results["failed"].append(skill_name)
900
+ continue
901
+
902
+ try:
903
+ source_path = Path(source_file)
904
+ if not source_path.exists():
905
+ self.logger.warning(f"Cache file not found: {source_file}")
906
+ results["failed"].append(skill_name)
907
+ continue
908
+
909
+ # Source is the entire skill directory (not just SKILL.md)
910
+ source_dir = source_path.parent
911
+ target_skill_dir = deployment_dir / deployment_name
912
+
913
+ # Check if already deployed and up-to-date
914
+ should_deploy = force
915
+ was_existing = target_skill_dir.exists()
916
+
917
+ if not force and was_existing:
918
+ # Compare modification times of SKILL.md files
919
+ source_mtime = source_path.stat().st_mtime
920
+ target_file = target_skill_dir / "SKILL.md"
921
+ if target_file.exists():
922
+ target_mtime = target_file.stat().st_mtime
923
+ should_deploy = source_mtime > target_mtime
924
+ else:
925
+ should_deploy = True
926
+
927
+ if not should_deploy and was_existing:
928
+ results["skipped"].append(deployment_name)
929
+ self.logger.debug(f"Skipped (up-to-date): {deployment_name}")
930
+ continue
931
+
932
+ # Security: Validate paths
933
+ if not self._validate_safe_path(deployment_dir, target_skill_dir):
934
+ self.logger.error(f"Invalid target path: {target_skill_dir}")
935
+ results["failed"].append(skill_name)
936
+ continue
937
+
938
+ # Remove existing if force or updating
939
+ if target_skill_dir.exists():
940
+ if target_skill_dir.is_symlink():
941
+ self.logger.warning(f"Removing symlink: {target_skill_dir}")
942
+ target_skill_dir.unlink()
943
+ else:
944
+ shutil.rmtree(target_skill_dir)
945
+
946
+ # Copy entire skill directory from cache
947
+ shutil.copytree(source_dir, target_skill_dir)
948
+
949
+ # Track result
950
+ if was_existing:
951
+ results["updated"].append(deployment_name)
952
+ self.logger.info(f"Updated: {deployment_name}")
953
+ else:
954
+ results["deployed"].append(deployment_name)
955
+ self.logger.info(f"Deployed: {deployment_name}")
956
+
957
+ except PermissionError as e:
958
+ self.logger.error(f"Permission denied deploying {skill_name}: {e}")
959
+ results["failed"].append(skill_name)
960
+ except OSError as e:
961
+ self.logger.error(f"IO error deploying {skill_name}: {e}")
962
+ results["failed"].append(skill_name)
963
+ except Exception as e:
964
+ self.logger.error(f"Unexpected error deploying {skill_name}: {e}")
965
+ results["failed"].append(skill_name)
966
+
967
+ # Log summary
968
+ total_success = len(results["deployed"]) + len(results["updated"])
969
+ self.logger.info(
970
+ f"Deployment complete: {total_success} deployed/updated, "
971
+ f"{len(results['skipped'])} skipped, {len(results['failed'])} failed"
972
+ )
973
+
974
+ # Return format matching agents deployment pattern
975
+ return {
976
+ "deployed": results["deployed"],
977
+ "deployed_count": len(results["deployed"]),
978
+ "updated": results["updated"],
979
+ "updated_count": len(results["updated"]),
980
+ "skipped": results["skipped"],
981
+ "skipped_count": len(results["skipped"]),
982
+ "failed": results["failed"],
983
+ "failed_count": len(results["failed"]),
984
+ "deployment_dir": results["deployment_dir"],
985
+ }
986
+
987
+ def deploy_skills(
988
+ self,
989
+ target_dir: Optional[Path] = None,
990
+ force: bool = False,
991
+ progress_callback=None,
992
+ skill_filter: Optional[Set[str]] = None,
993
+ ) -> Dict[str, Any]:
994
+ """Deploy skills from cache to target directory with flat structure and automatic cleanup.
995
+
996
+ Flattens nested Git repository structure into Claude Code compatible
997
+ flat directory structure. Each skill directory is copied with a
998
+ hyphen-separated name derived from its path.
999
+
1000
+ CRITICAL: When skill_filter is provided (agent-referenced skills), this function:
1001
+ 1. Deploys ONLY the filtered skills
1002
+ 2. REMOVES orphaned skills (deployed but not in filter)
1003
+ 3. Returns removed_count and removed_skills in result
1004
+
1005
+ Transformation Example:
1006
+ Cache: collaboration/dispatching-parallel-agents/SKILL.md
1007
+ Deploy: collaboration-dispatching-parallel-agents/SKILL.md
1008
+
1009
+ Args:
1010
+ target_dir: Target deployment directory (default: ~/.claude/skills/)
1011
+ force: Overwrite existing skills
1012
+ progress_callback: Optional callback(increment: int) called for each skill deployed
1013
+ skill_filter: Optional set of skill names to deploy (selective deployment).
1014
+ If None, deploys ALL skills WITHOUT cleanup.
1015
+ If provided, deploys ONLY filtered skills AND removes orphans.
1016
+
1017
+ Returns:
1018
+ Dict with deployment results:
1019
+ {
1020
+ "deployed_count": int,
1021
+ "skipped_count": int,
1022
+ "failed_count": int,
1023
+ "deployed_skills": List[str],
1024
+ "skipped_skills": List[str],
1025
+ "errors": List[str],
1026
+ "filtered_count": int, # Number of skills filtered out
1027
+ "removed_count": int, # Number of orphaned skills removed
1028
+ "removed_skills": List[str] # Names of removed orphaned skills
1029
+ }
1030
+
1031
+ Example:
1032
+ >>> manager = GitSkillSourceManager(config)
1033
+ >>> result = manager.deploy_skills()
1034
+ >>> print(f"Deployed {result['deployed_count']} skills")
1035
+
1036
+ # Selective deployment based on agent requirements (with cleanup):
1037
+ >>> required = {"typescript-core", "react-patterns"}
1038
+ >>> result = manager.deploy_skills(skill_filter=required)
1039
+ >>> print(f"Deployed {result['deployed_count']}, removed {result['removed_count']} orphans")
1040
+ """
1041
+ if target_dir is None:
1042
+ target_dir = Path.home() / ".claude" / "skills"
1043
+
1044
+ target_dir.mkdir(parents=True, exist_ok=True)
1045
+
1046
+ deployed = []
1047
+ skipped = []
1048
+ errors = []
1049
+ filtered_count = 0
1050
+ removed_skills = [] # Track removed orphaned skills
1051
+
1052
+ # Get all skills from all sources
1053
+ all_skills = self.get_all_skills()
1054
+
1055
+ # Apply skill filter if provided (selective deployment)
1056
+ if skill_filter is not None:
1057
+ original_count = len(all_skills)
1058
+ # Normalize filter to lowercase for case-insensitive matching
1059
+ normalized_filter = {s.lower() for s in skill_filter}
1060
+
1061
+ def matches_filter(deployment_name: str) -> bool:
1062
+ """Match using same fuzzy logic as ProfileManager.is_skill_enabled()"""
1063
+ deployment_lower = deployment_name.lower()
1064
+
1065
+ # Exact match
1066
+ if deployment_lower in normalized_filter:
1067
+ return True
1068
+
1069
+ # Fuzzy match: check if deployment name ends with or contains short name
1070
+ # Example: "toolchains-python-frameworks-flask" matches "flask"
1071
+ for short_name in normalized_filter:
1072
+ if deployment_lower.endswith(f"-{short_name}"):
1073
+ return True
1074
+ # Check if short name is contained as a segment
1075
+ if f"-{short_name}-" in deployment_lower:
1076
+ return True
1077
+ if deployment_lower.startswith(f"{short_name}-"):
1078
+ return True
1079
+
1080
+ return False
1081
+
1082
+ # Match against deployment_name using fuzzy matching
1083
+ all_skills = [
1084
+ s for s in all_skills if matches_filter(s.get("deployment_name", ""))
1085
+ ]
1086
+ filtered_count = original_count - len(all_skills)
1087
+ self.logger.info(
1088
+ f"Selective deployment: {len(all_skills)} of {original_count} skills "
1089
+ f"match agent requirements ({filtered_count} filtered out)"
1090
+ )
1091
+
1092
+ # Cleanup: Remove skills from target directory that aren't in the filtered set
1093
+ # This ensures only agent-referenced skills remain deployed
1094
+ removed_skills = self._cleanup_unfiltered_skills(target_dir, all_skills)
1095
+ if removed_skills:
1096
+ self.logger.info(
1097
+ f"Removed {len(removed_skills)} orphaned skills not referenced by agents: {removed_skills[:10]}"
1098
+ + (
1099
+ f" (and {len(removed_skills) - 10} more)"
1100
+ if len(removed_skills) > 10
1101
+ else ""
1102
+ )
1103
+ )
1104
+
1105
+ self.logger.info(
1106
+ f"Deploying {len(all_skills)} skills to {target_dir} (force={force})"
1107
+ )
1108
+
1109
+ for idx, skill in enumerate(all_skills, start=1):
1110
+ skill_name = skill.get("name", "unknown")
1111
+ deployment_name = skill.get("deployment_name")
1112
+
1113
+ if not deployment_name:
1114
+ self.logger.warning(
1115
+ f"Skill {skill_name} missing deployment_name, skipping"
1116
+ )
1117
+ errors.append(f"{skill_name}: Missing deployment_name")
1118
+ if progress_callback:
1119
+ progress_callback(idx)
1120
+ continue
1121
+
1122
+ try:
1123
+ result = self._deploy_single_skill(
1124
+ skill, target_dir, deployment_name, force
1125
+ )
1126
+
1127
+ if result["deployed"]:
1128
+ deployed.append(deployment_name)
1129
+ elif result["skipped"]:
1130
+ skipped.append(deployment_name)
1131
+
1132
+ if result["error"]:
1133
+ errors.append(result["error"])
1134
+
1135
+ except Exception as e:
1136
+ self.logger.error(f"Failed to deploy {skill_name}: {e}")
1137
+ errors.append(f"{skill_name}: {e}")
1138
+
1139
+ # Call progress callback for each skill processed
1140
+ if progress_callback:
1141
+ progress_callback(idx)
1142
+
1143
+ self.logger.info(
1144
+ f"Deployment complete: {len(deployed)} deployed, "
1145
+ f"{len(skipped)} skipped, {len(errors)} errors"
1146
+ + (f", {len(removed_skills)} removed" if removed_skills else "")
1147
+ )
1148
+
1149
+ return {
1150
+ "deployed_count": len(deployed),
1151
+ "skipped_count": len(skipped),
1152
+ "failed_count": len(errors),
1153
+ "deployed_skills": deployed,
1154
+ "skipped_skills": skipped,
1155
+ "errors": errors,
1156
+ "filtered_count": filtered_count,
1157
+ "removed_count": len(removed_skills),
1158
+ "removed_skills": removed_skills,
1159
+ }
1160
+
1161
+ def _cleanup_unfiltered_skills(
1162
+ self, target_dir: Path, filtered_skills: List[Dict[str, Any]]
1163
+ ) -> List[str]:
1164
+ """Remove skills from target directory that aren't in the filtered skill list.
1165
+
1166
+ Uses fuzzy matching to handle both exact deployment names and short skill names.
1167
+ For example:
1168
+ - "toolchains-python-frameworks-flask" (deployed dir) matches "flask" (filter)
1169
+ - "toolchains-elixir-frameworks-phoenix-liveview" matches "phoenix-liveview"
1170
+
1171
+ Args:
1172
+ target_dir: Target deployment directory
1173
+ filtered_skills: List of skills that should remain deployed
1174
+
1175
+ Returns:
1176
+ List of skill names that were removed
1177
+ """
1178
+ import shutil
1179
+
1180
+ removed_skills = []
1181
+
1182
+ # Build set of deployment names (exact matches)
1183
+ expected_deployments = {
1184
+ skill.get("deployment_name").lower()
1185
+ for skill in filtered_skills
1186
+ if skill.get("deployment_name")
1187
+ }
1188
+
1189
+ # Build helper function for fuzzy matching (matches logic from deploy_skills)
1190
+ def should_keep_skill(deployed_dir_name: str) -> bool:
1191
+ """Check if deployed skill matches any expected deployment using fuzzy matching.
1192
+
1193
+ Matches the same logic as matches_filter() in deploy_skills() at line 1053.
1194
+ """
1195
+ deployed_lower = deployed_dir_name.lower()
1196
+
1197
+ # Exact match
1198
+ if deployed_lower in expected_deployments:
1199
+ return True
1200
+
1201
+ # Fuzzy match: check if deployment name matches any short name pattern
1202
+ # Example: "toolchains-elixir-frameworks-phoenix-liveview" matches "phoenix-liveview"
1203
+ for expected_name in expected_deployments:
1204
+ # Suffix match: deployment ends with "-shortname"
1205
+ if deployed_lower.endswith(f"-{expected_name}"):
1206
+ return True
1207
+ # Segment match: "-shortname-" appears in deployment
1208
+ if f"-{expected_name}-" in deployed_lower:
1209
+ return True
1210
+ # Prefix match: deployment starts with "shortname-"
1211
+ if deployed_lower.startswith(f"{expected_name}-"):
1212
+ return True
1213
+
1214
+ return False
1215
+
1216
+ # Check each directory in target_dir
1217
+ if not target_dir.exists():
1218
+ return removed_skills
1219
+
1220
+ try:
1221
+ for item in target_dir.iterdir():
1222
+ # Skip files, only process directories
1223
+ if not item.is_dir():
1224
+ continue
1225
+
1226
+ # Skip hidden directories
1227
+ if item.name.startswith("."):
1228
+ continue
1229
+
1230
+ # Check if this skill directory should be kept (fuzzy matching)
1231
+ if not should_keep_skill(item.name):
1232
+ try:
1233
+ # Security: Validate path is within target_dir
1234
+ if not self._validate_safe_path(target_dir, item):
1235
+ self.logger.error(
1236
+ f"Refusing to remove path outside target directory: {item}"
1237
+ )
1238
+ continue
1239
+
1240
+ # Remove the skill directory
1241
+ if item.is_symlink():
1242
+ item.unlink()
1243
+ else:
1244
+ shutil.rmtree(item)
1245
+
1246
+ removed_skills.append(item.name)
1247
+ self.logger.info(f"Removed orphaned skill: {item.name}")
1248
+
1249
+ except Exception as e:
1250
+ self.logger.warning(
1251
+ f"Failed to remove skill directory {item.name}: {e}"
1252
+ )
1253
+
1254
+ except Exception as e:
1255
+ self.logger.error(f"Error during skill cleanup: {e}")
1256
+
1257
+ return removed_skills
1258
+
1259
+ def _deploy_single_skill(
1260
+ self, skill: Dict[str, Any], target_dir: Path, deployment_name: str, force: bool
1261
+ ) -> Dict[str, Any]:
1262
+ """Deploy a single skill with flattened directory name.
1263
+
1264
+ Args:
1265
+ skill: Skill metadata dict
1266
+ target_dir: Target deployment directory
1267
+ deployment_name: Flattened deployment directory name
1268
+ force: Overwrite if exists
1269
+
1270
+ Returns:
1271
+ Dict with deployed, skipped, error flags
1272
+ """
1273
+ import shutil
1274
+
1275
+ source_file = Path(skill["source_file"])
1276
+ source_dir = source_file.parent
1277
+
1278
+ target_skill_dir = target_dir / deployment_name
1279
+
1280
+ # Check if already deployed
1281
+ if target_skill_dir.exists() and not force:
1282
+ self.logger.debug(f"Skipped {deployment_name} (already exists)")
1283
+ return {"deployed": False, "skipped": True, "error": None}
1284
+
1285
+ # Security: Validate paths
1286
+ if not self._validate_safe_path(target_dir, target_skill_dir):
1287
+ return {
1288
+ "deployed": False,
1289
+ "skipped": False,
1290
+ "error": f"Invalid target path: {target_skill_dir}",
1291
+ }
1292
+
1293
+ try:
1294
+ # Remove existing if force
1295
+ if target_skill_dir.exists():
1296
+ if target_skill_dir.is_symlink():
1297
+ self.logger.warning(f"Removing symlink: {target_skill_dir}")
1298
+ target_skill_dir.unlink()
1299
+ else:
1300
+ shutil.rmtree(target_skill_dir)
1301
+
1302
+ # Copy entire skill directory with all resources
1303
+ shutil.copytree(source_dir, target_skill_dir)
1304
+
1305
+ self.logger.debug(
1306
+ f"Deployed {deployment_name} from {source_dir} to {target_skill_dir}"
1307
+ )
1308
+ return {"deployed": True, "skipped": False, "error": None}
1309
+
1310
+ except Exception as e:
1311
+ return {
1312
+ "deployed": False,
1313
+ "skipped": False,
1314
+ "error": f"{deployment_name}: {e}",
1315
+ }
1316
+
1317
+ def _validate_safe_path(self, base: Path, target: Path) -> bool:
1318
+ """Ensure target path is within base directory (security).
1319
+
1320
+ Args:
1321
+ base: Base directory
1322
+ target: Target path to validate
1323
+
1324
+ Returns:
1325
+ True if path is safe, False otherwise
1326
+ """
1327
+ try:
1328
+ target.resolve().relative_to(base.resolve())
1329
+ return True
1330
+ except ValueError:
1331
+ return False
1332
+
1333
+ def __repr__(self) -> str:
1334
+ """Return string representation."""
1335
+ sources = self.config.load()
1336
+ enabled_count = len([s for s in sources if s.enabled])
1337
+ return (
1338
+ f"GitSkillSourceManager(cache='{self.cache_dir}', "
1339
+ f"sources={len(sources)}, enabled={enabled_count})"
1340
+ )