claude-mpm 4.24.0__py3-none-any.whl → 5.4.41__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 (623) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +4 -0
  3. claude_mpm/agents/BASE_AGENT.md +164 -0
  4. claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +3 -48
  5. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +2002 -0
  6. claude_mpm/agents/MEMORY.md +1 -1
  7. claude_mpm/agents/PM_INSTRUCTIONS.md +735 -925
  8. claude_mpm/agents/WORKFLOW.md +5 -254
  9. claude_mpm/agents/__init__.py +6 -0
  10. claude_mpm/agents/agent_loader.py +14 -48
  11. claude_mpm/agents/base_agent.json +7 -4
  12. claude_mpm/agents/frontmatter_validator.py +71 -3
  13. claude_mpm/agents/templates/circuit-breakers.md +1391 -0
  14. claude_mpm/agents/templates/context-management-examples.md +544 -0
  15. claude_mpm/agents/templates/{pm_red_flags.md → pm-red-flags.md} +48 -0
  16. claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
  17. claude_mpm/agents/templates/research-gate-examples.md +669 -0
  18. claude_mpm/agents/templates/structured-questions-examples.md +615 -0
  19. claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
  20. claude_mpm/agents/templates/ticketing-examples.md +277 -0
  21. claude_mpm/cli/__init__.py +37 -2
  22. claude_mpm/cli/__main__.py +4 -0
  23. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  24. claude_mpm/cli/commands/__init__.py +2 -0
  25. claude_mpm/cli/commands/agent_source.py +774 -0
  26. claude_mpm/cli/commands/agent_state_manager.py +180 -31
  27. claude_mpm/cli/commands/agents.py +1116 -55
  28. claude_mpm/cli/commands/agents_cleanup.py +210 -0
  29. claude_mpm/cli/commands/agents_discover.py +338 -0
  30. claude_mpm/cli/commands/aggregate.py +1 -1
  31. claude_mpm/cli/commands/analyze.py +3 -3
  32. claude_mpm/cli/commands/auto_configure.py +725 -242
  33. claude_mpm/cli/commands/config.py +95 -6
  34. claude_mpm/cli/commands/configure.py +1875 -46
  35. claude_mpm/cli/commands/configure_agent_display.py +29 -10
  36. claude_mpm/cli/commands/configure_navigation.py +63 -46
  37. claude_mpm/cli/commands/debug.py +12 -12
  38. claude_mpm/cli/commands/doctor.py +10 -2
  39. claude_mpm/cli/commands/hook_errors.py +277 -0
  40. claude_mpm/cli/commands/local_deploy.py +1 -4
  41. claude_mpm/cli/commands/mcp_install_commands.py +1 -1
  42. claude_mpm/cli/commands/mpm_init/core.py +229 -2
  43. claude_mpm/cli/commands/mpm_init/git_activity.py +10 -10
  44. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  45. claude_mpm/cli/commands/mpm_init/prompts.py +286 -6
  46. claude_mpm/cli/commands/postmortem.py +401 -0
  47. claude_mpm/cli/commands/profile.py +277 -0
  48. claude_mpm/cli/commands/run.py +123 -165
  49. claude_mpm/cli/commands/skill_source.py +694 -0
  50. claude_mpm/cli/commands/skills.py +782 -20
  51. claude_mpm/cli/commands/summarize.py +413 -0
  52. claude_mpm/cli/executor.py +96 -3
  53. claude_mpm/cli/interactive/agent_wizard.py +1030 -45
  54. claude_mpm/cli/parsers/agent_source_parser.py +171 -0
  55. claude_mpm/cli/parsers/agents_parser.py +307 -10
  56. claude_mpm/cli/parsers/auto_configure_parser.py +13 -138
  57. claude_mpm/cli/parsers/base_parser.py +65 -0
  58. claude_mpm/cli/parsers/config_parser.py +162 -39
  59. claude_mpm/cli/parsers/profile_parser.py +148 -0
  60. claude_mpm/cli/parsers/skill_source_parser.py +169 -0
  61. claude_mpm/cli/parsers/skills_parser.py +146 -0
  62. claude_mpm/cli/parsers/source_parser.py +138 -0
  63. claude_mpm/cli/startup.py +1280 -118
  64. claude_mpm/cli/startup_display.py +480 -0
  65. claude_mpm/cli/utils.py +1 -1
  66. claude_mpm/cli_module/commands.py +1 -1
  67. claude_mpm/commands/mpm-config.md +21 -134
  68. claude_mpm/commands/mpm-doctor.md +16 -20
  69. claude_mpm/commands/mpm-help.md +13 -283
  70. claude_mpm/commands/mpm-init.md +88 -489
  71. claude_mpm/commands/mpm-monitor.md +23 -401
  72. claude_mpm/commands/mpm-organize.md +72 -247
  73. claude_mpm/commands/mpm-postmortem.md +21 -0
  74. claude_mpm/commands/mpm-session-resume.md +30 -0
  75. claude_mpm/commands/mpm-status.md +13 -68
  76. claude_mpm/commands/mpm-ticket-view.md +109 -0
  77. claude_mpm/commands/mpm-version.md +13 -106
  78. claude_mpm/commands/mpm.md +10 -0
  79. claude_mpm/config/agent_presets.py +488 -0
  80. claude_mpm/config/agent_sources.py +352 -0
  81. claude_mpm/config/skill_presets.py +392 -0
  82. claude_mpm/config/skill_sources.py +590 -0
  83. claude_mpm/constants.py +13 -0
  84. claude_mpm/core/claude_runner.py +5 -34
  85. claude_mpm/core/config.py +15 -1
  86. claude_mpm/core/constants.py +1 -1
  87. claude_mpm/core/framework/__init__.py +3 -16
  88. claude_mpm/core/framework/formatters/content_formatter.py +3 -13
  89. claude_mpm/core/framework/loaders/agent_loader.py +8 -5
  90. claude_mpm/core/framework/loaders/file_loader.py +54 -101
  91. claude_mpm/core/framework/loaders/instruction_loader.py +66 -5
  92. claude_mpm/core/framework_loader.py +4 -2
  93. claude_mpm/core/hook_error_memory.py +381 -0
  94. claude_mpm/core/hook_manager.py +41 -2
  95. claude_mpm/core/interactive_session.py +91 -10
  96. claude_mpm/core/logger.py +16 -1
  97. claude_mpm/core/oneshot_session.py +71 -8
  98. claude_mpm/core/optimized_startup.py +59 -0
  99. claude_mpm/core/output_style_manager.py +173 -43
  100. claude_mpm/core/protocols/__init__.py +23 -0
  101. claude_mpm/core/protocols/runner_protocol.py +103 -0
  102. claude_mpm/core/protocols/session_protocol.py +131 -0
  103. claude_mpm/core/shared/config_loader.py +1 -1
  104. claude_mpm/core/shared/singleton_manager.py +11 -4
  105. claude_mpm/core/socketio_pool.py +3 -3
  106. claude_mpm/core/system_context.py +38 -0
  107. claude_mpm/core/unified_agent_registry.py +134 -16
  108. claude_mpm/core/unified_config.py +22 -0
  109. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  110. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +1 -0
  111. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +1 -0
  112. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +1 -0
  113. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +1 -0
  114. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +1 -0
  115. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +2 -0
  116. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DjhvlsAc.js +1 -0
  117. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/N4qtv3Hx.js +2 -0
  118. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uj46x2Wr.js +1 -0
  119. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +2 -0
  120. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +1 -0
  121. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.CAGBuiOw.js +1 -0
  122. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +1 -0
  123. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +10 -0
  124. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  125. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  126. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  127. claude_mpm/experimental/cli_enhancements.py +1 -5
  128. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  129. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  130. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  131. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  132. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  133. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  134. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  135. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  136. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  137. claude_mpm/hooks/claude_hooks/event_handlers.py +214 -79
  138. claude_mpm/hooks/claude_hooks/hook_handler.py +155 -1
  139. claude_mpm/hooks/claude_hooks/installer.py +33 -10
  140. claude_mpm/hooks/claude_hooks/memory_integration.py +28 -0
  141. claude_mpm/hooks/claude_hooks/response_tracking.py +2 -3
  142. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  143. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  144. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  145. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  146. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  147. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  148. claude_mpm/hooks/claude_hooks/services/connection_manager.py +30 -6
  149. claude_mpm/hooks/failure_learning/__init__.py +2 -8
  150. claude_mpm/hooks/failure_learning/failure_detection_hook.py +1 -6
  151. claude_mpm/hooks/failure_learning/fix_detection_hook.py +1 -6
  152. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +1 -6
  153. claude_mpm/hooks/kuzu_response_hook.py +1 -5
  154. claude_mpm/hooks/memory_integration_hook.py +46 -1
  155. claude_mpm/init.py +63 -19
  156. claude_mpm/models/agent_definition.py +7 -0
  157. claude_mpm/models/git_repository.py +198 -0
  158. claude_mpm/scripts/claude-hook-handler.sh +60 -20
  159. claude_mpm/scripts/launch_monitor.py +93 -13
  160. claude_mpm/scripts/start_activity_logging.py +3 -1
  161. claude_mpm/services/agents/agent_builder.py +48 -12
  162. claude_mpm/services/agents/agent_preset_service.py +238 -0
  163. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  164. claude_mpm/services/agents/agent_review_service.py +280 -0
  165. claude_mpm/services/agents/agent_selection_service.py +484 -0
  166. claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
  167. claude_mpm/services/agents/cache_git_manager.py +621 -0
  168. claude_mpm/services/agents/deployment/agent_deployment.py +148 -2
  169. claude_mpm/services/agents/deployment/agent_discovery_service.py +104 -73
  170. claude_mpm/services/agents/deployment/agent_format_converter.py +1 -1
  171. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +1 -5
  172. claude_mpm/services/agents/deployment/agent_metrics_collector.py +3 -3
  173. claude_mpm/services/agents/deployment/agent_restore_handler.py +1 -4
  174. claude_mpm/services/agents/deployment/agent_template_builder.py +238 -15
  175. claude_mpm/services/agents/deployment/agents_directory_resolver.py +101 -15
  176. claude_mpm/services/agents/deployment/async_agent_deployment.py +2 -1
  177. claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -3
  178. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +422 -31
  179. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +2 -2
  180. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +1 -4
  181. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +841 -0
  182. claude_mpm/services/agents/deployment/single_agent_deployer.py +2 -2
  183. claude_mpm/services/agents/deployment/system_instructions_deployer.py +168 -46
  184. claude_mpm/services/agents/deployment/validation/deployment_validator.py +2 -2
  185. claude_mpm/services/agents/git_source_manager.py +663 -0
  186. claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
  187. claude_mpm/services/agents/loading/framework_agent_loader.py +9 -12
  188. claude_mpm/services/agents/local_template_manager.py +50 -10
  189. claude_mpm/services/agents/recommender.py +5 -3
  190. claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
  191. claude_mpm/services/agents/sources/__init__.py +13 -0
  192. claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
  193. claude_mpm/services/agents/sources/git_source_sync_service.py +1094 -0
  194. claude_mpm/services/agents/startup_sync.py +259 -0
  195. claude_mpm/services/agents/toolchain_detector.py +478 -0
  196. claude_mpm/services/analysis/__init__.py +35 -0
  197. claude_mpm/services/analysis/clone_detector.py +1030 -0
  198. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  199. claude_mpm/services/analysis/postmortem_service.py +765 -0
  200. claude_mpm/services/cli/session_pause_manager.py +1 -1
  201. claude_mpm/services/command_deployment_service.py +271 -6
  202. claude_mpm/services/core/base.py +7 -2
  203. claude_mpm/services/core/interfaces/__init__.py +1 -3
  204. claude_mpm/services/core/interfaces/health.py +1 -4
  205. claude_mpm/services/core/models/__init__.py +2 -11
  206. claude_mpm/services/diagnostics/checks/__init__.py +4 -0
  207. claude_mpm/services/diagnostics/checks/agent_check.py +2 -4
  208. claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
  209. claude_mpm/services/diagnostics/checks/instructions_check.py +1 -2
  210. claude_mpm/services/diagnostics/checks/mcp_check.py +0 -1
  211. claude_mpm/services/diagnostics/checks/mcp_services_check.py +7 -15
  212. claude_mpm/services/diagnostics/checks/monitor_check.py +0 -1
  213. claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
  214. claude_mpm/services/diagnostics/diagnostic_runner.py +9 -0
  215. claude_mpm/services/diagnostics/doctor_reporter.py +40 -10
  216. claude_mpm/services/event_bus/config.py +3 -1
  217. claude_mpm/services/event_bus/direct_relay.py +3 -3
  218. claude_mpm/services/events/consumers/logging.py +1 -2
  219. claude_mpm/services/git/__init__.py +21 -0
  220. claude_mpm/services/git/git_operations_service.py +579 -0
  221. claude_mpm/services/github/__init__.py +21 -0
  222. claude_mpm/services/github/github_cli_service.py +397 -0
  223. claude_mpm/services/infrastructure/monitoring/__init__.py +1 -5
  224. claude_mpm/services/infrastructure/monitoring/aggregator.py +1 -6
  225. claude_mpm/services/instructions/__init__.py +9 -0
  226. claude_mpm/services/instructions/instruction_cache_service.py +374 -0
  227. claude_mpm/services/local_ops/__init__.py +3 -13
  228. claude_mpm/services/local_ops/health_checks/__init__.py +1 -3
  229. claude_mpm/services/local_ops/health_manager.py +1 -4
  230. claude_mpm/services/local_ops/resource_monitor.py +1 -1
  231. claude_mpm/services/mcp_config_manager.py +75 -145
  232. claude_mpm/services/mcp_service_verifier.py +6 -3
  233. claude_mpm/services/model/model_router.py +1 -2
  234. claude_mpm/services/monitor/daemon.py +38 -11
  235. claude_mpm/services/monitor/daemon_manager.py +134 -21
  236. claude_mpm/services/monitor/management/lifecycle.py +8 -1
  237. claude_mpm/services/monitor/server.py +700 -24
  238. claude_mpm/services/pm_skills_deployer.py +676 -0
  239. claude_mpm/services/port_manager.py +1 -1
  240. claude_mpm/services/pr/__init__.py +14 -0
  241. claude_mpm/services/pr/pr_template_service.py +329 -0
  242. claude_mpm/services/profile_manager.py +331 -0
  243. claude_mpm/services/project/documentation_manager.py +2 -1
  244. claude_mpm/services/project/project_organizer.py +4 -0
  245. claude_mpm/services/project/toolchain_analyzer.py +3 -1
  246. claude_mpm/services/runner_configuration_service.py +16 -3
  247. claude_mpm/services/self_upgrade_service.py +120 -12
  248. claude_mpm/services/session_management_service.py +16 -4
  249. claude_mpm/services/skills/__init__.py +21 -0
  250. claude_mpm/services/skills/git_skill_source_manager.py +1297 -0
  251. claude_mpm/services/skills/selective_skill_deployer.py +704 -0
  252. claude_mpm/services/skills/skill_discovery_service.py +568 -0
  253. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  254. claude_mpm/services/skills_config.py +547 -0
  255. claude_mpm/services/skills_deployer.py +1072 -0
  256. claude_mpm/services/socketio/dashboard_server.py +1 -0
  257. claude_mpm/services/socketio/event_normalizer.py +51 -6
  258. claude_mpm/services/socketio/handlers/connection.py +1 -1
  259. claude_mpm/services/socketio/handlers/git.py +1 -1
  260. claude_mpm/services/socketio/server/core.py +387 -112
  261. claude_mpm/services/socketio/server/main.py +1 -3
  262. claude_mpm/services/system_instructions_service.py +1 -3
  263. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +0 -3
  264. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +0 -1
  265. claude_mpm/services/unified/deployment_strategies/vercel.py +1 -5
  266. claude_mpm/services/unified/unified_deployment.py +1 -5
  267. claude_mpm/services/version_control/conflict_resolution.py +6 -4
  268. claude_mpm/services/version_control/git_operations.py +103 -0
  269. claude_mpm/services/visualization/__init__.py +1 -5
  270. claude_mpm/services/visualization/mermaid_generator.py +2 -3
  271. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +2 -2
  272. claude_mpm/skills/skill_manager.py +92 -3
  273. claude_mpm/skills/skills_registry.py +0 -1
  274. claude_mpm/templates/questions/__init__.py +38 -0
  275. claude_mpm/templates/questions/base.py +193 -0
  276. claude_mpm/templates/questions/pr_strategy.py +311 -0
  277. claude_mpm/templates/questions/project_init.py +385 -0
  278. claude_mpm/templates/questions/ticket_mgmt.py +394 -0
  279. claude_mpm/tools/__main__.py +8 -8
  280. claude_mpm/utils/agent_dependency_loader.py +91 -12
  281. claude_mpm/utils/agent_filters.py +261 -0
  282. claude_mpm/utils/dependency_cache.py +3 -1
  283. claude_mpm/utils/gitignore.py +244 -0
  284. claude_mpm/utils/migration.py +372 -0
  285. claude_mpm/utils/progress.py +387 -0
  286. claude_mpm/utils/robust_installer.py +49 -7
  287. claude_mpm/utils/structured_questions.py +619 -0
  288. {claude_mpm-4.24.0.dist-info → claude_mpm-5.4.41.dist-info}/METADATA +445 -122
  289. {claude_mpm-4.24.0.dist-info → claude_mpm-5.4.41.dist-info}/RECORD +298 -503
  290. claude_mpm-5.4.41.dist-info/entry_points.txt +5 -0
  291. claude_mpm-5.4.41.dist-info/licenses/LICENSE +94 -0
  292. claude_mpm-5.4.41.dist-info/licenses/LICENSE-FAQ.md +153 -0
  293. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
  294. claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
  295. claude_mpm/agents/BASE_OPS.md +0 -219
  296. claude_mpm/agents/BASE_PM.md +0 -468
  297. claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
  298. claude_mpm/agents/BASE_QA.md +0 -167
  299. claude_mpm/agents/BASE_RESEARCH.md +0 -53
  300. claude_mpm/agents/base_agent_loader.py +0 -626
  301. claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -17
  302. claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +0 -3
  303. claude_mpm/agents/templates/agent-manager.json +0 -273
  304. claude_mpm/agents/templates/agentic-coder-optimizer.json +0 -248
  305. claude_mpm/agents/templates/api_qa.json +0 -183
  306. claude_mpm/agents/templates/circuit_breakers.md +0 -638
  307. claude_mpm/agents/templates/clerk-ops.json +0 -235
  308. claude_mpm/agents/templates/code_analyzer.json +0 -101
  309. claude_mpm/agents/templates/content-agent.json +0 -358
  310. claude_mpm/agents/templates/dart_engineer.json +0 -307
  311. claude_mpm/agents/templates/data_engineer.json +0 -225
  312. claude_mpm/agents/templates/documentation.json +0 -238
  313. claude_mpm/agents/templates/engineer.json +0 -210
  314. claude_mpm/agents/templates/gcp_ops_agent.json +0 -253
  315. claude_mpm/agents/templates/golang_engineer.json +0 -270
  316. claude_mpm/agents/templates/imagemagick.json +0 -264
  317. claude_mpm/agents/templates/java_engineer.json +0 -346
  318. claude_mpm/agents/templates/javascript_engineer_agent.json +0 -380
  319. claude_mpm/agents/templates/local_ops_agent.json +0 -1840
  320. claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +0 -39
  321. claude_mpm/agents/templates/logs/prompts/agent_engineer_20250901_010124_142.md +0 -400
  322. claude_mpm/agents/templates/memory_manager.json +0 -158
  323. claude_mpm/agents/templates/nextjs_engineer.json +0 -285
  324. claude_mpm/agents/templates/ops.json +0 -185
  325. claude_mpm/agents/templates/php-engineer.json +0 -287
  326. claude_mpm/agents/templates/product_owner.json +0 -338
  327. claude_mpm/agents/templates/project_organizer.json +0 -144
  328. claude_mpm/agents/templates/prompt-engineer.json +0 -737
  329. claude_mpm/agents/templates/python_engineer.json +0 -387
  330. claude_mpm/agents/templates/qa.json +0 -243
  331. claude_mpm/agents/templates/react_engineer.json +0 -239
  332. claude_mpm/agents/templates/refactoring_engineer.json +0 -276
  333. claude_mpm/agents/templates/research.json +0 -188
  334. claude_mpm/agents/templates/ruby-engineer.json +0 -280
  335. claude_mpm/agents/templates/rust_engineer.json +0 -275
  336. claude_mpm/agents/templates/security.json +0 -202
  337. claude_mpm/agents/templates/svelte-engineer.json +0 -225
  338. claude_mpm/agents/templates/tauri_engineer.json +0 -274
  339. claude_mpm/agents/templates/ticketing.json +0 -178
  340. claude_mpm/agents/templates/typescript_engineer.json +0 -285
  341. claude_mpm/agents/templates/vercel_ops_agent.json +0 -412
  342. claude_mpm/agents/templates/version_control.json +0 -159
  343. claude_mpm/agents/templates/web_qa.json +0 -400
  344. claude_mpm/agents/templates/web_ui.json +0 -189
  345. claude_mpm/cli/commands/agents_detect.py +0 -380
  346. claude_mpm/cli/commands/agents_recommend.py +0 -309
  347. claude_mpm/cli/ticket_cli.py +0 -35
  348. claude_mpm/commands/mpm-agents-detect.md +0 -168
  349. claude_mpm/commands/mpm-agents-recommend.md +0 -214
  350. claude_mpm/commands/mpm-agents.md +0 -122
  351. claude_mpm/commands/mpm-auto-configure.md +0 -269
  352. claude_mpm/commands/mpm-resume.md +0 -372
  353. claude_mpm/commands/mpm-tickets.md +0 -151
  354. claude_mpm/dashboard/.claude-mpm/socketio-instances.json +0 -1
  355. claude_mpm/dashboard/analysis_runner.py +0 -455
  356. claude_mpm/dashboard/index.html +0 -13
  357. claude_mpm/dashboard/open_dashboard.py +0 -66
  358. claude_mpm/dashboard/react/components/DataInspector/DataInspector.module.css +0 -188
  359. claude_mpm/dashboard/react/components/EventViewer/EventViewer.module.css +0 -156
  360. claude_mpm/dashboard/react/components/shared/ConnectionStatus.module.css +0 -38
  361. claude_mpm/dashboard/react/components/shared/FilterBar.module.css +0 -92
  362. claude_mpm/dashboard/static/archive/activity_dashboard_fixed.html +0 -248
  363. claude_mpm/dashboard/static/archive/activity_dashboard_test.html +0 -61
  364. claude_mpm/dashboard/static/archive/test_activity_connection.html +0 -179
  365. claude_mpm/dashboard/static/archive/test_claude_tree_tab.html +0 -68
  366. claude_mpm/dashboard/static/archive/test_dashboard.html +0 -409
  367. claude_mpm/dashboard/static/archive/test_dashboard_fixed.html +0 -519
  368. claude_mpm/dashboard/static/archive/test_dashboard_verification.html +0 -181
  369. claude_mpm/dashboard/static/archive/test_file_data.html +0 -315
  370. claude_mpm/dashboard/static/archive/test_file_tree_empty_state.html +0 -243
  371. claude_mpm/dashboard/static/archive/test_file_tree_fix.html +0 -234
  372. claude_mpm/dashboard/static/archive/test_file_tree_rename.html +0 -117
  373. claude_mpm/dashboard/static/archive/test_file_tree_tab.html +0 -115
  374. claude_mpm/dashboard/static/archive/test_file_viewer.html +0 -224
  375. claude_mpm/dashboard/static/archive/test_final_activity.html +0 -220
  376. claude_mpm/dashboard/static/archive/test_tab_fix.html +0 -139
  377. claude_mpm/dashboard/static/built/assets/events.DjpNxWNo.css +0 -1
  378. claude_mpm/dashboard/static/built/components/activity-tree.js +0 -2
  379. claude_mpm/dashboard/static/built/components/agent-hierarchy.js +0 -777
  380. claude_mpm/dashboard/static/built/components/agent-inference.js +0 -2
  381. claude_mpm/dashboard/static/built/components/build-tracker.js +0 -333
  382. claude_mpm/dashboard/static/built/components/code-simple.js +0 -857
  383. claude_mpm/dashboard/static/built/components/code-tree/tree-breadcrumb.js +0 -353
  384. claude_mpm/dashboard/static/built/components/code-tree/tree-constants.js +0 -235
  385. claude_mpm/dashboard/static/built/components/code-tree/tree-search.js +0 -409
  386. claude_mpm/dashboard/static/built/components/code-tree/tree-utils.js +0 -435
  387. claude_mpm/dashboard/static/built/components/code-tree.js +0 -2
  388. claude_mpm/dashboard/static/built/components/code-viewer.js +0 -2
  389. claude_mpm/dashboard/static/built/components/connection-debug.js +0 -654
  390. claude_mpm/dashboard/static/built/components/diff-viewer.js +0 -891
  391. claude_mpm/dashboard/static/built/components/event-processor.js +0 -2
  392. claude_mpm/dashboard/static/built/components/event-viewer.js +0 -2
  393. claude_mpm/dashboard/static/built/components/export-manager.js +0 -2
  394. claude_mpm/dashboard/static/built/components/file-change-tracker.js +0 -443
  395. claude_mpm/dashboard/static/built/components/file-change-viewer.js +0 -690
  396. claude_mpm/dashboard/static/built/components/file-tool-tracker.js +0 -2
  397. claude_mpm/dashboard/static/built/components/file-viewer.js +0 -2
  398. claude_mpm/dashboard/static/built/components/hud-library-loader.js +0 -2
  399. claude_mpm/dashboard/static/built/components/hud-manager.js +0 -2
  400. claude_mpm/dashboard/static/built/components/hud-visualizer.js +0 -2
  401. claude_mpm/dashboard/static/built/components/module-viewer.js +0 -2
  402. claude_mpm/dashboard/static/built/components/nav-bar.js +0 -145
  403. claude_mpm/dashboard/static/built/components/page-structure.js +0 -429
  404. claude_mpm/dashboard/static/built/components/session-manager.js +0 -2
  405. claude_mpm/dashboard/static/built/components/socket-manager.js +0 -2
  406. claude_mpm/dashboard/static/built/components/ui-state-manager.js +0 -2
  407. claude_mpm/dashboard/static/built/components/unified-data-viewer.js +0 -2
  408. claude_mpm/dashboard/static/built/components/working-directory.js +0 -2
  409. claude_mpm/dashboard/static/built/connection-manager.js +0 -536
  410. claude_mpm/dashboard/static/built/dashboard.js +0 -2
  411. claude_mpm/dashboard/static/built/extension-error-handler.js +0 -164
  412. claude_mpm/dashboard/static/built/react/events.js +0 -30
  413. claude_mpm/dashboard/static/built/shared/dom-helpers.js +0 -396
  414. claude_mpm/dashboard/static/built/shared/event-bus.js +0 -330
  415. claude_mpm/dashboard/static/built/shared/event-filter-service.js +0 -540
  416. claude_mpm/dashboard/static/built/shared/logger.js +0 -385
  417. claude_mpm/dashboard/static/built/shared/page-structure.js +0 -249
  418. claude_mpm/dashboard/static/built/shared/tooltip-service.js +0 -253
  419. claude_mpm/dashboard/static/built/socket-client.js +0 -2
  420. claude_mpm/dashboard/static/built/tab-isolation-fix.js +0 -185
  421. claude_mpm/dashboard/static/css/activity.css +0 -1958
  422. claude_mpm/dashboard/static/css/connection-status.css +0 -370
  423. claude_mpm/dashboard/static/css/dashboard.css +0 -4701
  424. claude_mpm/dashboard/static/dist/assets/events.DjpNxWNo.css +0 -1
  425. claude_mpm/dashboard/static/dist/components/activity-tree.js +0 -2
  426. claude_mpm/dashboard/static/dist/components/agent-inference.js +0 -2
  427. claude_mpm/dashboard/static/dist/components/code-tree.js +0 -2
  428. claude_mpm/dashboard/static/dist/components/code-viewer.js +0 -2
  429. claude_mpm/dashboard/static/dist/components/event-processor.js +0 -2
  430. claude_mpm/dashboard/static/dist/components/event-viewer.js +0 -2
  431. claude_mpm/dashboard/static/dist/components/export-manager.js +0 -2
  432. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +0 -2
  433. claude_mpm/dashboard/static/dist/components/file-viewer.js +0 -2
  434. claude_mpm/dashboard/static/dist/components/hud-library-loader.js +0 -2
  435. claude_mpm/dashboard/static/dist/components/hud-manager.js +0 -2
  436. claude_mpm/dashboard/static/dist/components/hud-visualizer.js +0 -2
  437. claude_mpm/dashboard/static/dist/components/module-viewer.js +0 -2
  438. claude_mpm/dashboard/static/dist/components/session-manager.js +0 -2
  439. claude_mpm/dashboard/static/dist/components/socket-manager.js +0 -2
  440. claude_mpm/dashboard/static/dist/components/ui-state-manager.js +0 -2
  441. claude_mpm/dashboard/static/dist/components/unified-data-viewer.js +0 -2
  442. claude_mpm/dashboard/static/dist/components/working-directory.js +0 -2
  443. claude_mpm/dashboard/static/dist/dashboard.js +0 -2
  444. claude_mpm/dashboard/static/dist/react/events.js +0 -30
  445. claude_mpm/dashboard/static/dist/socket-client.js +0 -2
  446. claude_mpm/dashboard/static/events.html +0 -607
  447. claude_mpm/dashboard/static/index.html +0 -635
  448. claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
  449. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
  450. claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
  451. claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
  452. claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
  453. claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
  454. claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
  455. claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
  456. claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
  457. claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
  458. claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
  459. claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
  460. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
  461. claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
  462. claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
  463. claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
  464. claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
  465. claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
  466. claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
  467. claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
  468. claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
  469. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
  470. claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
  471. claude_mpm/dashboard/static/js/connection-manager.js +0 -536
  472. claude_mpm/dashboard/static/js/dashboard.js +0 -1896
  473. claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
  474. claude_mpm/dashboard/static/js/shared/dom-helpers.js +0 -396
  475. claude_mpm/dashboard/static/js/shared/event-bus.js +0 -330
  476. claude_mpm/dashboard/static/js/shared/logger.js +0 -385
  477. claude_mpm/dashboard/static/js/shared/tooltip-service.js +0 -253
  478. claude_mpm/dashboard/static/js/socket-client.js +0 -1457
  479. claude_mpm/dashboard/static/js/stores/dashboard-store.js +0 -562
  480. claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
  481. claude_mpm/dashboard/static/legacy/activity.html +0 -736
  482. claude_mpm/dashboard/static/legacy/agents.html +0 -786
  483. claude_mpm/dashboard/static/legacy/files.html +0 -747
  484. claude_mpm/dashboard/static/legacy/tools.html +0 -831
  485. claude_mpm/dashboard/static/monitors.html +0 -431
  486. claude_mpm/dashboard/static/production/events.html +0 -659
  487. claude_mpm/dashboard/static/production/main.html +0 -698
  488. claude_mpm/dashboard/static/production/monitors.html +0 -483
  489. claude_mpm/dashboard/static/socket.io.min.js +0 -7
  490. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
  491. claude_mpm/dashboard/static/test-archive/dashboard.html +0 -635
  492. claude_mpm/dashboard/static/test-archive/debug-events.html +0 -147
  493. claude_mpm/dashboard/static/test-archive/test-navigation.html +0 -256
  494. claude_mpm/dashboard/static/test-archive/test-react-exports.html +0 -180
  495. claude_mpm/dashboard/static/test-archive/test_debug.html +0 -25
  496. claude_mpm/dashboard/templates/code_simple.html +0 -153
  497. claude_mpm/dashboard/templates/index.html +0 -606
  498. claude_mpm/dashboard/test_dashboard.html +0 -372
  499. claude_mpm/scripts/mcp_server.py +0 -75
  500. claude_mpm/scripts/mcp_wrapper.py +0 -39
  501. claude_mpm/services/mcp_gateway/__init__.py +0 -159
  502. claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
  503. claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
  504. claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
  505. claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
  506. claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
  507. claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
  508. claude_mpm/services/mcp_gateway/core/base.py +0 -312
  509. claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
  510. claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
  511. claude_mpm/services/mcp_gateway/core/process_pool.py +0 -971
  512. claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
  513. claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
  514. claude_mpm/services/mcp_gateway/main.py +0 -589
  515. claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
  516. claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
  517. claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
  518. claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
  519. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -419
  520. claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
  521. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -714
  522. claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
  523. claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
  524. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
  525. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
  526. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
  527. claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
  528. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -551
  529. claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
  530. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
  531. claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
  532. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +0 -79
  533. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +0 -178
  534. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +0 -577
  535. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +0 -467
  536. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +0 -537
  537. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +0 -730
  538. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +0 -112
  539. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +0 -146
  540. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +0 -412
  541. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +0 -81
  542. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +0 -362
  543. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +0 -312
  544. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +0 -152
  545. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +0 -668
  546. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +0 -587
  547. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +0 -438
  548. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +0 -391
  549. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +0 -119
  550. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +0 -148
  551. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +0 -483
  552. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +0 -452
  553. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +0 -449
  554. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +0 -411
  555. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +0 -14
  556. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +0 -58
  557. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +0 -68
  558. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +0 -69
  559. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +0 -131
  560. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +0 -325
  561. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +0 -490
  562. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +0 -425
  563. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +0 -499
  564. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +0 -86
  565. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +0 -43
  566. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +0 -47
  567. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +0 -65
  568. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +0 -30
  569. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +0 -16
  570. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +0 -160
  571. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +0 -412
  572. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +0 -602
  573. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +0 -915
  574. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +0 -916
  575. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +0 -752
  576. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +0 -1237
  577. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +0 -189
  578. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +0 -500
  579. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +0 -464
  580. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +0 -619
  581. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +0 -437
  582. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +0 -231
  583. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +0 -170
  584. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +0 -602
  585. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +0 -821
  586. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +0 -742
  587. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +0 -726
  588. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +0 -764
  589. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +0 -831
  590. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +0 -226
  591. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +0 -901
  592. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +0 -901
  593. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +0 -775
  594. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +0 -937
  595. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +0 -770
  596. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +0 -961
  597. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +0 -119
  598. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +0 -253
  599. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +0 -145
  600. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +0 -543
  601. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +0 -741
  602. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +0 -470
  603. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +0 -458
  604. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +0 -639
  605. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +0 -140
  606. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +0 -572
  607. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +0 -411
  608. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +0 -569
  609. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +0 -695
  610. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +0 -184
  611. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +0 -459
  612. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +0 -479
  613. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +0 -687
  614. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +0 -758
  615. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +0 -868
  616. claude_mpm-4.24.0.dist-info/entry_points.txt +0 -10
  617. claude_mpm-4.24.0.dist-info/licenses/LICENSE +0 -21
  618. /claude_mpm/agents/templates/{git_file_tracking.md → git-file-tracking.md} +0 -0
  619. /claude_mpm/agents/templates/{pm_examples.md → pm-examples.md} +0 -0
  620. /claude_mpm/agents/templates/{response_format.md → response-format.md} +0 -0
  621. /claude_mpm/agents/templates/{validation_templates.md → validation-templates.md} +0 -0
  622. {claude_mpm-4.24.0.dist-info → claude_mpm-5.4.41.dist-info}/WHEEL +0 -0
  623. {claude_mpm-4.24.0.dist-info → claude_mpm-5.4.41.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1094 @@
1
+ """Git Source Sync Service for agent templates.
2
+
3
+ Syncs agent markdown files from remote Git repositories (GitHub) using
4
+ ETag-based caching and SQLite state tracking for efficient updates.
5
+ Implements Stage 1 of the three-stage sync algorithm:
6
+ - Check repository for updates using ETag headers
7
+ - Download agent files via raw.githubusercontent.com URLs
8
+ - Track content with SHA-256 hashes and sync history in SQLite
9
+ """
10
+
11
+ import json
12
+ import logging
13
+ import time
14
+ from datetime import datetime, timezone
15
+ from pathlib import Path
16
+ from typing import Any, Dict, List, Optional, Tuple
17
+
18
+ import requests
19
+
20
+ from claude_mpm.core.file_utils import get_file_hash
21
+ from claude_mpm.services.agents.sources.agent_sync_state import AgentSyncState
22
+ from claude_mpm.utils.progress import create_progress_bar
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ class GitSyncError(Exception):
28
+ """Base exception for git sync errors."""
29
+
30
+
31
+ class NetworkError(GitSyncError):
32
+ """Network/HTTP errors."""
33
+
34
+
35
+ class CacheError(GitSyncError):
36
+ """Cache read/write errors."""
37
+
38
+
39
+ class ETagCache:
40
+ """Manages ETag storage for efficient HTTP caching.
41
+
42
+ Design Decision: Simple JSON file-based cache for ETag storage
43
+
44
+ Rationale: ETags are small text strings that change infrequently.
45
+ JSON provides human-readable format for debugging and is sufficient
46
+ for this use case. Rejected SQLite as it adds complexity without
47
+ significant benefits for this simple key-value storage.
48
+
49
+ Trade-offs:
50
+ - Simplicity: JSON is simple and debuggable
51
+ - Performance: File I/O is fast enough for <100 ETags
52
+ - Scalability: Limited to ~1000s of ETags before performance degrades
53
+
54
+ Extension Points: Can be replaced with SQLite if ETag count exceeds
55
+ performance threshold (>1000 agents syncing).
56
+ """
57
+
58
+ def __init__(self, cache_file: Path):
59
+ """Initialize ETag cache.
60
+
61
+ Args:
62
+ cache_file: Path to JSON file storing ETags
63
+ """
64
+ self._cache_file = cache_file
65
+ self._cache: Dict[str, Dict[str, Any]] = self._load_cache()
66
+
67
+ def get_etag(self, url: str) -> Optional[str]:
68
+ """Retrieve stored ETag for URL.
69
+
70
+ Args:
71
+ url: URL to look up ETag for
72
+
73
+ Returns:
74
+ ETag string or None if not found
75
+ """
76
+ entry = self._cache.get(url, {})
77
+ return entry.get("etag")
78
+
79
+ def set_etag(self, url: str, etag: str, file_size: Optional[int] = None):
80
+ """Store ETag for URL.
81
+
82
+ Args:
83
+ url: URL to store ETag for
84
+ etag: ETag value to store
85
+ file_size: Optional file size in bytes
86
+ """
87
+ self._cache[url] = {
88
+ "etag": etag,
89
+ "last_modified": datetime.now(timezone.utc).isoformat(),
90
+ "file_size": file_size,
91
+ }
92
+ self._save_cache()
93
+
94
+ def _load_cache(self) -> Dict[str, Dict[str, Any]]:
95
+ """Load ETag cache from JSON file.
96
+
97
+ Returns:
98
+ Dictionary mapping URLs to ETag metadata
99
+
100
+ Error Handling:
101
+ - FileNotFoundError: Returns empty dict (first run)
102
+ - JSONDecodeError: Logs warning and returns empty dict
103
+ - PermissionError: Logs error and returns empty dict
104
+ """
105
+ if not self._cache_file.exists():
106
+ return {}
107
+
108
+ try:
109
+ with self._cache_file.open() as f:
110
+ return json.load(f)
111
+ except json.JSONDecodeError:
112
+ logger.warning(f"Invalid ETag cache file: {self._cache_file}, resetting")
113
+ return {}
114
+ except PermissionError as e:
115
+ logger.error(f"Permission denied reading ETag cache: {e}")
116
+ return {}
117
+ except Exception as e:
118
+ logger.error(f"Error loading ETag cache: {e}")
119
+ return {}
120
+
121
+ def _save_cache(self):
122
+ """Persist ETag cache to JSON file.
123
+
124
+ Error Handling:
125
+ - PermissionError: Logs error but doesn't raise (cache is optional)
126
+ - IOError: Logs error but doesn't raise (graceful degradation)
127
+
128
+ Failure Mode: If cache write fails, next sync will re-download
129
+ all files (inefficient but correct behavior).
130
+ """
131
+ try:
132
+ # Ensure parent directory exists
133
+ self._cache_file.parent.mkdir(parents=True, exist_ok=True)
134
+
135
+ with self._cache_file.open("w") as f:
136
+ json.dump(self._cache, f, indent=2)
137
+ except PermissionError as e:
138
+ logger.error(f"Permission denied writing ETag cache: {e}")
139
+ except OSError as e:
140
+ logger.error(f"IO error writing ETag cache: {e}")
141
+ except Exception as e:
142
+ logger.error(f"Error saving ETag cache: {e}")
143
+
144
+
145
+ class GitSourceSyncService:
146
+ """Service for syncing agent templates from remote Git repositories.
147
+
148
+ Design Decision: Use raw.githubusercontent.com URLs instead of Git API
149
+
150
+ Rationale: Raw URLs bypass GitHub API rate limits (60/hour unauthenticated,
151
+ 5000/hour authenticated). For agent files, direct raw access is sufficient
152
+ and more reliable. Rejected Git API because it requires base64 decoding
153
+ and consumes rate limit unnecessarily.
154
+
155
+ Trade-offs:
156
+ - Performance: Raw URLs have no rate limit, instant access
157
+ - Simplicity: Direct HTTP GET, no JSON parsing or base64 decoding
158
+ - Discovery: Cannot auto-discover agent list (requires manifest or hardcoded)
159
+ - Metadata: No commit info, file size, or last modified date
160
+
161
+ Optimization Opportunities:
162
+ 1. Async Downloads: Use aiohttp for parallel agent downloads
163
+ - Estimated speedup: 5-10x for initial sync (10 agents)
164
+ - Effort: 4-6 hours, medium complexity
165
+ - Threshold: Implement when agent count >20
166
+
167
+ 2. Manifest File: Add agents.json to repository for auto-discovery
168
+ - Removes hardcoded agent list
169
+ - Effort: 2 hours
170
+ - Blocks: Requires repository write access
171
+
172
+ Performance:
173
+ - Time Complexity: O(n) where n = number of agents
174
+ - Space Complexity: O(n) for in-memory agent content during sync
175
+ - Expected Performance:
176
+ * First sync (10 agents): ~5-10 seconds
177
+ * Subsequent sync (no changes): ~1-2 seconds (ETag checks only)
178
+ * Partial update (2 of 10 changed): ~2-3 seconds
179
+ """
180
+
181
+ def __init__(
182
+ self,
183
+ source_url: str = "https://raw.githubusercontent.com/bobmatnyc/claude-mpm-agents/main/agents",
184
+ cache_dir: Optional[Path] = None,
185
+ source_id: str = "github-remote",
186
+ ):
187
+ """Initialize Git source sync service.
188
+
189
+ Args:
190
+ source_url: Base URL for raw files (without trailing slash)
191
+ cache_dir: Local cache directory (defaults to ~/.claude-mpm/cache/agents/)
192
+ source_id: Unique identifier for this source (for multi-source support)
193
+
194
+ Design Decision: Cache to ~/.claude-mpm/cache/agents/ (canonical location)
195
+
196
+ Rationale: Separates cached repository structure from deployed agents.
197
+ This allows preserving nested directory structure in cache while
198
+ flattening for deployment. Enables multiple deployment targets
199
+ (user, project) from single cache source.
200
+
201
+ Trade-offs:
202
+ - Storage: Uses 2x disk space (cache + deployment)
203
+ - Performance: Copy operation on deployment (~10ms for 50 agents)
204
+ - Flexibility: Supports project-specific deployments
205
+ - Migration: Requires one-time migration from old cache location
206
+ """
207
+ self.source_url = source_url.rstrip("/")
208
+ self.source_id = source_id
209
+
210
+ # Setup cache directory (canonical: ~/.claude-mpm/cache/agents/)
211
+ if cache_dir:
212
+ self.cache_dir = Path(cache_dir)
213
+ else:
214
+ # Default to ~/.claude-mpm/cache/agents/ (canonical cache location)
215
+ home = Path.home()
216
+ self.cache_dir = home / ".claude-mpm" / "cache" / "agents"
217
+
218
+ self.cache_dir.mkdir(parents=True, exist_ok=True)
219
+
220
+ # Setup HTTP session with connection pooling
221
+ self.session = requests.Session()
222
+ self.session.headers["Accept"] = "text/plain"
223
+
224
+ # Initialize SQLite state tracking (NEW)
225
+ self.sync_state = AgentSyncState()
226
+
227
+ # Register this source
228
+ self.sync_state.register_source(
229
+ source_id=self.source_id, url=self.source_url, enabled=True
230
+ )
231
+
232
+ # Initialize ETag cache (DEPRECATED - kept for backward compatibility)
233
+ etag_cache_file = self.cache_dir / ".etag-cache.json"
234
+ self.etag_cache = ETagCache(etag_cache_file)
235
+
236
+ # Migrate old ETag cache to SQLite if it exists
237
+ if etag_cache_file.exists():
238
+ self._migrate_etag_cache(etag_cache_file)
239
+
240
+ # NEW: Initialize git manager for cache (Phase 1 integration)
241
+ from claude_mpm.services.agents.cache_git_manager import CacheGitManager
242
+
243
+ self.git_manager = CacheGitManager(self.cache_dir)
244
+
245
+ def sync_agents(
246
+ self,
247
+ force_refresh: bool = False,
248
+ show_progress: bool = True,
249
+ progress_prefix: str = "Syncing agents",
250
+ progress_suffix: str = "agents",
251
+ ) -> Dict[str, Any]:
252
+ """Sync agents from remote Git repository with SQLite state tracking.
253
+
254
+ Args:
255
+ force_refresh: Force download even if cache is fresh (bypasses ETag)
256
+ show_progress: Show ASCII progress bar during sync (default: True, auto-detects TTY)
257
+ progress_prefix: Custom prefix for progress bar (default: "Syncing agents")
258
+ progress_suffix: Custom suffix for completion message (default: "agents")
259
+
260
+ Returns:
261
+ Dictionary with sync results:
262
+ {
263
+ "synced": ["agent1.md", "agent2.md"], # New downloads
264
+ "cached": ["agent3.md"], # ETag 304 responses
265
+ "failed": [], # Failed downloads
266
+ "total_downloaded": 2,
267
+ "cache_hits": 1
268
+ }
269
+
270
+ Error Handling:
271
+ - Network errors: Individual agent failures don't stop sync
272
+ - Failed agents added to "failed" list
273
+ - Returns partial success if some agents sync successfully
274
+ """
275
+ logger.info(f"Starting agent sync from {self.source_url}")
276
+ logger.debug(f"Cache directory: {self.cache_dir}")
277
+ logger.debug(f"Force refresh: {force_refresh}")
278
+
279
+ start_time = time.time()
280
+
281
+ # NEW: Pre-sync git operations (Phase 1 integration)
282
+ if self.git_manager.is_git_repo():
283
+ logger.debug("Cache is a git repository, checking for updates...")
284
+
285
+ # Warn about uncommitted changes
286
+ if self.git_manager.has_uncommitted_changes():
287
+ uncommitted_count = len(
288
+ self.git_manager.get_status().get("uncommitted", [])
289
+ )
290
+ logger.warning(
291
+ f"Cache has {uncommitted_count} uncommitted change(s). "
292
+ "These will be preserved, but consider committing them."
293
+ )
294
+
295
+ # Pull latest if online (non-blocking)
296
+ try:
297
+ success, msg = self.git_manager.pull_latest()
298
+ if success:
299
+ logger.info(f"✅ Git pull: {msg}")
300
+ else:
301
+ logger.warning(f"⚠️ Git pull failed: {msg}")
302
+ logger.info("Continuing with HTTP sync as fallback")
303
+ except Exception as e:
304
+ logger.warning(f"Git pull error (continuing with HTTP sync): {e}")
305
+ else:
306
+ logger.debug("Cache is not a git repository, skipping git operations")
307
+
308
+ results = {
309
+ "synced": [],
310
+ "cached": [],
311
+ "failed": [],
312
+ "total_downloaded": 0,
313
+ "cache_hits": 0,
314
+ }
315
+
316
+ # Get list of agents to sync
317
+ agent_list = self._get_agent_list()
318
+
319
+ # Create progress bar if enabled
320
+ progress_bar = None
321
+ if show_progress:
322
+ progress_bar = create_progress_bar(
323
+ total=len(agent_list), prefix=progress_prefix
324
+ )
325
+
326
+ for idx, agent_filename in enumerate(agent_list, start=1):
327
+ try:
328
+ # Update progress bar with current file
329
+ if progress_bar:
330
+ progress_bar.update(idx, message=agent_filename)
331
+
332
+ url = f"{self.source_url}/{agent_filename}"
333
+ content, status = self._fetch_with_etag(url, force_refresh)
334
+
335
+ if status == 200:
336
+ # New content downloaded - save and track
337
+ self._save_to_cache(agent_filename, content)
338
+
339
+ # Track file with content hash in SQLite
340
+ cache_file = self.cache_dir / agent_filename
341
+ content_sha = get_file_hash(cache_file, algorithm="sha256")
342
+ if content_sha:
343
+ self.sync_state.track_file(
344
+ source_id=self.source_id,
345
+ file_path=agent_filename,
346
+ content_sha=content_sha,
347
+ local_path=str(cache_file),
348
+ file_size=len(content.encode("utf-8")),
349
+ )
350
+
351
+ results["synced"].append(agent_filename)
352
+ results["total_downloaded"] += 1
353
+ logger.debug(f"Downloaded: {agent_filename}")
354
+
355
+ elif status == 304:
356
+ # Not modified - verify hash
357
+ cache_file = self.cache_dir / agent_filename
358
+ if cache_file.exists():
359
+ current_sha = get_file_hash(cache_file, algorithm="sha256")
360
+ if current_sha and self.sync_state.has_file_changed(
361
+ self.source_id, agent_filename, current_sha
362
+ ):
363
+ # Hash mismatch - re-download
364
+ logger.warning(
365
+ f"Hash mismatch for {agent_filename}, re-downloading"
366
+ )
367
+ content, _ = self._fetch_with_etag(url, force_refresh=True)
368
+ if content:
369
+ self._save_to_cache(agent_filename, content)
370
+ # Re-calculate and track hash
371
+ new_sha = get_file_hash(cache_file, algorithm="sha256")
372
+ if new_sha:
373
+ self.sync_state.track_file(
374
+ source_id=self.source_id,
375
+ file_path=agent_filename,
376
+ content_sha=new_sha,
377
+ local_path=str(cache_file),
378
+ file_size=len(content.encode("utf-8")),
379
+ )
380
+ results["synced"].append(agent_filename)
381
+ results["total_downloaded"] += 1
382
+ else:
383
+ results["failed"].append(agent_filename)
384
+ else:
385
+ # Hash matches - true cache hit
386
+ results["cached"].append(agent_filename)
387
+ results["cache_hits"] += 1
388
+ logger.debug(f"Cache hit: {agent_filename}")
389
+ else:
390
+ # Cache file missing - re-download
391
+ logger.warning(
392
+ f"Cache file missing for {agent_filename}, re-downloading"
393
+ )
394
+ content, _ = self._fetch_with_etag(url, force_refresh=True)
395
+ if content:
396
+ self._save_to_cache(agent_filename, content)
397
+ # Track hash
398
+ current_sha = get_file_hash(cache_file, algorithm="sha256")
399
+ if current_sha:
400
+ self.sync_state.track_file(
401
+ source_id=self.source_id,
402
+ file_path=agent_filename,
403
+ content_sha=current_sha,
404
+ local_path=str(cache_file),
405
+ file_size=len(content.encode("utf-8")),
406
+ )
407
+ results["synced"].append(agent_filename)
408
+ results["total_downloaded"] += 1
409
+ else:
410
+ results["failed"].append(agent_filename)
411
+
412
+ else:
413
+ # Error status
414
+ logger.warning(f"Unexpected status {status} for {agent_filename}")
415
+ results["failed"].append(agent_filename)
416
+
417
+ except requests.RequestException as e:
418
+ logger.error(f"Network error downloading {agent_filename}: {e}")
419
+ results["failed"].append(agent_filename)
420
+ # Continue with other agents
421
+ except Exception as e:
422
+ logger.error(f"Unexpected error for {agent_filename}: {e}")
423
+ results["failed"].append(agent_filename)
424
+
425
+ # Record sync result in history
426
+ duration_ms = int((time.time() - start_time) * 1000)
427
+ status = (
428
+ "success"
429
+ if not results["failed"]
430
+ else ("partial" if results["synced"] or results["cached"] else "error")
431
+ )
432
+
433
+ self.sync_state.record_sync_result(
434
+ source_id=self.source_id,
435
+ status=status,
436
+ files_synced=results["total_downloaded"],
437
+ files_cached=results["cache_hits"],
438
+ files_failed=len(results["failed"]),
439
+ duration_ms=duration_ms,
440
+ )
441
+
442
+ # Update source metadata
443
+ self.sync_state.update_source_sync_metadata(source_id=self.source_id)
444
+
445
+ # Finish progress bar with clear breakdown
446
+ if progress_bar:
447
+ downloaded = results["total_downloaded"]
448
+ cached = results["cache_hits"]
449
+ total = downloaded + cached
450
+ failed_count = len(results["failed"])
451
+
452
+ if failed_count > 0:
453
+ progress_bar.finish(
454
+ message=f"Complete: {downloaded} downloaded, {cached} cached, {failed_count} failed ({total} total)"
455
+ )
456
+ # Show breakdown to clarify only changed files were downloaded
457
+ elif cached > 0:
458
+ progress_bar.finish(
459
+ message=f"Complete: {downloaded} downloaded, {cached} cached ({total} total)"
460
+ )
461
+ else:
462
+ # All new downloads (first sync)
463
+ progress_bar.finish(
464
+ message=f"Complete: {downloaded} {progress_suffix} downloaded"
465
+ )
466
+
467
+ # Log summary
468
+ logger.info(
469
+ f"Sync complete: {results['total_downloaded']} downloaded, "
470
+ f"{results['cache_hits']} from cache, {len(results['failed'])} failed"
471
+ )
472
+
473
+ return results
474
+
475
+ def check_for_updates(self) -> Dict[str, bool]:
476
+ """Check if remote repository has updates using ETag.
477
+
478
+ Uses HEAD requests to check ETags without downloading content.
479
+
480
+ Returns:
481
+ Dictionary mapping agent filenames to update status:
482
+ {
483
+ "research.md": True, # Has updates
484
+ "engineer.md": False, # No updates (ETag matches)
485
+ }
486
+
487
+ Performance: ~1-2 seconds for 10 agents (HEAD requests only)
488
+ """
489
+ logger.info("Checking for agent updates")
490
+ updates = {}
491
+
492
+ agent_list = self._get_agent_list()
493
+
494
+ for agent_filename in agent_list:
495
+ try:
496
+ url = f"{self.source_url}/{agent_filename}"
497
+ cached_etag = self.etag_cache.get_etag(url)
498
+
499
+ # Use HEAD request to check ETag without downloading
500
+ response = self.session.head(url, timeout=30)
501
+
502
+ if response.status_code == 200:
503
+ remote_etag = response.headers.get("ETag")
504
+ has_update = remote_etag != cached_etag
505
+ updates[agent_filename] = has_update
506
+
507
+ if has_update:
508
+ logger.info(f"Update available: {agent_filename}")
509
+ else:
510
+ logger.warning(
511
+ f"Could not check {agent_filename}: HTTP {response.status_code}"
512
+ )
513
+ updates[agent_filename] = False
514
+
515
+ except requests.RequestException as e:
516
+ logger.error(f"Network error checking {agent_filename}: {e}")
517
+ updates[agent_filename] = False
518
+
519
+ return updates
520
+
521
+ def download_agent_file(self, filename: str) -> Optional[str]:
522
+ """Download single agent file with ETag caching.
523
+
524
+ Args:
525
+ filename: Agent filename (e.g., "research.md")
526
+
527
+ Returns:
528
+ Agent content as string, or None if download fails
529
+
530
+ Error Handling:
531
+ - Network errors: Returns None, logs error
532
+ - 404 Not Found: Returns None, logs warning
533
+ - Cache fallback: Attempts to load from cache on error
534
+ """
535
+ url = f"{self.source_url}/{filename}"
536
+
537
+ try:
538
+ content, status = self._fetch_with_etag(url)
539
+
540
+ if status == 200:
541
+ self._save_to_cache(filename, content)
542
+ return content
543
+ if status == 304:
544
+ # Load from cache
545
+ return self._load_from_cache(filename)
546
+ logger.warning(f"HTTP {status} for {filename}")
547
+ return None
548
+
549
+ except requests.RequestException as e:
550
+ logger.error(f"Network error downloading {filename}: {e}")
551
+ # Try cache fallback
552
+ return self._load_from_cache(filename)
553
+
554
+ def _fetch_with_etag(
555
+ self, url: str, force_refresh: bool = False
556
+ ) -> Tuple[Optional[str], int]:
557
+ """Fetch URL with ETag caching.
558
+
559
+ Design Decision: Use If-None-Match header for conditional requests
560
+
561
+ Rationale: ETag-based caching is standard HTTP pattern that GitHub
562
+ supports. Reduces bandwidth by 95%+ for unchanged files. Alternative
563
+ was Last-Modified timestamps, but ETags are more reliable for Git
564
+ content (commit hash based).
565
+
566
+ Args:
567
+ url: URL to fetch
568
+ force_refresh: Skip ETag check and force download
569
+
570
+ Returns:
571
+ Tuple of (content, status_code) where:
572
+ - status_code 200: New content downloaded
573
+ - status_code 304: Not modified (use cached)
574
+ - content is None on 304
575
+
576
+ Error Handling:
577
+ - Timeout: 30 second timeout, raises requests.Timeout
578
+ - Connection errors: Raises requests.ConnectionError
579
+ - HTTP errors (4xx, 5xx): Returns (None, status_code)
580
+ """
581
+ headers = {}
582
+
583
+ # Add ETag header if we have cached version and not forcing refresh
584
+ if not force_refresh:
585
+ cached_etag = self.etag_cache.get_etag(url)
586
+ if cached_etag:
587
+ headers["If-None-Match"] = cached_etag
588
+
589
+ response = self.session.get(url, headers=headers, timeout=30)
590
+
591
+ if response.status_code == 304:
592
+ # Not modified - use cached version
593
+ return None, 304
594
+
595
+ if response.status_code == 200:
596
+ # New content - update cache
597
+ content = response.text
598
+ etag = response.headers.get("ETag")
599
+ if etag:
600
+ file_size = len(content.encode("utf-8"))
601
+ self.etag_cache.set_etag(url, etag, file_size)
602
+ return content, 200
603
+
604
+ # Error status
605
+ return None, response.status_code
606
+
607
+ def _save_to_cache(self, filename: str, content: str):
608
+ """Save agent file to cache (Phase 1: preserves nested directory structure).
609
+
610
+ Design Decision: Preserve nested directory structure in cache
611
+
612
+ Rationale: Cache mirrors remote repository structure, allowing
613
+ proper organization and future features (e.g., category browsing).
614
+ Deployment layer flattens to .claude-mpm/agents/ for backward
615
+ compatibility.
616
+
617
+ Args:
618
+ filename: Agent file path (may include directories, e.g., "engineer/core/engineer.md")
619
+ content: File content
620
+
621
+ Error Handling:
622
+ - PermissionError: Logs error but doesn't raise
623
+ - IOError: Logs error but doesn't raise
624
+
625
+ Failure Mode: If cache write fails, agent is still synced in memory
626
+ but will need re-download on next sync (graceful degradation).
627
+ """
628
+ try:
629
+ cache_file = self.cache_dir / filename
630
+ # Create parent directories for nested structure
631
+ cache_file.parent.mkdir(parents=True, exist_ok=True)
632
+ cache_file.write_text(content, encoding="utf-8")
633
+ logger.debug(f"Saved to cache: {filename}")
634
+ except PermissionError as e:
635
+ logger.error(f"Permission denied writing {filename}: {e}")
636
+ except OSError as e:
637
+ logger.error(f"IO error writing {filename}: {e}")
638
+ except Exception as e:
639
+ logger.error(f"Error saving {filename} to cache: {e}")
640
+
641
+ def _load_from_cache(self, filename: str) -> Optional[str]:
642
+ """Load agent file from cache.
643
+
644
+ Args:
645
+ filename: Agent filename
646
+
647
+ Returns:
648
+ Cached content or None if not found
649
+
650
+ Error Handling:
651
+ - FileNotFoundError: Returns None (not in cache)
652
+ - PermissionError: Logs error, returns None
653
+ - IOError: Logs error, returns None
654
+ """
655
+ cache_file = self.cache_dir / filename
656
+
657
+ if not cache_file.exists():
658
+ logger.debug(f"No cached version of {filename}")
659
+ return None
660
+
661
+ try:
662
+ content = cache_file.read_text(encoding="utf-8")
663
+ logger.debug(f"Loaded from cache: {filename}")
664
+ return content
665
+ except PermissionError as e:
666
+ logger.error(f"Permission denied reading {filename}: {e}")
667
+ return None
668
+ except OSError as e:
669
+ logger.error(f"IO error reading {filename}: {e}")
670
+ return None
671
+ except Exception as e:
672
+ logger.error(f"Error loading {filename} from cache: {e}")
673
+ return None
674
+
675
+ def _get_agent_list(self) -> List[str]:
676
+ """Get list of agent file paths to sync (including nested directories).
677
+
678
+ Design Decision: Use Git Tree API instead of Contents API (Phase 1 fix)
679
+
680
+ Rationale: Git Tree API with recursive=1 discovers entire repository
681
+ structure in a single request, solving the "1 agent discovered" issue.
682
+ Contents API only shows top-level files, missing nested directories.
683
+
684
+ Trade-offs:
685
+ - Performance: Single API call vs. 10-50+ recursive calls
686
+ - Rate Limits: 1 request vs. dozens (avoids 403 errors)
687
+ - Discovery: Finds ALL files in nested structure (50+ agents)
688
+ - API Complexity: Requires commit SHA lookup before tree fetch
689
+
690
+ Alternatives Considered:
691
+ 1. Contents API with recursion: 50+ API calls, hits rate limits
692
+ 2. Hardcoded nested paths: Misses new agents, unmaintainable
693
+ 3. Manifest file: Requires repository write access
694
+
695
+ Error Handling:
696
+ - Network errors: Falls back to static list
697
+ - Rate limit exceeded: Falls back to static list
698
+ - JSON parse errors: Falls back to static list
699
+
700
+ Returns:
701
+ List of agent file paths with directory structure
702
+ (e.g., ["research.md", "engineer/core/engineer.md", ...])
703
+ """
704
+ # Extract repository info from source URL
705
+ # URL format: https://raw.githubusercontent.com/owner/repo/branch/path
706
+ try:
707
+ # Parse GitHub URL to extract owner/repo/branch
708
+ url_parts = self.source_url.replace(
709
+ "https://raw.githubusercontent.com/", ""
710
+ ).split("/")
711
+
712
+ if len(url_parts) >= 3:
713
+ owner = url_parts[0]
714
+ repo = url_parts[1]
715
+ branch = url_parts[2]
716
+ base_path = "/".join(url_parts[3:]) if len(url_parts) > 3 else ""
717
+
718
+ logger.debug(
719
+ f"Discovering agents from {owner}/{repo}/{branch} via Git Tree API"
720
+ )
721
+
722
+ # Use Git Tree API for recursive discovery
723
+ agent_files = self._discover_agents_via_tree_api(
724
+ owner, repo, branch, base_path
725
+ )
726
+
727
+ if agent_files:
728
+ logger.info(
729
+ f"Discovered {len(agent_files)} agents via Git Tree API"
730
+ )
731
+ return sorted(agent_files)
732
+
733
+ logger.warning("No agent files found via Tree API, using fallback list")
734
+
735
+ except requests.RequestException as e:
736
+ logger.warning(
737
+ f"Network error fetching agent list from API: {e}, using fallback list"
738
+ )
739
+ except (json.JSONDecodeError, KeyError, ValueError) as e:
740
+ logger.warning(
741
+ f"Error parsing GitHub API response: {e}, using fallback list"
742
+ )
743
+ except Exception as e:
744
+ logger.warning(
745
+ f"Unexpected error fetching agent list: {e}, using fallback list"
746
+ )
747
+
748
+ # Fallback to known agent list if API fails
749
+ logger.debug("Using fallback agent list")
750
+ return [
751
+ "research.md",
752
+ "engineer.md",
753
+ "qa.md",
754
+ "documentation.md",
755
+ "security.md",
756
+ "ops.md",
757
+ "ticketing.md",
758
+ "product_owner.md",
759
+ "version_control.md",
760
+ "project_organizer.md",
761
+ ]
762
+
763
+ def _discover_agents_via_tree_api(
764
+ self, owner: str, repo: str, branch: str, base_path: str = ""
765
+ ) -> List[str]:
766
+ """Discover all agent files using GitHub Git Tree API with recursion.
767
+
768
+ Design Decision: Two-step Tree API pattern (commit SHA → tree)
769
+
770
+ Rationale: Git Tree API requires commit SHA, not branch name.
771
+ Step 1 resolves branch to SHA, Step 2 fetches recursive tree.
772
+ This pattern is standard for GitHub API and handles branch
773
+ references correctly.
774
+
775
+ Algorithm:
776
+ 1. GET /repos/{owner}/{repo}/git/refs/heads/{branch} → commit SHA
777
+ 2. GET /repos/{owner}/{repo}/git/trees/{sha}?recursive=1 → all files
778
+ 3. Filter for .md/.json files in agents/ directory
779
+ 4. Exclude README.md and .gitignore
780
+
781
+ Args:
782
+ owner: GitHub owner (e.g., "bobmatnyc")
783
+ repo: Repository name (e.g., "claude-mpm-agents")
784
+ branch: Branch name (e.g., "main")
785
+ base_path: Base path prefix to filter (e.g., "agents")
786
+
787
+ Returns:
788
+ List of agent file paths relative to base_path
789
+ (e.g., ["research.md", "engineer/core/engineer.md"])
790
+
791
+ Error Handling:
792
+ - HTTP 404: Branch or repo not found, raises RequestException
793
+ - HTTP 403: Rate limit exceeded, raises RequestException
794
+ - Timeout: 30 second timeout, raises RequestException
795
+ - Empty tree: Returns empty list (logged as warning)
796
+
797
+ Performance:
798
+ - Time: ~500-800ms for 50+ agents (2 API calls)
799
+ - Rate Limit: Consumes 2 API calls per sync
800
+ - Scalability: Handles repositories with 1000s of files
801
+ """
802
+ # Step 1: Get commit SHA for branch
803
+ refs_url = (
804
+ f"https://api.github.com/repos/{owner}/{repo}/git/refs/heads/{branch}"
805
+ )
806
+ logger.debug(f"Fetching commit SHA from {refs_url}")
807
+
808
+ refs_response = self.session.get(
809
+ refs_url, headers={"Accept": "application/vnd.github+json"}, timeout=30
810
+ )
811
+
812
+ if refs_response.status_code == 403:
813
+ logger.warning(
814
+ "GitHub API rate limit exceeded (HTTP 403). "
815
+ "Consider setting GITHUB_TOKEN environment variable."
816
+ )
817
+ raise requests.RequestException("Rate limit exceeded")
818
+
819
+ refs_response.raise_for_status()
820
+ commit_sha = refs_response.json()["object"]["sha"]
821
+ logger.debug(f"Resolved {branch} to commit {commit_sha[:8]}")
822
+
823
+ # Step 2: Get recursive tree for commit
824
+ tree_url = f"https://api.github.com/repos/{owner}/{repo}/git/trees/{commit_sha}"
825
+ params = {"recursive": "1"} # Recursively fetch all files
826
+
827
+ logger.debug(f"Fetching recursive tree from {tree_url}")
828
+ tree_response = self.session.get(
829
+ tree_url,
830
+ headers={"Accept": "application/vnd.github+json"},
831
+ params=params,
832
+ timeout=30,
833
+ )
834
+ tree_response.raise_for_status()
835
+
836
+ tree_data = tree_response.json()
837
+ all_items = tree_data.get("tree", [])
838
+
839
+ logger.debug(f"Tree API returned {len(all_items)} total items")
840
+
841
+ # Step 3: Filter for agent files
842
+ agent_files = []
843
+ for item in all_items:
844
+ # Only process files (blobs), not directories (trees)
845
+ if item["type"] != "blob":
846
+ continue
847
+
848
+ path = item["path"]
849
+
850
+ # Filter for files in base_path (e.g., "agents/")
851
+ if base_path and not path.startswith(base_path + "/"):
852
+ continue
853
+
854
+ # Exclude build/dist directories (prevents double-counting)
855
+ # e.g., both "agents/engineer.md" and "dist/agents/engineer.md"
856
+ path_parts = path.split("/")
857
+ if any(excluded in path_parts for excluded in ["dist", "build", ".cache"]):
858
+ continue
859
+
860
+ # Remove base_path prefix for relative paths
861
+ if base_path:
862
+ relative_path = path[len(base_path) + 1 :]
863
+ else:
864
+ relative_path = path
865
+
866
+ # Filter for .md or .json files, exclude README and .gitignore
867
+ if (
868
+ relative_path.endswith(".md") or relative_path.endswith(".json")
869
+ ) and relative_path not in ["README.md", ".gitignore"]:
870
+ agent_files.append(relative_path)
871
+
872
+ logger.debug(f"Filtered to {len(agent_files)} agent files")
873
+ return agent_files
874
+
875
+ def _migrate_etag_cache(self, cache_file: Path):
876
+ """Migrate old ETag cache to SQLite (one-time operation).
877
+
878
+ Args:
879
+ cache_file: Path to old JSON ETag cache file
880
+
881
+ Error Handling:
882
+ - Migration failures are logged but don't stop initialization
883
+ - Old cache is renamed to .migrated to prevent re-migration
884
+ """
885
+ try:
886
+ with cache_file.open() as f:
887
+ old_cache = json.load(f)
888
+
889
+ logger.info(f"Migrating {len(old_cache)} ETag entries to SQLite...")
890
+
891
+ migrated = 0
892
+ for url, metadata in old_cache.items():
893
+ try:
894
+ etag = metadata.get("etag")
895
+ if etag:
896
+ # Store in new system
897
+ self.sync_state.update_source_sync_metadata(
898
+ source_id=self.source_id, etag=etag
899
+ )
900
+ migrated += 1
901
+ except Exception as e:
902
+ logger.error(f"Failed to migrate {url}: {e}")
903
+
904
+ # Rename old cache to prevent re-migration
905
+ backup_file = cache_file.with_suffix(".json.migrated")
906
+ cache_file.rename(backup_file)
907
+
908
+ logger.info(
909
+ f"ETag cache migration complete: {migrated} entries migrated, "
910
+ f"old cache backed up to {backup_file.name}"
911
+ )
912
+
913
+ except json.JSONDecodeError as e:
914
+ logger.error(f"Invalid JSON in ETag cache, skipping migration: {e}")
915
+ except Exception as e:
916
+ logger.error(f"Failed to migrate ETag cache: {e}")
917
+
918
+ def get_cached_agents_dir(self) -> Path:
919
+ """Get directory containing cached agent files.
920
+
921
+ Returns:
922
+ Path to cache directory for integration with MultiSourceAgentDeploymentService
923
+ """
924
+ return self.cache_dir
925
+
926
+ def deploy_agents_to_project(
927
+ self,
928
+ project_dir: Path,
929
+ agent_list: Optional[List[str]] = None,
930
+ force: bool = False,
931
+ ) -> Dict[str, Any]:
932
+ """Deploy agents from cache to project directory (Phase 1 deployment).
933
+
934
+ Design Decision: Copy from cache to project-specific deployment directory
935
+
936
+ Rationale: Separates syncing (cache) from deployment (project-local).
937
+ Allows multiple projects to use same cache with different agent
938
+ configurations. Flattens nested structure for backward compatibility.
939
+
940
+ Trade-offs:
941
+ - Storage: 2x disk usage (cache + deployments)
942
+ - Performance: Copy operation ~10ms for 50 agents
943
+ - Isolation: Each project has independent agent set
944
+ - Flexibility: Can deploy subset of cached agents per project
945
+
946
+ Algorithm:
947
+ 1. Create deployment directory (.claude-mpm/agents/)
948
+ 2. Discover cached agents if list not provided
949
+ 3. For each agent, flatten path and copy to deployment
950
+ 4. Track deployment results (new, updated, skipped)
951
+
952
+ Args:
953
+ project_dir: Project root directory (e.g., /path/to/project)
954
+ agent_list: Optional list of agent paths to deploy (uses all if None)
955
+ force: Force redeployment even if up-to-date
956
+
957
+ Returns:
958
+ Dictionary with deployment results:
959
+ {
960
+ "deployed": ["engineer.md"], # Newly deployed
961
+ "updated": ["research.md"], # Updated existing
962
+ "skipped": ["qa.md"], # Already up-to-date
963
+ "failed": ["broken.md"], # Copy failures
964
+ "deployment_dir": "/path/.claude-mpm/agents"
965
+ }
966
+
967
+ Error Handling:
968
+ - Missing cache files: Logged and added to "failed" list
969
+ - Permission errors: Individual failures don't stop deployment
970
+ - Directory creation: Creates deployment directory if missing
971
+
972
+ Example:
973
+ >>> service = GitSourceSyncService()
974
+ >>> service.sync_agents() # Sync to cache first
975
+ >>> result = service.deploy_agents_to_project(Path("/my/project"))
976
+ >>> print(f"Deployed {len(result['deployed'])} agents")
977
+ """
978
+ import shutil
979
+
980
+ # Deploy to .claude/agents/ where Claude Code expects them
981
+ deployment_dir = project_dir / ".claude" / "agents"
982
+ deployment_dir.mkdir(parents=True, exist_ok=True)
983
+
984
+ results = {
985
+ "deployed": [],
986
+ "updated": [],
987
+ "skipped": [],
988
+ "failed": [],
989
+ "deployment_dir": str(deployment_dir),
990
+ }
991
+
992
+ # Get agents from cache or use provided list
993
+ if agent_list is None:
994
+ agent_list = self._discover_cached_agents()
995
+
996
+ logger.info(
997
+ f"Deploying {len(agent_list)} agents from cache to {deployment_dir}"
998
+ )
999
+
1000
+ for agent_path in agent_list:
1001
+ try:
1002
+ cache_file = self.cache_dir / agent_path
1003
+
1004
+ if not cache_file.exists():
1005
+ logger.warning(f"Cache file not found: {agent_path}")
1006
+ results["failed"].append(agent_path)
1007
+ continue
1008
+
1009
+ # Flatten nested path for deployment (engineer/core/engineer.md → engineer.md)
1010
+ deploy_filename = Path(agent_path).name
1011
+ deploy_file = deployment_dir / deploy_filename
1012
+
1013
+ # Check if update needed (compare modification times)
1014
+ should_deploy = force
1015
+ was_existing = deploy_file.exists()
1016
+
1017
+ if not force and was_existing:
1018
+ cache_mtime = cache_file.stat().st_mtime
1019
+ deploy_mtime = deploy_file.stat().st_mtime
1020
+ should_deploy = cache_mtime > deploy_mtime
1021
+
1022
+ if not should_deploy and was_existing:
1023
+ results["skipped"].append(deploy_filename)
1024
+ logger.debug(f"Skipped (up-to-date): {deploy_filename}")
1025
+ continue
1026
+
1027
+ # Copy from cache to deployment
1028
+ shutil.copy2(cache_file, deploy_file)
1029
+
1030
+ # Track result
1031
+ if deploy_file.exists():
1032
+ if was_existing:
1033
+ results["updated"].append(deploy_filename)
1034
+ logger.info(f"Updated: {deploy_filename}")
1035
+ else:
1036
+ results["deployed"].append(deploy_filename)
1037
+ logger.info(f"Deployed: {deploy_filename}")
1038
+ else:
1039
+ results["failed"].append(deploy_filename)
1040
+ logger.error(f"Failed to deploy: {deploy_filename}")
1041
+
1042
+ except PermissionError as e:
1043
+ logger.error(f"Permission denied deploying {agent_path}: {e}")
1044
+ results["failed"].append(Path(agent_path).name)
1045
+ except OSError as e:
1046
+ logger.error(f"IO error deploying {agent_path}: {e}")
1047
+ results["failed"].append(Path(agent_path).name)
1048
+ except Exception as e:
1049
+ logger.error(f"Unexpected error deploying {agent_path}: {e}")
1050
+ results["failed"].append(Path(agent_path).name)
1051
+
1052
+ # Log summary
1053
+ total_success = len(results["deployed"]) + len(results["updated"])
1054
+ logger.info(
1055
+ f"Deployment complete: {total_success} deployed/updated, "
1056
+ f"{len(results['skipped'])} skipped, {len(results['failed'])} failed"
1057
+ )
1058
+
1059
+ return results
1060
+
1061
+ def _discover_cached_agents(self) -> List[str]:
1062
+ """Discover all agent files currently in cache.
1063
+
1064
+ Scans cache directory for .md and .json files, preserving
1065
+ nested directory structure in returned paths.
1066
+
1067
+ Returns:
1068
+ List of agent file paths relative to cache directory
1069
+ (e.g., ["research.md", "engineer/core/engineer.md"])
1070
+
1071
+ Algorithm:
1072
+ 1. Walk cache directory recursively
1073
+ 2. Find all .md and .json files
1074
+ 3. Convert to paths relative to cache root
1075
+ 4. Filter out README.md and .gitignore
1076
+ """
1077
+ cached_agents = []
1078
+
1079
+ if not self.cache_dir.exists():
1080
+ logger.warning(f"Cache directory does not exist: {self.cache_dir}")
1081
+ return []
1082
+
1083
+ for file_path in self.cache_dir.rglob("*"):
1084
+ if file_path.is_file() and file_path.suffix in {".md", ".json"}:
1085
+ # Get relative path from cache directory
1086
+ relative_path = file_path.relative_to(self.cache_dir)
1087
+ relative_str = str(relative_path)
1088
+
1089
+ # Exclude README and .gitignore
1090
+ if relative_str not in ["README.md", ".gitignore"]:
1091
+ cached_agents.append(relative_str)
1092
+
1093
+ logger.debug(f"Discovered {len(cached_agents)} cached agents")
1094
+ return sorted(cached_agents)