claude-mpm 4.21.3__py3-none-any.whl → 5.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (484) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_PM.md +12 -0
  3. claude_mpm/agents/OUTPUT_STYLE.md +3 -48
  4. claude_mpm/agents/PM_INSTRUCTIONS.md +632 -334
  5. claude_mpm/agents/WORKFLOW.md +75 -2
  6. claude_mpm/agents/__init__.py +6 -0
  7. claude_mpm/agents/agent_loader.py +1 -4
  8. claude_mpm/agents/base_agent.json +6 -3
  9. claude_mpm/agents/frontmatter_validator.py +1 -1
  10. claude_mpm/agents/templates/{circuit_breakers.md → circuit-breakers.md} +370 -3
  11. claude_mpm/agents/templates/context-management-examples.md +544 -0
  12. claude_mpm/agents/templates/{pm_red_flags.md → pm-red-flags.md} +89 -19
  13. claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
  14. claude_mpm/agents/templates/research-gate-examples.md +669 -0
  15. claude_mpm/agents/templates/structured-questions-examples.md +615 -0
  16. claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
  17. claude_mpm/agents/templates/ticketing-examples.md +277 -0
  18. claude_mpm/cli/__init__.py +38 -2
  19. claude_mpm/cli/commands/agent_source.py +774 -0
  20. claude_mpm/cli/commands/agent_state_manager.py +125 -20
  21. claude_mpm/cli/commands/agents.py +684 -13
  22. claude_mpm/cli/commands/agents_cleanup.py +210 -0
  23. claude_mpm/cli/commands/agents_discover.py +338 -0
  24. claude_mpm/cli/commands/aggregate.py +1 -1
  25. claude_mpm/cli/commands/analyze.py +3 -3
  26. claude_mpm/cli/commands/auto_configure.py +2 -6
  27. claude_mpm/cli/commands/cleanup.py +1 -1
  28. claude_mpm/cli/commands/config.py +7 -4
  29. claude_mpm/cli/commands/configure.py +478 -44
  30. claude_mpm/cli/commands/configure_agent_display.py +4 -4
  31. claude_mpm/cli/commands/configure_navigation.py +63 -46
  32. claude_mpm/cli/commands/debug.py +12 -12
  33. claude_mpm/cli/commands/doctor.py +10 -2
  34. claude_mpm/cli/commands/hook_errors.py +277 -0
  35. claude_mpm/cli/commands/local_deploy.py +1 -4
  36. claude_mpm/cli/commands/mcp_install_commands.py +1 -1
  37. claude_mpm/cli/commands/mpm_init/core.py +50 -2
  38. claude_mpm/cli/commands/mpm_init/git_activity.py +10 -10
  39. claude_mpm/cli/commands/mpm_init/prompts.py +6 -6
  40. claude_mpm/cli/commands/run.py +124 -128
  41. claude_mpm/cli/commands/skill_source.py +694 -0
  42. claude_mpm/cli/commands/skills.py +435 -1
  43. claude_mpm/cli/executor.py +78 -3
  44. claude_mpm/cli/interactive/agent_wizard.py +919 -41
  45. claude_mpm/cli/parsers/agent_source_parser.py +171 -0
  46. claude_mpm/cli/parsers/agents_parser.py +173 -4
  47. claude_mpm/cli/parsers/base_parser.py +49 -0
  48. claude_mpm/cli/parsers/config_parser.py +96 -43
  49. claude_mpm/cli/parsers/skill_source_parser.py +169 -0
  50. claude_mpm/cli/parsers/skills_parser.py +138 -0
  51. claude_mpm/cli/parsers/source_parser.py +138 -0
  52. claude_mpm/cli/startup.py +499 -84
  53. claude_mpm/cli/startup_display.py +480 -0
  54. claude_mpm/cli/utils.py +1 -1
  55. claude_mpm/cli_module/commands.py +1 -1
  56. claude_mpm/commands/{mpm-auto-configure.md → mpm-agents-auto-configure.md} +9 -0
  57. claude_mpm/commands/mpm-agents-detect.md +9 -0
  58. claude_mpm/commands/{mpm-agents.md → mpm-agents-list.md} +9 -0
  59. claude_mpm/commands/mpm-agents-recommend.md +9 -0
  60. claude_mpm/commands/{mpm-config.md → mpm-config-view.md} +9 -0
  61. claude_mpm/commands/mpm-doctor.md +9 -0
  62. claude_mpm/commands/mpm-help.md +11 -2
  63. claude_mpm/commands/mpm-init.md +27 -2
  64. claude_mpm/commands/mpm-monitor.md +9 -0
  65. claude_mpm/commands/{mpm-resume.md → mpm-session-resume.md} +9 -0
  66. claude_mpm/commands/mpm-status.md +9 -0
  67. claude_mpm/commands/{mpm-organize.md → mpm-ticket-organize.md} +9 -0
  68. claude_mpm/commands/mpm-ticket-view.md +552 -0
  69. claude_mpm/commands/mpm-version.md +9 -0
  70. claude_mpm/commands/mpm.md +10 -0
  71. claude_mpm/config/agent_presets.py +258 -0
  72. claude_mpm/config/agent_sources.py +325 -0
  73. claude_mpm/config/skill_sources.py +590 -0
  74. claude_mpm/constants.py +12 -0
  75. claude_mpm/core/api_validator.py +1 -1
  76. claude_mpm/core/claude_runner.py +17 -10
  77. claude_mpm/core/config.py +24 -0
  78. claude_mpm/core/constants.py +1 -1
  79. claude_mpm/core/framework/__init__.py +3 -16
  80. claude_mpm/core/framework/loaders/instruction_loader.py +25 -5
  81. claude_mpm/core/framework/processors/metadata_processor.py +1 -1
  82. claude_mpm/core/hook_error_memory.py +381 -0
  83. claude_mpm/core/hook_manager.py +41 -2
  84. claude_mpm/core/interactive_session.py +112 -5
  85. claude_mpm/core/logger.py +3 -1
  86. claude_mpm/core/oneshot_session.py +94 -4
  87. claude_mpm/dashboard/static/css/activity.css +69 -69
  88. claude_mpm/dashboard/static/css/connection-status.css +10 -10
  89. claude_mpm/dashboard/static/css/dashboard.css +15 -15
  90. claude_mpm/dashboard/static/js/components/activity-tree.js +178 -178
  91. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +101 -101
  92. claude_mpm/dashboard/static/js/components/agent-inference.js +31 -31
  93. claude_mpm/dashboard/static/js/components/build-tracker.js +59 -59
  94. claude_mpm/dashboard/static/js/components/code-simple.js +107 -107
  95. claude_mpm/dashboard/static/js/components/connection-debug.js +101 -101
  96. claude_mpm/dashboard/static/js/components/diff-viewer.js +113 -113
  97. claude_mpm/dashboard/static/js/components/event-viewer.js +12 -12
  98. claude_mpm/dashboard/static/js/components/file-change-tracker.js +57 -57
  99. claude_mpm/dashboard/static/js/components/file-change-viewer.js +74 -74
  100. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +6 -6
  101. claude_mpm/dashboard/static/js/components/file-viewer.js +42 -42
  102. claude_mpm/dashboard/static/js/components/module-viewer.js +27 -27
  103. claude_mpm/dashboard/static/js/components/session-manager.js +14 -14
  104. claude_mpm/dashboard/static/js/components/socket-manager.js +1 -1
  105. claude_mpm/dashboard/static/js/components/ui-state-manager.js +14 -14
  106. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +110 -110
  107. claude_mpm/dashboard/static/js/components/working-directory.js +8 -8
  108. claude_mpm/dashboard/static/js/connection-manager.js +76 -76
  109. claude_mpm/dashboard/static/js/dashboard.js +76 -58
  110. claude_mpm/dashboard/static/js/extension-error-handler.js +22 -22
  111. claude_mpm/dashboard/static/js/socket-client.js +138 -121
  112. claude_mpm/dashboard/templates/code_simple.html +23 -23
  113. claude_mpm/dashboard/templates/index.html +18 -18
  114. claude_mpm/experimental/cli_enhancements.py +1 -5
  115. claude_mpm/hooks/claude_hooks/event_handlers.py +3 -1
  116. claude_mpm/hooks/claude_hooks/hook_handler.py +24 -7
  117. claude_mpm/hooks/claude_hooks/installer.py +45 -0
  118. claude_mpm/hooks/failure_learning/__init__.py +2 -8
  119. claude_mpm/hooks/failure_learning/failure_detection_hook.py +1 -6
  120. claude_mpm/hooks/failure_learning/fix_detection_hook.py +1 -6
  121. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +1 -6
  122. claude_mpm/hooks/kuzu_response_hook.py +1 -5
  123. claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
  124. claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
  125. claude_mpm/models/git_repository.py +198 -0
  126. claude_mpm/scripts/claude-hook-handler.sh +3 -3
  127. claude_mpm/scripts/start_activity_logging.py +3 -1
  128. claude_mpm/services/agents/agent_builder.py +45 -9
  129. claude_mpm/services/agents/agent_preset_service.py +238 -0
  130. claude_mpm/services/agents/agent_selection_service.py +484 -0
  131. claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
  132. claude_mpm/services/agents/deployment/agent_deployment.py +126 -2
  133. claude_mpm/services/agents/deployment/agent_discovery_service.py +105 -73
  134. claude_mpm/services/agents/deployment/agent_format_converter.py +1 -1
  135. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +1 -5
  136. claude_mpm/services/agents/deployment/agent_metrics_collector.py +3 -3
  137. claude_mpm/services/agents/deployment/agent_restore_handler.py +1 -4
  138. claude_mpm/services/agents/deployment/agent_template_builder.py +236 -15
  139. claude_mpm/services/agents/deployment/agents_directory_resolver.py +101 -15
  140. claude_mpm/services/agents/deployment/async_agent_deployment.py +2 -1
  141. claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -3
  142. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +115 -15
  143. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +2 -2
  144. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +1 -4
  145. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +363 -0
  146. claude_mpm/services/agents/deployment/single_agent_deployer.py +2 -2
  147. claude_mpm/services/agents/deployment/system_instructions_deployer.py +168 -46
  148. claude_mpm/services/agents/deployment/validation/deployment_validator.py +2 -2
  149. claude_mpm/services/agents/git_source_manager.py +629 -0
  150. claude_mpm/services/agents/loading/framework_agent_loader.py +9 -12
  151. claude_mpm/services/agents/local_template_manager.py +50 -10
  152. claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
  153. claude_mpm/services/agents/sources/__init__.py +13 -0
  154. claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
  155. claude_mpm/services/agents/sources/git_source_sync_service.py +1055 -0
  156. claude_mpm/services/agents/startup_sync.py +239 -0
  157. claude_mpm/services/agents/toolchain_detector.py +474 -0
  158. claude_mpm/services/cli/session_pause_manager.py +1 -1
  159. claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
  160. claude_mpm/services/command_deployment_service.py +92 -1
  161. claude_mpm/services/core/interfaces/__init__.py +1 -3
  162. claude_mpm/services/core/interfaces/health.py +1 -4
  163. claude_mpm/services/core/models/__init__.py +2 -11
  164. claude_mpm/services/diagnostics/checks/__init__.py +4 -0
  165. claude_mpm/services/diagnostics/checks/agent_check.py +0 -2
  166. claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
  167. claude_mpm/services/diagnostics/checks/instructions_check.py +1 -2
  168. claude_mpm/services/diagnostics/checks/mcp_check.py +0 -1
  169. claude_mpm/services/diagnostics/checks/monitor_check.py +0 -1
  170. claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
  171. claude_mpm/services/diagnostics/diagnostic_runner.py +9 -0
  172. claude_mpm/services/diagnostics/doctor_reporter.py +40 -10
  173. claude_mpm/services/event_bus/direct_relay.py +3 -3
  174. claude_mpm/services/event_bus/event_bus.py +36 -3
  175. claude_mpm/services/events/consumers/logging.py +1 -2
  176. claude_mpm/services/git/__init__.py +21 -0
  177. claude_mpm/services/git/git_operations_service.py +494 -0
  178. claude_mpm/services/github/__init__.py +21 -0
  179. claude_mpm/services/github/github_cli_service.py +397 -0
  180. claude_mpm/services/infrastructure/monitoring/__init__.py +1 -5
  181. claude_mpm/services/infrastructure/monitoring/aggregator.py +1 -6
  182. claude_mpm/services/infrastructure/monitoring/resources.py +1 -1
  183. claude_mpm/services/instructions/__init__.py +9 -0
  184. claude_mpm/services/instructions/instruction_cache_service.py +374 -0
  185. claude_mpm/services/local_ops/__init__.py +3 -13
  186. claude_mpm/services/local_ops/health_checks/__init__.py +1 -3
  187. claude_mpm/services/local_ops/health_manager.py +1 -4
  188. claude_mpm/services/local_ops/process_manager.py +1 -1
  189. claude_mpm/services/local_ops/resource_monitor.py +2 -2
  190. claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
  191. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +1 -6
  192. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -2
  193. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +1 -1
  194. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +6 -2
  195. claude_mpm/services/memory/optimizer.py +1 -1
  196. claude_mpm/services/model/model_router.py +8 -9
  197. claude_mpm/services/monitor/daemon.py +1 -1
  198. claude_mpm/services/monitor/server.py +2 -2
  199. claude_mpm/services/native_agent_converter.py +356 -0
  200. claude_mpm/services/port_manager.py +1 -1
  201. claude_mpm/services/pr/__init__.py +14 -0
  202. claude_mpm/services/pr/pr_template_service.py +329 -0
  203. claude_mpm/services/project/documentation_manager.py +2 -1
  204. claude_mpm/services/project/toolchain_analyzer.py +3 -1
  205. claude_mpm/services/runner_configuration_service.py +1 -0
  206. claude_mpm/services/self_upgrade_service.py +165 -7
  207. claude_mpm/services/skills/__init__.py +18 -0
  208. claude_mpm/services/skills/git_skill_source_manager.py +1169 -0
  209. claude_mpm/services/skills/skill_discovery_service.py +568 -0
  210. claude_mpm/services/skills_config.py +547 -0
  211. claude_mpm/services/skills_deployer.py +955 -0
  212. claude_mpm/services/socketio/handlers/connection.py +1 -1
  213. claude_mpm/services/socketio/handlers/git.py +2 -2
  214. claude_mpm/services/socketio/server/core.py +1 -4
  215. claude_mpm/services/socketio/server/main.py +1 -3
  216. claude_mpm/services/system_instructions_service.py +1 -3
  217. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +0 -3
  218. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +0 -1
  219. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +1 -1
  220. claude_mpm/services/unified/deployment_strategies/vercel.py +1 -5
  221. claude_mpm/services/unified/unified_deployment.py +1 -5
  222. claude_mpm/services/version_control/conflict_resolution.py +6 -4
  223. claude_mpm/services/visualization/__init__.py +1 -5
  224. claude_mpm/services/visualization/mermaid_generator.py +2 -3
  225. claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
  226. claude_mpm/skills/bundled/performance-profiling.md +6 -0
  227. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +2 -2
  228. claude_mpm/skills/skills_registry.py +0 -1
  229. claude_mpm/templates/questions/__init__.py +38 -0
  230. claude_mpm/templates/questions/base.py +193 -0
  231. claude_mpm/templates/questions/pr_strategy.py +311 -0
  232. claude_mpm/templates/questions/project_init.py +385 -0
  233. claude_mpm/templates/questions/ticket_mgmt.py +394 -0
  234. claude_mpm/tools/__main__.py +8 -8
  235. claude_mpm/tools/code_tree_analyzer/analysis.py +1 -1
  236. claude_mpm/utils/agent_dependency_loader.py +80 -13
  237. claude_mpm/utils/dependency_cache.py +3 -1
  238. claude_mpm/utils/gitignore.py +241 -0
  239. claude_mpm/utils/log_cleanup.py +3 -3
  240. claude_mpm/utils/progress.py +383 -0
  241. claude_mpm/utils/robust_installer.py +3 -5
  242. claude_mpm/utils/structured_questions.py +619 -0
  243. {claude_mpm-4.21.3.dist-info → claude_mpm-5.0.2.dist-info}/METADATA +429 -59
  244. {claude_mpm-4.21.3.dist-info → claude_mpm-5.0.2.dist-info}/RECORD +252 -425
  245. claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -17
  246. claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +0 -3
  247. claude_mpm/agents/templates/agent-manager.json +0 -273
  248. claude_mpm/agents/templates/agentic-coder-optimizer.json +0 -248
  249. claude_mpm/agents/templates/api_qa.json +0 -180
  250. claude_mpm/agents/templates/clerk-ops.json +0 -235
  251. claude_mpm/agents/templates/code_analyzer.json +0 -101
  252. claude_mpm/agents/templates/content-agent.json +0 -358
  253. claude_mpm/agents/templates/dart_engineer.json +0 -307
  254. claude_mpm/agents/templates/data_engineer.json +0 -225
  255. claude_mpm/agents/templates/documentation.json +0 -211
  256. claude_mpm/agents/templates/engineer.json +0 -210
  257. claude_mpm/agents/templates/gcp_ops_agent.json +0 -253
  258. claude_mpm/agents/templates/golang_engineer.json +0 -270
  259. claude_mpm/agents/templates/imagemagick.json +0 -264
  260. claude_mpm/agents/templates/java_engineer.json +0 -346
  261. claude_mpm/agents/templates/local_ops_agent.json +0 -1840
  262. claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +0 -39
  263. claude_mpm/agents/templates/logs/prompts/agent_engineer_20250901_010124_142.md +0 -400
  264. claude_mpm/agents/templates/memory_manager.json +0 -158
  265. claude_mpm/agents/templates/nextjs_engineer.json +0 -285
  266. claude_mpm/agents/templates/ops.json +0 -185
  267. claude_mpm/agents/templates/php-engineer.json +0 -287
  268. claude_mpm/agents/templates/product_owner.json +0 -338
  269. claude_mpm/agents/templates/project_organizer.json +0 -140
  270. claude_mpm/agents/templates/prompt-engineer.json +0 -737
  271. claude_mpm/agents/templates/python_engineer.json +0 -387
  272. claude_mpm/agents/templates/qa.json +0 -242
  273. claude_mpm/agents/templates/react_engineer.json +0 -238
  274. claude_mpm/agents/templates/refactoring_engineer.json +0 -276
  275. claude_mpm/agents/templates/research.json +0 -188
  276. claude_mpm/agents/templates/ruby-engineer.json +0 -280
  277. claude_mpm/agents/templates/rust_engineer.json +0 -275
  278. claude_mpm/agents/templates/security.json +0 -202
  279. claude_mpm/agents/templates/svelte-engineer.json +0 -225
  280. claude_mpm/agents/templates/ticketing.json +0 -177
  281. claude_mpm/agents/templates/typescript_engineer.json +0 -285
  282. claude_mpm/agents/templates/vercel_ops_agent.json +0 -412
  283. claude_mpm/agents/templates/version_control.json +0 -157
  284. claude_mpm/agents/templates/web_qa.json +0 -399
  285. claude_mpm/agents/templates/web_ui.json +0 -189
  286. claude_mpm/commands/mpm-tickets.md +0 -102
  287. claude_mpm/dashboard/.claude-mpm/socketio-instances.json +0 -1
  288. claude_mpm/dashboard/react/components/DataInspector/DataInspector.module.css +0 -188
  289. claude_mpm/dashboard/react/components/EventViewer/EventViewer.module.css +0 -156
  290. claude_mpm/dashboard/react/components/shared/ConnectionStatus.module.css +0 -38
  291. claude_mpm/dashboard/react/components/shared/FilterBar.module.css +0 -92
  292. claude_mpm/dashboard/static/archive/activity_dashboard_fixed.html +0 -248
  293. claude_mpm/dashboard/static/archive/activity_dashboard_test.html +0 -61
  294. claude_mpm/dashboard/static/archive/test_activity_connection.html +0 -179
  295. claude_mpm/dashboard/static/archive/test_claude_tree_tab.html +0 -68
  296. claude_mpm/dashboard/static/archive/test_dashboard.html +0 -409
  297. claude_mpm/dashboard/static/archive/test_dashboard_fixed.html +0 -519
  298. claude_mpm/dashboard/static/archive/test_dashboard_verification.html +0 -181
  299. claude_mpm/dashboard/static/archive/test_file_data.html +0 -315
  300. claude_mpm/dashboard/static/archive/test_file_tree_empty_state.html +0 -243
  301. claude_mpm/dashboard/static/archive/test_file_tree_fix.html +0 -234
  302. claude_mpm/dashboard/static/archive/test_file_tree_rename.html +0 -117
  303. claude_mpm/dashboard/static/archive/test_file_tree_tab.html +0 -115
  304. claude_mpm/dashboard/static/archive/test_file_viewer.html +0 -224
  305. claude_mpm/dashboard/static/archive/test_final_activity.html +0 -220
  306. claude_mpm/dashboard/static/archive/test_tab_fix.html +0 -139
  307. claude_mpm/dashboard/static/built/assets/events.DjpNxWNo.css +0 -1
  308. claude_mpm/dashboard/static/built/components/activity-tree.js +0 -2
  309. claude_mpm/dashboard/static/built/components/agent-hierarchy.js +0 -777
  310. claude_mpm/dashboard/static/built/components/agent-inference.js +0 -2
  311. claude_mpm/dashboard/static/built/components/build-tracker.js +0 -333
  312. claude_mpm/dashboard/static/built/components/code-simple.js +0 -857
  313. claude_mpm/dashboard/static/built/components/code-tree/tree-breadcrumb.js +0 -353
  314. claude_mpm/dashboard/static/built/components/code-tree/tree-constants.js +0 -235
  315. claude_mpm/dashboard/static/built/components/code-tree/tree-search.js +0 -409
  316. claude_mpm/dashboard/static/built/components/code-tree/tree-utils.js +0 -435
  317. claude_mpm/dashboard/static/built/components/code-tree.js +0 -2
  318. claude_mpm/dashboard/static/built/components/code-viewer.js +0 -2
  319. claude_mpm/dashboard/static/built/components/connection-debug.js +0 -654
  320. claude_mpm/dashboard/static/built/components/diff-viewer.js +0 -891
  321. claude_mpm/dashboard/static/built/components/event-processor.js +0 -2
  322. claude_mpm/dashboard/static/built/components/event-viewer.js +0 -2
  323. claude_mpm/dashboard/static/built/components/export-manager.js +0 -2
  324. claude_mpm/dashboard/static/built/components/file-change-tracker.js +0 -443
  325. claude_mpm/dashboard/static/built/components/file-change-viewer.js +0 -690
  326. claude_mpm/dashboard/static/built/components/file-tool-tracker.js +0 -2
  327. claude_mpm/dashboard/static/built/components/file-viewer.js +0 -2
  328. claude_mpm/dashboard/static/built/components/hud-library-loader.js +0 -2
  329. claude_mpm/dashboard/static/built/components/hud-manager.js +0 -2
  330. claude_mpm/dashboard/static/built/components/hud-visualizer.js +0 -2
  331. claude_mpm/dashboard/static/built/components/module-viewer.js +0 -2
  332. claude_mpm/dashboard/static/built/components/nav-bar.js +0 -145
  333. claude_mpm/dashboard/static/built/components/page-structure.js +0 -429
  334. claude_mpm/dashboard/static/built/components/session-manager.js +0 -2
  335. claude_mpm/dashboard/static/built/components/socket-manager.js +0 -2
  336. claude_mpm/dashboard/static/built/components/ui-state-manager.js +0 -2
  337. claude_mpm/dashboard/static/built/components/unified-data-viewer.js +0 -2
  338. claude_mpm/dashboard/static/built/components/working-directory.js +0 -2
  339. claude_mpm/dashboard/static/built/connection-manager.js +0 -536
  340. claude_mpm/dashboard/static/built/dashboard.js +0 -2
  341. claude_mpm/dashboard/static/built/extension-error-handler.js +0 -164
  342. claude_mpm/dashboard/static/built/react/events.js +0 -30
  343. claude_mpm/dashboard/static/built/shared/dom-helpers.js +0 -396
  344. claude_mpm/dashboard/static/built/shared/event-bus.js +0 -330
  345. claude_mpm/dashboard/static/built/shared/event-filter-service.js +0 -540
  346. claude_mpm/dashboard/static/built/shared/logger.js +0 -385
  347. claude_mpm/dashboard/static/built/shared/page-structure.js +0 -249
  348. claude_mpm/dashboard/static/built/shared/tooltip-service.js +0 -253
  349. claude_mpm/dashboard/static/built/socket-client.js +0 -2
  350. claude_mpm/dashboard/static/built/tab-isolation-fix.js +0 -185
  351. claude_mpm/dashboard/static/dist/assets/events.DjpNxWNo.css +0 -1
  352. claude_mpm/dashboard/static/dist/components/activity-tree.js +0 -2
  353. claude_mpm/dashboard/static/dist/components/agent-inference.js +0 -2
  354. claude_mpm/dashboard/static/dist/components/code-tree.js +0 -2
  355. claude_mpm/dashboard/static/dist/components/code-viewer.js +0 -2
  356. claude_mpm/dashboard/static/dist/components/event-processor.js +0 -2
  357. claude_mpm/dashboard/static/dist/components/event-viewer.js +0 -2
  358. claude_mpm/dashboard/static/dist/components/export-manager.js +0 -2
  359. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +0 -2
  360. claude_mpm/dashboard/static/dist/components/file-viewer.js +0 -2
  361. claude_mpm/dashboard/static/dist/components/hud-library-loader.js +0 -2
  362. claude_mpm/dashboard/static/dist/components/hud-manager.js +0 -2
  363. claude_mpm/dashboard/static/dist/components/hud-visualizer.js +0 -2
  364. claude_mpm/dashboard/static/dist/components/module-viewer.js +0 -2
  365. claude_mpm/dashboard/static/dist/components/session-manager.js +0 -2
  366. claude_mpm/dashboard/static/dist/components/socket-manager.js +0 -2
  367. claude_mpm/dashboard/static/dist/components/ui-state-manager.js +0 -2
  368. claude_mpm/dashboard/static/dist/components/unified-data-viewer.js +0 -2
  369. claude_mpm/dashboard/static/dist/components/working-directory.js +0 -2
  370. claude_mpm/dashboard/static/dist/dashboard.js +0 -2
  371. claude_mpm/dashboard/static/dist/react/events.js +0 -30
  372. claude_mpm/dashboard/static/dist/socket-client.js +0 -2
  373. claude_mpm/dashboard/static/events.html +0 -607
  374. claude_mpm/dashboard/static/index.html +0 -635
  375. claude_mpm/dashboard/static/js/shared/dom-helpers.js +0 -396
  376. claude_mpm/dashboard/static/js/shared/event-bus.js +0 -330
  377. claude_mpm/dashboard/static/js/shared/logger.js +0 -385
  378. claude_mpm/dashboard/static/js/shared/tooltip-service.js +0 -253
  379. claude_mpm/dashboard/static/js/stores/dashboard-store.js +0 -562
  380. claude_mpm/dashboard/static/legacy/activity.html +0 -736
  381. claude_mpm/dashboard/static/legacy/agents.html +0 -786
  382. claude_mpm/dashboard/static/legacy/files.html +0 -747
  383. claude_mpm/dashboard/static/legacy/tools.html +0 -831
  384. claude_mpm/dashboard/static/monitors.html +0 -431
  385. claude_mpm/dashboard/static/production/events.html +0 -659
  386. claude_mpm/dashboard/static/production/main.html +0 -698
  387. claude_mpm/dashboard/static/production/monitors.html +0 -483
  388. claude_mpm/dashboard/static/test-archive/dashboard.html +0 -635
  389. claude_mpm/dashboard/static/test-archive/debug-events.html +0 -147
  390. claude_mpm/dashboard/static/test-archive/test-navigation.html +0 -256
  391. claude_mpm/dashboard/static/test-archive/test-react-exports.html +0 -180
  392. claude_mpm/dashboard/static/test-archive/test_debug.html +0 -25
  393. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +0 -79
  394. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +0 -178
  395. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +0 -577
  396. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +0 -467
  397. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +0 -537
  398. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +0 -730
  399. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +0 -112
  400. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +0 -146
  401. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +0 -412
  402. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +0 -81
  403. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +0 -362
  404. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +0 -312
  405. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +0 -152
  406. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +0 -668
  407. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +0 -587
  408. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +0 -438
  409. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +0 -391
  410. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +0 -119
  411. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +0 -148
  412. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +0 -483
  413. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +0 -452
  414. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +0 -449
  415. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +0 -411
  416. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +0 -14
  417. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +0 -58
  418. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +0 -68
  419. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +0 -69
  420. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +0 -131
  421. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +0 -325
  422. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +0 -490
  423. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +0 -425
  424. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +0 -499
  425. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +0 -86
  426. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +0 -43
  427. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +0 -47
  428. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +0 -65
  429. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +0 -30
  430. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +0 -16
  431. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +0 -160
  432. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +0 -412
  433. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +0 -602
  434. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +0 -915
  435. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +0 -916
  436. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +0 -752
  437. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +0 -1237
  438. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +0 -189
  439. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +0 -500
  440. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +0 -464
  441. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +0 -619
  442. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +0 -437
  443. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +0 -231
  444. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +0 -170
  445. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +0 -602
  446. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +0 -821
  447. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +0 -742
  448. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +0 -726
  449. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +0 -764
  450. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +0 -831
  451. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +0 -226
  452. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +0 -901
  453. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +0 -901
  454. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +0 -775
  455. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +0 -937
  456. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +0 -770
  457. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +0 -961
  458. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +0 -119
  459. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +0 -253
  460. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +0 -145
  461. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +0 -543
  462. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +0 -741
  463. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +0 -470
  464. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +0 -458
  465. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +0 -639
  466. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +0 -140
  467. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +0 -572
  468. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +0 -411
  469. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +0 -569
  470. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +0 -695
  471. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +0 -184
  472. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +0 -459
  473. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +0 -479
  474. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +0 -687
  475. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +0 -758
  476. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +0 -868
  477. /claude_mpm/agents/templates/{git_file_tracking.md → git-file-tracking.md} +0 -0
  478. /claude_mpm/agents/templates/{pm_examples.md → pm-examples.md} +0 -0
  479. /claude_mpm/agents/templates/{response_format.md → response-format.md} +0 -0
  480. /claude_mpm/agents/templates/{validation_templates.md → validation-templates.md} +0 -0
  481. {claude_mpm-4.21.3.dist-info → claude_mpm-5.0.2.dist-info}/WHEEL +0 -0
  482. {claude_mpm-4.21.3.dist-info → claude_mpm-5.0.2.dist-info}/entry_points.txt +0 -0
  483. {claude_mpm-4.21.3.dist-info → claude_mpm-5.0.2.dist-info}/licenses/LICENSE +0 -0
  484. {claude_mpm-4.21.3.dist-info → claude_mpm-5.0.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,13 @@
1
+ """Git source sync services for agent templates.
2
+
3
+ This module provides services for syncing agent templates from remote
4
+ Git repositories, with ETag-based caching for efficient updates and
5
+ SQLite-based state tracking.
6
+ """
7
+
8
+ from claude_mpm.services.agents.sources.agent_sync_state import AgentSyncState
9
+ from claude_mpm.services.agents.sources.git_source_sync_service import (
10
+ GitSourceSyncService,
11
+ )
12
+
13
+ __all__ = ["AgentSyncState", "GitSourceSyncService"]
@@ -0,0 +1,516 @@
1
+ """SQLite-based state tracking for agent sync operations.
2
+
3
+ This service manages sync state for agent files from Git sources, providing:
4
+ - Per-file SHA-256 content hash tracking
5
+ - Source metadata (URLs, last commit SHA, ETags)
6
+ - Complete sync history audit trail
7
+ - Change detection for efficient incremental updates
8
+
9
+ Database Location: ~/.config/claude-mpm/agent_sync.db
10
+ Thread Safety: Uses connection-per-operation pattern (safe for single-threaded use)
11
+ Performance: Optimized with indexes; expected <10ms per operation
12
+ """
13
+
14
+ import logging
15
+ import sqlite3
16
+ from contextlib import contextmanager
17
+ from datetime import datetime, timedelta, timezone
18
+ from pathlib import Path
19
+ from typing import Any, Dict, List, Optional
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ class AgentSyncStateError(Exception):
25
+ """Base exception for sync state errors."""
26
+
27
+
28
+ class DatabaseError(AgentSyncStateError):
29
+ """Database operation errors."""
30
+
31
+
32
+ class AgentSyncState:
33
+ """Service for tracking agent sync state in SQLite database.
34
+
35
+ Responsibilities:
36
+ - Manage SQLite connection lifecycle
37
+ - Track per-file content hashes (SHA-256)
38
+ - Record sync history with timestamps
39
+ - Query file change status
40
+ - Provide migration utilities
41
+
42
+ Design Decision: Connection-per-operation pattern
43
+
44
+ Rationale: Simplifies connection management and prevents connection leaks.
45
+ SQLite allows concurrent reads but serializes writes, so connection pooling
46
+ provides minimal benefit for our read-heavy workload.
47
+
48
+ Trade-offs:
49
+ - Simplicity: No pool management overhead
50
+ - Safety: Automatic cleanup via context manager
51
+ - Performance: Negligible overhead (<1ms per connection)
52
+
53
+ Extension Points: Can add connection pooling if multi-threaded access needed.
54
+ """
55
+
56
+ # Schema version for migrations
57
+ SCHEMA_VERSION = 1
58
+
59
+ def __init__(self, db_path: Optional[Path] = None):
60
+ """Initialize sync state service.
61
+
62
+ Args:
63
+ db_path: Path to SQLite database (defaults to ~/.config/claude-mpm/agent_sync.db)
64
+ """
65
+ if db_path:
66
+ self.db_path = Path(db_path)
67
+ else:
68
+ # Default location: ~/.config/claude-mpm/agent_sync.db
69
+ config_dir = Path.home() / ".config" / "claude-mpm"
70
+ config_dir.mkdir(parents=True, exist_ok=True)
71
+ self.db_path = config_dir / "agent_sync.db"
72
+
73
+ # Initialize database
74
+ self._initialize_database()
75
+
76
+ @contextmanager
77
+ def _get_connection(self):
78
+ """Context manager for database connections.
79
+
80
+ Yields:
81
+ sqlite3.Connection with foreign keys enabled and row factory
82
+
83
+ Error Handling:
84
+ - Exception during transaction: Rolls back automatically
85
+ - Connection errors: Propagates to caller
86
+ - Cleanup: Always closes connection
87
+ """
88
+ conn = sqlite3.connect(str(self.db_path))
89
+ conn.row_factory = sqlite3.Row # Enable dict-like access
90
+ conn.execute("PRAGMA foreign_keys = ON") # Enable FK constraints
91
+ try:
92
+ yield conn
93
+ conn.commit()
94
+ except Exception:
95
+ conn.rollback()
96
+ raise
97
+ finally:
98
+ conn.close()
99
+
100
+ def _initialize_database(self):
101
+ """Initialize database schema if not exists.
102
+
103
+ Creates all tables, indexes, and metadata on first run.
104
+ Verifies schema version on subsequent runs.
105
+ """
106
+ with self._get_connection() as conn:
107
+ # Check if database exists and has schema
108
+ cursor = conn.execute(
109
+ "SELECT name FROM sqlite_master WHERE type='table' AND name='sources'"
110
+ )
111
+ if cursor.fetchone() is None:
112
+ # Database is new, create schema
113
+ self._create_schema(conn)
114
+ logger.info(f"Initialized sync state database: {self.db_path}")
115
+ else:
116
+ # Verify schema version
117
+ version = self._get_schema_version(conn)
118
+ if version != self.SCHEMA_VERSION:
119
+ logger.warning(
120
+ f"Schema version mismatch: expected {self.SCHEMA_VERSION}, found {version}"
121
+ )
122
+ # TODO: Implement migration in future ticket
123
+
124
+ def _create_schema(self, conn: sqlite3.Connection):
125
+ """Create database schema with all tables and indexes.
126
+
127
+ Schema Design:
128
+ - sources: Track Git repositories or file sources
129
+ - agent_files: Track individual files and content hashes
130
+ - sync_history: Audit trail of all sync operations
131
+ - schema_metadata: Schema versioning for migrations
132
+ """
133
+ conn.executescript(
134
+ """
135
+ -- Sources table: Track Git repositories or file sources
136
+ CREATE TABLE sources (
137
+ id TEXT PRIMARY KEY, -- Source identifier (e.g., "github-remote", "local-project")
138
+ url TEXT NOT NULL, -- Source URL or file path
139
+ last_sha TEXT, -- Last synced commit SHA (Git sources only)
140
+ last_sync_time TEXT, -- ISO 8601 timestamp of last sync
141
+ etag TEXT, -- HTTP ETag for GitHub raw URLs
142
+ enabled INTEGER DEFAULT 1, -- 0=disabled, 1=enabled
143
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP,
144
+ updated_at TEXT DEFAULT CURRENT_TIMESTAMP
145
+ );
146
+
147
+ -- Agent files table: Track individual files and content hashes
148
+ CREATE TABLE agent_files (
149
+ source_id TEXT NOT NULL, -- FK to sources.id
150
+ file_path TEXT NOT NULL, -- Relative path (e.g., "research.md")
151
+ content_sha TEXT NOT NULL, -- SHA-256 hash of file content
152
+ local_path TEXT, -- Absolute path to cached file
153
+ synced_at TEXT NOT NULL, -- ISO 8601 timestamp when file was synced
154
+ file_size INTEGER, -- File size in bytes
155
+ PRIMARY KEY (source_id, file_path),
156
+ FOREIGN KEY (source_id) REFERENCES sources(id) ON DELETE CASCADE
157
+ );
158
+
159
+ -- Sync history table: Audit trail of all sync operations
160
+ CREATE TABLE sync_history (
161
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
162
+ source_id TEXT NOT NULL, -- FK to sources.id
163
+ sync_time TEXT NOT NULL, -- ISO 8601 timestamp
164
+ status TEXT NOT NULL, -- 'success', 'partial', 'error'
165
+ files_synced INTEGER DEFAULT 0, -- Number of files downloaded
166
+ files_cached INTEGER DEFAULT 0, -- Number of cache hits
167
+ files_failed INTEGER DEFAULT 0, -- Number of failed downloads
168
+ error_message TEXT, -- Error details if status='error'
169
+ duration_ms INTEGER, -- Sync duration in milliseconds
170
+ FOREIGN KEY (source_id) REFERENCES sources(id) ON DELETE CASCADE
171
+ );
172
+
173
+ -- Performance indexes
174
+ CREATE INDEX idx_agent_files_source ON agent_files(source_id);
175
+ CREATE INDEX idx_agent_files_path ON agent_files(file_path);
176
+ CREATE INDEX idx_sync_history_source_time ON sync_history(source_id, sync_time DESC);
177
+ CREATE INDEX idx_sync_history_status ON sync_history(status);
178
+
179
+ -- Metadata table for schema versioning
180
+ CREATE TABLE schema_metadata (
181
+ key TEXT PRIMARY KEY,
182
+ value TEXT NOT NULL
183
+ );
184
+
185
+ INSERT INTO schema_metadata (key, value) VALUES ('version', '1');
186
+ INSERT INTO schema_metadata (key, value) VALUES ('created_at', datetime('now'));
187
+ """
188
+ )
189
+
190
+ def _get_schema_version(self, conn: sqlite3.Connection) -> int:
191
+ """Get current schema version.
192
+
193
+ Args:
194
+ conn: Database connection
195
+
196
+ Returns:
197
+ Schema version number (0 if schema_metadata table doesn't exist)
198
+ """
199
+ try:
200
+ cursor = conn.execute(
201
+ "SELECT value FROM schema_metadata WHERE key = 'version'"
202
+ )
203
+ row = cursor.fetchone()
204
+ return int(row[0]) if row else 0
205
+ except sqlite3.OperationalError:
206
+ return 0
207
+
208
+ # ==============================================================================
209
+ # SOURCE MANAGEMENT
210
+ # ==============================================================================
211
+
212
+ def register_source(self, source_id: str, url: str, enabled: bool = True) -> None:
213
+ """Register or update a sync source.
214
+
215
+ Args:
216
+ source_id: Unique source identifier (e.g., "github-remote")
217
+ url: Source URL or file path
218
+ enabled: Whether source is enabled for sync
219
+
220
+ Example:
221
+ sync_state.register_source(
222
+ source_id="github-remote",
223
+ url="https://raw.githubusercontent.com/bobmatnyc/claude-mpm-agents/main",
224
+ enabled=True
225
+ )
226
+ """
227
+ with self._get_connection() as conn:
228
+ conn.execute(
229
+ """
230
+ INSERT INTO sources (id, url, enabled, updated_at)
231
+ VALUES (?, ?, ?, ?)
232
+ ON CONFLICT(id) DO UPDATE SET
233
+ url = excluded.url,
234
+ enabled = excluded.enabled,
235
+ updated_at = excluded.updated_at
236
+ """,
237
+ (source_id, url, int(enabled), datetime.now(timezone.utc).isoformat()),
238
+ )
239
+ logger.debug(f"Registered source: {source_id} -> {url}")
240
+
241
+ def update_source_sync_metadata(
242
+ self,
243
+ source_id: str,
244
+ last_sha: Optional[str] = None,
245
+ etag: Optional[str] = None,
246
+ ) -> None:
247
+ """Update source sync metadata (commit SHA, ETag).
248
+
249
+ Args:
250
+ source_id: Source identifier
251
+ last_sha: Latest commit SHA (Git sources)
252
+ etag: HTTP ETag (GitHub raw URLs)
253
+
254
+ Example:
255
+ sync_state.update_source_sync_metadata(
256
+ source_id="github-remote",
257
+ last_sha="abc123def456",
258
+ etag='"W/abc123"'
259
+ )
260
+ """
261
+ with self._get_connection() as conn:
262
+ conn.execute(
263
+ """
264
+ UPDATE sources
265
+ SET last_sha = ?, etag = ?, last_sync_time = ?, updated_at = ?
266
+ WHERE id = ?
267
+ """,
268
+ (
269
+ last_sha,
270
+ etag,
271
+ datetime.now(timezone.utc).isoformat(),
272
+ datetime.now(timezone.utc).isoformat(),
273
+ source_id,
274
+ ),
275
+ )
276
+ logger.debug(f"Updated source metadata: {source_id}")
277
+
278
+ def get_source_info(self, source_id: str) -> Optional[Dict[str, Any]]:
279
+ """Get source metadata.
280
+
281
+ Args:
282
+ source_id: Source identifier
283
+
284
+ Returns:
285
+ Source metadata dict or None if not found
286
+
287
+ Example:
288
+ >>> info = sync_state.get_source_info("github-remote")
289
+ >>> print(info["url"])
290
+ https://raw.githubusercontent.com/...
291
+ """
292
+ with self._get_connection() as conn:
293
+ cursor = conn.execute("SELECT * FROM sources WHERE id = ?", (source_id,))
294
+ row = cursor.fetchone()
295
+ return dict(row) if row else None
296
+
297
+ def get_all_sources(self, enabled_only: bool = False) -> List[Dict[str, Any]]:
298
+ """Get all registered sources.
299
+
300
+ Args:
301
+ enabled_only: Only return enabled sources
302
+
303
+ Returns:
304
+ List of source metadata dicts
305
+ """
306
+ with self._get_connection() as conn:
307
+ query = "SELECT * FROM sources"
308
+ if enabled_only:
309
+ query += " WHERE enabled = 1"
310
+ cursor = conn.execute(query)
311
+ return [dict(row) for row in cursor.fetchall()]
312
+
313
+ # ==============================================================================
314
+ # FILE TRACKING
315
+ # ==============================================================================
316
+
317
+ def track_file(
318
+ self,
319
+ source_id: str,
320
+ file_path: str,
321
+ content_sha: str,
322
+ local_path: Optional[str] = None,
323
+ file_size: Optional[int] = None,
324
+ ) -> None:
325
+ """Track agent file with content hash.
326
+
327
+ Args:
328
+ source_id: Source identifier
329
+ file_path: Relative file path (e.g., "research.md")
330
+ content_sha: SHA-256 hash of file content
331
+ local_path: Absolute path to cached file
332
+ file_size: File size in bytes
333
+
334
+ Example:
335
+ sync_state.track_file(
336
+ source_id="github-remote",
337
+ file_path="research.md",
338
+ content_sha="abc123def456...",
339
+ local_path="/home/user/.claude-mpm/cache/research.md",
340
+ file_size=2048
341
+ )
342
+ """
343
+ with self._get_connection() as conn:
344
+ conn.execute(
345
+ """
346
+ INSERT INTO agent_files (source_id, file_path, content_sha, local_path, synced_at, file_size)
347
+ VALUES (?, ?, ?, ?, ?, ?)
348
+ ON CONFLICT(source_id, file_path) DO UPDATE SET
349
+ content_sha = excluded.content_sha,
350
+ local_path = excluded.local_path,
351
+ synced_at = excluded.synced_at,
352
+ file_size = excluded.file_size
353
+ """,
354
+ (
355
+ source_id,
356
+ file_path,
357
+ content_sha,
358
+ local_path,
359
+ datetime.now(timezone.utc).isoformat(),
360
+ file_size,
361
+ ),
362
+ )
363
+ logger.debug(f"Tracked file: {source_id}/{file_path} -> {content_sha[:8]}...")
364
+
365
+ def get_file_hash(self, source_id: str, file_path: str) -> Optional[str]:
366
+ """Get stored content hash for file.
367
+
368
+ Args:
369
+ source_id: Source identifier
370
+ file_path: Relative file path
371
+
372
+ Returns:
373
+ SHA-256 hash or None if not tracked
374
+ """
375
+ with self._get_connection() as conn:
376
+ cursor = conn.execute(
377
+ "SELECT content_sha FROM agent_files WHERE source_id = ? AND file_path = ?",
378
+ (source_id, file_path),
379
+ )
380
+ row = cursor.fetchone()
381
+ return row["content_sha"] if row else None
382
+
383
+ def has_file_changed(
384
+ self, source_id: str, file_path: str, current_sha: str
385
+ ) -> bool:
386
+ """Check if file content has changed.
387
+
388
+ Args:
389
+ source_id: Source identifier
390
+ file_path: Relative file path
391
+ current_sha: Current SHA-256 hash
392
+
393
+ Returns:
394
+ True if changed or not tracked, False if unchanged
395
+
396
+ Example:
397
+ >>> changed = sync_state.has_file_changed(
398
+ ... "github-remote", "research.md", "abc123..."
399
+ ... )
400
+ >>> if changed:
401
+ ... print("File needs update")
402
+ """
403
+ stored_sha = self.get_file_hash(source_id, file_path)
404
+ if stored_sha is None:
405
+ return True # Not tracked = changed
406
+ return stored_sha != current_sha
407
+
408
+ # ==============================================================================
409
+ # SYNC HISTORY
410
+ # ==============================================================================
411
+
412
+ def record_sync_result(
413
+ self,
414
+ source_id: str,
415
+ status: str,
416
+ files_synced: int = 0,
417
+ files_cached: int = 0,
418
+ files_failed: int = 0,
419
+ error_message: Optional[str] = None,
420
+ duration_ms: Optional[int] = None,
421
+ ) -> int:
422
+ """Record sync operation result.
423
+
424
+ Args:
425
+ source_id: Source identifier
426
+ status: 'success', 'partial', or 'error'
427
+ files_synced: Number of files downloaded
428
+ files_cached: Number of cache hits
429
+ files_failed: Number of failed downloads
430
+ error_message: Error details if status='error'
431
+ duration_ms: Sync duration in milliseconds
432
+
433
+ Returns:
434
+ Sync history record ID
435
+
436
+ Example:
437
+ record_id = sync_state.record_sync_result(
438
+ source_id="github-remote",
439
+ status="success",
440
+ files_synced=5,
441
+ files_cached=3,
442
+ duration_ms=1500
443
+ )
444
+ """
445
+ with self._get_connection() as conn:
446
+ cursor = conn.execute(
447
+ """
448
+ INSERT INTO sync_history (
449
+ source_id, sync_time, status, files_synced, files_cached,
450
+ files_failed, error_message, duration_ms
451
+ )
452
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
453
+ """,
454
+ (
455
+ source_id,
456
+ datetime.now(timezone.utc).isoformat(),
457
+ status,
458
+ files_synced,
459
+ files_cached,
460
+ files_failed,
461
+ error_message,
462
+ duration_ms,
463
+ ),
464
+ )
465
+ return cursor.lastrowid
466
+
467
+ def get_sync_history(self, source_id: str, limit: int = 10) -> List[Dict[str, Any]]:
468
+ """Get recent sync history for source.
469
+
470
+ Args:
471
+ source_id: Source identifier
472
+ limit: Maximum number of records
473
+
474
+ Returns:
475
+ List of sync history records (most recent first)
476
+
477
+ Example:
478
+ >>> history = sync_state.get_sync_history("github-remote", limit=5)
479
+ >>> for record in history:
480
+ ... print(f"{record['sync_time']}: {record['status']}")
481
+ """
482
+ with self._get_connection() as conn:
483
+ cursor = conn.execute(
484
+ """
485
+ SELECT * FROM sync_history
486
+ WHERE source_id = ?
487
+ ORDER BY sync_time DESC
488
+ LIMIT ?
489
+ """,
490
+ (source_id, limit),
491
+ )
492
+ return [dict(row) for row in cursor.fetchall()]
493
+
494
+ def cleanup_old_history(self, days: int = 30) -> int:
495
+ """Remove sync history older than specified days.
496
+
497
+ Args:
498
+ days: Number of days to retain
499
+
500
+ Returns:
501
+ Number of records deleted
502
+
503
+ Example:
504
+ deleted = sync_state.cleanup_old_history(days=30)
505
+ print(f"Cleaned up {deleted} old sync records")
506
+ """
507
+ cutoff = (datetime.now(timezone.utc) - timedelta(days=days)).isoformat()
508
+
509
+ with self._get_connection() as conn:
510
+ cursor = conn.execute(
511
+ "DELETE FROM sync_history WHERE sync_time < ?", (cutoff,)
512
+ )
513
+ deleted = cursor.rowcount
514
+
515
+ logger.info(f"Cleaned up {deleted} sync history records older than {days} days")
516
+ return deleted