claude-mpm 5.4.41__py3-none-any.whl → 5.6.72__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 (490) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
  3. claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
  4. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +109 -1925
  5. claude_mpm/agents/PM_INSTRUCTIONS.md +161 -298
  6. claude_mpm/agents/WORKFLOW.md +2 -0
  7. claude_mpm/agents/templates/circuit-breakers.md +26 -17
  8. claude_mpm/auth/__init__.py +35 -0
  9. claude_mpm/auth/callback_server.py +328 -0
  10. claude_mpm/auth/models.py +104 -0
  11. claude_mpm/auth/oauth_manager.py +266 -0
  12. claude_mpm/auth/providers/__init__.py +12 -0
  13. claude_mpm/auth/providers/base.py +165 -0
  14. claude_mpm/auth/providers/google.py +261 -0
  15. claude_mpm/auth/token_storage.py +252 -0
  16. claude_mpm/cli/__init__.py +5 -1
  17. claude_mpm/cli/commands/agents.py +2 -4
  18. claude_mpm/cli/commands/agents_reconcile.py +197 -0
  19. claude_mpm/cli/commands/autotodos.py +566 -0
  20. claude_mpm/cli/commands/commander.py +216 -0
  21. claude_mpm/cli/commands/configure.py +620 -21
  22. claude_mpm/cli/commands/configure_agent_display.py +3 -1
  23. claude_mpm/cli/commands/hook_errors.py +60 -60
  24. claude_mpm/cli/commands/mcp.py +29 -17
  25. claude_mpm/cli/commands/mcp_command_router.py +39 -0
  26. claude_mpm/cli/commands/mcp_service_commands.py +304 -0
  27. claude_mpm/cli/commands/monitor.py +2 -2
  28. claude_mpm/cli/commands/mpm_init/core.py +15 -8
  29. claude_mpm/cli/commands/oauth.py +481 -0
  30. claude_mpm/cli/commands/profile.py +9 -10
  31. claude_mpm/cli/commands/run.py +35 -3
  32. claude_mpm/cli/commands/skill_source.py +51 -2
  33. claude_mpm/cli/commands/skills.py +182 -32
  34. claude_mpm/cli/executor.py +129 -16
  35. claude_mpm/cli/helpers.py +1 -1
  36. claude_mpm/cli/interactive/__init__.py +10 -0
  37. claude_mpm/cli/interactive/agent_wizard.py +30 -50
  38. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  39. claude_mpm/cli/interactive/skill_selector.py +481 -0
  40. claude_mpm/cli/parsers/base_parser.py +89 -1
  41. claude_mpm/cli/parsers/commander_parser.py +116 -0
  42. claude_mpm/cli/parsers/mcp_parser.py +79 -0
  43. claude_mpm/cli/parsers/oauth_parser.py +165 -0
  44. claude_mpm/cli/parsers/profile_parser.py +0 -1
  45. claude_mpm/cli/parsers/run_parser.py +10 -0
  46. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  47. claude_mpm/cli/parsers/skills_parser.py +2 -3
  48. claude_mpm/cli/startup.py +662 -524
  49. claude_mpm/cli/startup_display.py +76 -7
  50. claude_mpm/cli/startup_logging.py +2 -2
  51. claude_mpm/cli/utils.py +7 -3
  52. claude_mpm/commander/__init__.py +78 -0
  53. claude_mpm/commander/adapters/__init__.py +60 -0
  54. claude_mpm/commander/adapters/auggie.py +260 -0
  55. claude_mpm/commander/adapters/base.py +288 -0
  56. claude_mpm/commander/adapters/claude_code.py +392 -0
  57. claude_mpm/commander/adapters/codex.py +237 -0
  58. claude_mpm/commander/adapters/communication.py +366 -0
  59. claude_mpm/commander/adapters/example_usage.py +310 -0
  60. claude_mpm/commander/adapters/mpm.py +389 -0
  61. claude_mpm/commander/adapters/registry.py +204 -0
  62. claude_mpm/commander/api/__init__.py +16 -0
  63. claude_mpm/commander/api/app.py +121 -0
  64. claude_mpm/commander/api/errors.py +133 -0
  65. claude_mpm/commander/api/routes/__init__.py +8 -0
  66. claude_mpm/commander/api/routes/events.py +184 -0
  67. claude_mpm/commander/api/routes/inbox.py +171 -0
  68. claude_mpm/commander/api/routes/messages.py +148 -0
  69. claude_mpm/commander/api/routes/projects.py +271 -0
  70. claude_mpm/commander/api/routes/sessions.py +226 -0
  71. claude_mpm/commander/api/routes/work.py +296 -0
  72. claude_mpm/commander/api/schemas.py +186 -0
  73. claude_mpm/commander/chat/__init__.py +7 -0
  74. claude_mpm/commander/chat/cli.py +149 -0
  75. claude_mpm/commander/chat/commands.py +122 -0
  76. claude_mpm/commander/chat/repl.py +1821 -0
  77. claude_mpm/commander/config.py +51 -0
  78. claude_mpm/commander/config_loader.py +115 -0
  79. claude_mpm/commander/core/__init__.py +10 -0
  80. claude_mpm/commander/core/block_manager.py +325 -0
  81. claude_mpm/commander/core/response_manager.py +323 -0
  82. claude_mpm/commander/daemon.py +603 -0
  83. claude_mpm/commander/env_loader.py +59 -0
  84. claude_mpm/commander/events/__init__.py +26 -0
  85. claude_mpm/commander/events/manager.py +392 -0
  86. claude_mpm/commander/frameworks/__init__.py +12 -0
  87. claude_mpm/commander/frameworks/base.py +233 -0
  88. claude_mpm/commander/frameworks/claude_code.py +58 -0
  89. claude_mpm/commander/frameworks/mpm.py +57 -0
  90. claude_mpm/commander/git/__init__.py +5 -0
  91. claude_mpm/commander/git/worktree_manager.py +212 -0
  92. claude_mpm/commander/inbox/__init__.py +16 -0
  93. claude_mpm/commander/inbox/dedup.py +128 -0
  94. claude_mpm/commander/inbox/inbox.py +224 -0
  95. claude_mpm/commander/inbox/models.py +70 -0
  96. claude_mpm/commander/instance_manager.py +865 -0
  97. claude_mpm/commander/llm/__init__.py +6 -0
  98. claude_mpm/commander/llm/openrouter_client.py +167 -0
  99. claude_mpm/commander/llm/summarizer.py +70 -0
  100. claude_mpm/commander/memory/__init__.py +45 -0
  101. claude_mpm/commander/memory/compression.py +347 -0
  102. claude_mpm/commander/memory/embeddings.py +230 -0
  103. claude_mpm/commander/memory/entities.py +310 -0
  104. claude_mpm/commander/memory/example_usage.py +290 -0
  105. claude_mpm/commander/memory/integration.py +325 -0
  106. claude_mpm/commander/memory/search.py +381 -0
  107. claude_mpm/commander/memory/store.py +657 -0
  108. claude_mpm/commander/models/__init__.py +18 -0
  109. claude_mpm/commander/models/events.py +127 -0
  110. claude_mpm/commander/models/project.py +162 -0
  111. claude_mpm/commander/models/work.py +214 -0
  112. claude_mpm/commander/parsing/__init__.py +20 -0
  113. claude_mpm/commander/parsing/extractor.py +132 -0
  114. claude_mpm/commander/parsing/output_parser.py +270 -0
  115. claude_mpm/commander/parsing/patterns.py +100 -0
  116. claude_mpm/commander/persistence/__init__.py +11 -0
  117. claude_mpm/commander/persistence/event_store.py +274 -0
  118. claude_mpm/commander/persistence/state_store.py +403 -0
  119. claude_mpm/commander/persistence/work_store.py +164 -0
  120. claude_mpm/commander/polling/__init__.py +13 -0
  121. claude_mpm/commander/polling/event_detector.py +104 -0
  122. claude_mpm/commander/polling/output_buffer.py +49 -0
  123. claude_mpm/commander/polling/output_poller.py +153 -0
  124. claude_mpm/commander/project_session.py +268 -0
  125. claude_mpm/commander/proxy/__init__.py +12 -0
  126. claude_mpm/commander/proxy/formatter.py +89 -0
  127. claude_mpm/commander/proxy/output_handler.py +191 -0
  128. claude_mpm/commander/proxy/relay.py +155 -0
  129. claude_mpm/commander/registry.py +410 -0
  130. claude_mpm/commander/runtime/__init__.py +10 -0
  131. claude_mpm/commander/runtime/executor.py +191 -0
  132. claude_mpm/commander/runtime/monitor.py +346 -0
  133. claude_mpm/commander/session/__init__.py +6 -0
  134. claude_mpm/commander/session/context.py +81 -0
  135. claude_mpm/commander/session/manager.py +59 -0
  136. claude_mpm/commander/tmux_orchestrator.py +362 -0
  137. claude_mpm/commander/web/__init__.py +1 -0
  138. claude_mpm/commander/work/__init__.py +30 -0
  139. claude_mpm/commander/work/executor.py +207 -0
  140. claude_mpm/commander/work/queue.py +405 -0
  141. claude_mpm/commander/workflow/__init__.py +27 -0
  142. claude_mpm/commander/workflow/event_handler.py +241 -0
  143. claude_mpm/commander/workflow/notifier.py +146 -0
  144. claude_mpm/commands/mpm-config.md +8 -0
  145. claude_mpm/commands/mpm-doctor.md +8 -0
  146. claude_mpm/commands/mpm-help.md +8 -0
  147. claude_mpm/commands/mpm-init.md +8 -0
  148. claude_mpm/commands/mpm-monitor.md +8 -0
  149. claude_mpm/commands/mpm-organize.md +8 -0
  150. claude_mpm/commands/mpm-postmortem.md +8 -0
  151. claude_mpm/commands/mpm-session-resume.md +9 -1
  152. claude_mpm/commands/mpm-status.md +8 -0
  153. claude_mpm/commands/mpm-ticket-view.md +8 -0
  154. claude_mpm/commands/mpm-version.md +8 -0
  155. claude_mpm/commands/mpm.md +8 -0
  156. claude_mpm/config/agent_presets.py +8 -7
  157. claude_mpm/config/skill_sources.py +16 -0
  158. claude_mpm/constants.py +6 -0
  159. claude_mpm/core/claude_runner.py +154 -2
  160. claude_mpm/core/config.py +35 -22
  161. claude_mpm/core/config_constants.py +74 -9
  162. claude_mpm/core/constants.py +56 -12
  163. claude_mpm/core/hook_manager.py +53 -4
  164. claude_mpm/core/interactive_session.py +12 -11
  165. claude_mpm/core/logger.py +26 -9
  166. claude_mpm/core/logging_utils.py +39 -13
  167. claude_mpm/core/network_config.py +148 -0
  168. claude_mpm/core/oneshot_session.py +7 -6
  169. claude_mpm/core/optimized_startup.py +3 -1
  170. claude_mpm/core/output_style_manager.py +66 -18
  171. claude_mpm/core/shared/config_loader.py +3 -1
  172. claude_mpm/core/socketio_pool.py +47 -15
  173. claude_mpm/core/unified_config.py +54 -8
  174. claude_mpm/core/unified_paths.py +95 -90
  175. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  176. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  177. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
  178. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
  179. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
  180. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
  181. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
  182. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
  183. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
  184. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
  185. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  186. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
  187. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uj46x2Wr.js → BSNlmTZj.js} +1 -1
  188. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
  189. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
  190. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
  191. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
  192. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  193. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  194. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
  195. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
  196. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
  197. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
  198. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
  199. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
  200. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
  201. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
  202. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  203. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
  204. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
  205. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
  206. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  207. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
  208. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  209. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
  210. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
  211. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
  212. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
  213. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
  214. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{N4qtv3Hx.js → DR8nis88.js} +2 -2
  215. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
  216. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  217. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
  218. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
  219. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
  220. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
  221. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
  222. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
  223. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  224. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
  225. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  226. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
  227. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DjhvlsAc.js → NqQ1dWOy.js} +1 -1
  228. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
  229. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
  230. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  231. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
  232. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
  233. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
  234. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
  235. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  236. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.CAGBuiOw.js → 0.RgBboRvH.js} +1 -1
  237. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
  238. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  239. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
  240. claude_mpm/dashboard/static/svelte-build/index.html +11 -11
  241. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  242. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  243. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  244. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  245. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  246. claude_mpm/experimental/cli_enhancements.py +2 -1
  247. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  248. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  249. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  250. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  251. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  252. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  253. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  254. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
  255. claude_mpm/hooks/claude_hooks/event_handlers.py +466 -136
  256. claude_mpm/hooks/claude_hooks/hook_handler.py +204 -104
  257. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  258. claude_mpm/hooks/claude_hooks/installer.py +291 -59
  259. claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
  260. claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
  261. claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
  262. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  263. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  264. claude_mpm/hooks/claude_hooks/services/__pycache__/container.cpython-311.pyc +0 -0
  265. claude_mpm/hooks/claude_hooks/services/__pycache__/protocols.cpython-311.pyc +0 -0
  266. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  267. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  268. claude_mpm/hooks/claude_hooks/services/connection_manager.py +41 -26
  269. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
  270. claude_mpm/hooks/claude_hooks/services/container.py +326 -0
  271. claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
  272. claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
  273. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
  274. claude_mpm/hooks/kuzu_memory_hook.py +5 -5
  275. claude_mpm/hooks/session_resume_hook.py +89 -1
  276. claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
  277. claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
  278. claude_mpm/init.py +224 -4
  279. claude_mpm/mcp/__init__.py +9 -0
  280. claude_mpm/mcp/google_workspace_server.py +610 -0
  281. claude_mpm/scripts/claude-hook-handler.sh +46 -19
  282. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  283. claude_mpm/services/agents/agent_selection_service.py +2 -2
  284. claude_mpm/services/agents/cache_git_manager.py +1 -1
  285. claude_mpm/services/agents/deployment/agent_discovery_service.py +3 -1
  286. claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
  287. claude_mpm/services/agents/deployment/agent_template_builder.py +37 -17
  288. claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
  289. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  290. claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
  291. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +36 -8
  292. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +50 -26
  293. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  294. claude_mpm/services/agents/git_source_manager.py +21 -2
  295. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  296. claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
  297. claude_mpm/services/agents/sources/git_source_sync_service.py +116 -5
  298. claude_mpm/services/agents/startup_sync.py +5 -2
  299. claude_mpm/services/cli/__init__.py +3 -0
  300. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  301. claude_mpm/services/cli/session_resume_helper.py +10 -2
  302. claude_mpm/services/command_deployment_service.py +44 -26
  303. claude_mpm/services/delegation_detector.py +175 -0
  304. claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
  305. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  306. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  307. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  308. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  309. claude_mpm/services/diagnostics/models.py +14 -1
  310. claude_mpm/services/event_log.py +325 -0
  311. claude_mpm/services/hook_installer_service.py +77 -8
  312. claude_mpm/services/infrastructure/__init__.py +4 -0
  313. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  314. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  315. claude_mpm/services/mcp_config_manager.py +99 -19
  316. claude_mpm/services/mcp_service_registry.py +294 -0
  317. claude_mpm/services/monitor/daemon_manager.py +15 -4
  318. claude_mpm/services/monitor/management/lifecycle.py +8 -3
  319. claude_mpm/services/monitor/server.py +111 -16
  320. claude_mpm/services/pm_skills_deployer.py +302 -94
  321. claude_mpm/services/profile_manager.py +10 -4
  322. claude_mpm/services/skills/git_skill_source_manager.py +192 -29
  323. claude_mpm/services/skills/selective_skill_deployer.py +211 -46
  324. claude_mpm/services/skills/skill_discovery_service.py +74 -4
  325. claude_mpm/services/skills_deployer.py +192 -70
  326. claude_mpm/services/socketio/handlers/hook.py +14 -7
  327. claude_mpm/services/socketio/server/main.py +12 -4
  328. claude_mpm/skills/__init__.py +2 -1
  329. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  330. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  331. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  332. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  333. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  334. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  335. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  336. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  337. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  338. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  339. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  340. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  341. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  342. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  343. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  344. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  345. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  346. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  347. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  348. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  349. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  350. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  351. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  352. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  353. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  354. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  355. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  356. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  357. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  358. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  359. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  360. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  361. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  362. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  363. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  364. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  365. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  366. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  367. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  368. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  369. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  370. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  371. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  372. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  373. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  374. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  375. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  376. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  377. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  378. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  379. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  380. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  381. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  382. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  383. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  384. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  385. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  386. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  387. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  388. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  389. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  390. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  391. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  392. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  393. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  394. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  395. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  396. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  397. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  398. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  399. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  400. claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
  401. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  402. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  403. claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
  404. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  405. claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
  406. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  407. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  408. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  409. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  410. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  411. claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
  412. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  413. claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
  414. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  415. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  416. claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
  417. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  418. claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
  419. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  420. claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
  421. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  422. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  423. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  424. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  425. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  426. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  427. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  428. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  429. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  430. claude_mpm/skills/bundled/security-scanning.md +112 -0
  431. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  432. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  433. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  434. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  435. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  436. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  437. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  438. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  439. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  440. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  441. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  442. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  443. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  444. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  445. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  446. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  447. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  448. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  449. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  450. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  451. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  452. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  453. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  454. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  455. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  456. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  457. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  458. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  459. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  460. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  461. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  462. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  463. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  464. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  465. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  466. claude_mpm/skills/registry.py +295 -90
  467. claude_mpm/skills/skill_manager.py +29 -23
  468. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  469. claude_mpm/utils/agent_dependency_loader.py +103 -4
  470. claude_mpm/utils/robust_installer.py +45 -24
  471. claude_mpm-5.6.72.dist-info/METADATA +416 -0
  472. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/RECORD +477 -159
  473. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/WHEEL +1 -1
  474. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/entry_points.txt +2 -0
  475. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +0 -1
  476. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +0 -1
  477. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +0 -1
  478. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +0 -1
  479. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +0 -1
  480. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +0 -2
  481. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +0 -2
  482. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +0 -1
  483. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +0 -1
  484. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +0 -10
  485. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  486. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  487. claude_mpm-5.4.41.dist-info/METADATA +0 -998
  488. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/licenses/LICENSE +0 -0
  489. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  490. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,57 @@
1
+ """Claude MPM framework implementation."""
2
+
3
+ import shlex
4
+ import shutil
5
+ from pathlib import Path
6
+
7
+ from .base import BaseFramework
8
+
9
+
10
+ class MPMFramework(BaseFramework):
11
+ """Claude MPM framework.
12
+
13
+ This framework launches Claude MPM with full agent orchestration.
14
+
15
+ Example:
16
+ >>> framework = MPMFramework()
17
+ >>> framework.name
18
+ 'mpm'
19
+ >>> framework.is_available()
20
+ True
21
+ >>> framework.get_startup_command(Path("/Users/user/myapp"))
22
+ "cd '/Users/user/myapp' && claude-mpm"
23
+ """
24
+
25
+ name = "mpm"
26
+ display_name = "Claude MPM"
27
+ command = "claude-mpm"
28
+
29
+ def get_startup_command(self, project_path: Path) -> str:
30
+ """Get the command to start Claude MPM in a project.
31
+
32
+ Args:
33
+ project_path: Path to the project directory
34
+
35
+ Returns:
36
+ Shell command string to start Claude MPM
37
+
38
+ Example:
39
+ >>> framework = MPMFramework()
40
+ >>> framework.get_startup_command(Path("/Users/user/myapp"))
41
+ "cd '/Users/user/myapp' && claude-mpm"
42
+ """
43
+ quoted_path = shlex.quote(str(project_path))
44
+ return f"cd {quoted_path} && claude-mpm"
45
+
46
+ def is_available(self) -> bool:
47
+ """Check if 'claude-mpm' command is available.
48
+
49
+ Returns:
50
+ True if 'claude-mpm' command exists in PATH
51
+
52
+ Example:
53
+ >>> framework = MPMFramework()
54
+ >>> framework.is_available()
55
+ True
56
+ """
57
+ return shutil.which("claude-mpm") is not None
@@ -0,0 +1,5 @@
1
+ """Git operations for Commander."""
2
+
3
+ from .worktree_manager import WorktreeInfo, WorktreeManager
4
+
5
+ __all__ = ["WorktreeInfo", "WorktreeManager"]
@@ -0,0 +1,212 @@
1
+ """Git worktree manager for session isolation."""
2
+
3
+ import logging
4
+ import subprocess # nosec B404 - subprocess needed for git commands
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from typing import Optional
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ @dataclass
13
+ class WorktreeInfo:
14
+ """Info about a git worktree."""
15
+
16
+ name: str
17
+ path: Path
18
+ branch: str
19
+ base_path: Path # Original repo path
20
+
21
+
22
+ class WorktreeManager:
23
+ """Manages git worktrees for session isolation."""
24
+
25
+ def __init__(self, base_path: Path):
26
+ """Initialize with base project path."""
27
+ self.base_path = Path(base_path)
28
+ self.worktrees_dir = self.base_path.parent / f".worktrees-{self.base_path.name}"
29
+
30
+ def create(self, name: str, branch: Optional[str] = None) -> WorktreeInfo:
31
+ """Create a worktree for a session.
32
+
33
+ Args:
34
+ name: Session/worktree name (e.g., "izzie")
35
+ branch: Branch name, defaults to session-{name}
36
+
37
+ Returns:
38
+ WorktreeInfo with path and branch details
39
+ """
40
+ branch = branch or f"session-{name}"
41
+ worktree_path = self.worktrees_dir / name
42
+
43
+ # Ensure worktrees directory exists
44
+ self.worktrees_dir.mkdir(parents=True, exist_ok=True)
45
+
46
+ # Check if worktree already exists
47
+ if worktree_path.exists():
48
+ logger.info(f"Worktree '{name}' already exists at {worktree_path}")
49
+ return self._get_worktree_info(name, worktree_path)
50
+
51
+ # Create new branch if it doesn't exist
52
+ try:
53
+ subprocess.run( # nosec B603 B607 - git command with safe args
54
+ ["git", "branch", branch],
55
+ cwd=self.base_path,
56
+ capture_output=True,
57
+ check=False, # Branch may already exist
58
+ )
59
+ except Exception as e:
60
+ logger.warning(f"Could not create branch {branch}: {e}")
61
+
62
+ # Create worktree
63
+ result = subprocess.run( # nosec B603 B607 - git command with safe args
64
+ ["git", "worktree", "add", str(worktree_path), branch],
65
+ check=False,
66
+ cwd=self.base_path,
67
+ capture_output=True,
68
+ text=True,
69
+ )
70
+
71
+ if result.returncode != 0:
72
+ raise RuntimeError(f"Failed to create worktree: {result.stderr}")
73
+
74
+ logger.info(f"Created worktree '{name}' at {worktree_path} on branch {branch}")
75
+ return WorktreeInfo(
76
+ name=name, path=worktree_path, branch=branch, base_path=self.base_path
77
+ )
78
+
79
+ def _get_worktree_info(self, name: str, path: Path) -> WorktreeInfo:
80
+ """Get info for existing worktree."""
81
+ result = subprocess.run( # nosec B603 B607 - git command with safe args
82
+ ["git", "branch", "--show-current"],
83
+ check=False,
84
+ cwd=path,
85
+ capture_output=True,
86
+ text=True,
87
+ )
88
+ branch = result.stdout.strip() or f"session-{name}"
89
+ return WorktreeInfo(
90
+ name=name, path=path, branch=branch, base_path=self.base_path
91
+ )
92
+
93
+ def list(self) -> list[WorktreeInfo]:
94
+ """List all worktrees for this project."""
95
+ result = subprocess.run( # nosec B603 B607 - git command with safe args
96
+ ["git", "worktree", "list", "--porcelain"],
97
+ check=False,
98
+ cwd=self.base_path,
99
+ capture_output=True,
100
+ text=True,
101
+ )
102
+
103
+ worktrees = []
104
+ current_path = None
105
+ current_branch = None
106
+
107
+ for line in result.stdout.strip().split("\n"):
108
+ if line.startswith("worktree "):
109
+ current_path = Path(line.split(" ", 1)[1])
110
+ elif line.startswith("branch "):
111
+ current_branch = line.split("/")[-1] # refs/heads/branch -> branch
112
+ elif line == "":
113
+ if current_path and str(self.worktrees_dir) in str(current_path):
114
+ name = current_path.name
115
+ worktrees.append(
116
+ WorktreeInfo(
117
+ name=name,
118
+ path=current_path,
119
+ branch=current_branch or f"session-{name}",
120
+ base_path=self.base_path,
121
+ )
122
+ )
123
+ current_path = None
124
+ current_branch = None
125
+
126
+ return worktrees
127
+
128
+ def remove(self, name: str, force: bool = False) -> bool:
129
+ """Remove a worktree."""
130
+ worktree_path = self.worktrees_dir / name
131
+
132
+ if not worktree_path.exists():
133
+ return False
134
+
135
+ args = ["git", "worktree", "remove", str(worktree_path)]
136
+ if force:
137
+ args.insert(3, "--force")
138
+
139
+ result = subprocess.run( # nosec B603 B607 - git command with safe args
140
+ args, check=False, cwd=self.base_path, capture_output=True, text=True
141
+ )
142
+ return result.returncode == 0
143
+
144
+ def get(self, name: str) -> Optional[WorktreeInfo]:
145
+ """Get worktree by name."""
146
+ worktree_path = self.worktrees_dir / name
147
+ if worktree_path.exists():
148
+ return self._get_worktree_info(name, worktree_path)
149
+ return None
150
+
151
+ def merge_to_main(self, name: str, delete_after: bool = True) -> tuple[bool, str]:
152
+ """Merge worktree branch back to main and optionally delete worktree.
153
+
154
+ Args:
155
+ name: Worktree name to merge
156
+ delete_after: Remove worktree after merge (default True)
157
+
158
+ Returns:
159
+ Tuple of (success, message)
160
+ """
161
+ worktree = self.get(name)
162
+ if not worktree:
163
+ return False, f"Worktree '{name}' not found"
164
+
165
+ # Get main branch name
166
+ result = subprocess.run( # nosec B603 B607 - git command with safe args
167
+ ["git", "symbolic-ref", "refs/remotes/origin/HEAD"],
168
+ check=False,
169
+ cwd=self.base_path,
170
+ capture_output=True,
171
+ text=True,
172
+ )
173
+ main_branch = (
174
+ result.stdout.strip().split("/")[-1] if result.returncode == 0 else "main"
175
+ )
176
+
177
+ # Checkout main in base repo
178
+ checkout_result = subprocess.run( # nosec B603 B607 - git command with safe args
179
+ ["git", "checkout", main_branch],
180
+ check=False,
181
+ cwd=self.base_path,
182
+ capture_output=True,
183
+ text=True,
184
+ )
185
+ if checkout_result.returncode != 0:
186
+ return False, f"Failed to checkout {main_branch}: {checkout_result.stderr}"
187
+
188
+ # Merge worktree branch
189
+ merge_result = subprocess.run( # nosec B603 B607 - git command with safe args
190
+ ["git", "merge", worktree.branch, "--no-edit"],
191
+ check=False,
192
+ cwd=self.base_path,
193
+ capture_output=True,
194
+ text=True,
195
+ )
196
+
197
+ if merge_result.returncode != 0:
198
+ return False, f"Merge failed: {merge_result.stderr}"
199
+
200
+ # Delete worktree if requested
201
+ if delete_after:
202
+ self.remove(name, force=True)
203
+ # Delete branch
204
+ subprocess.run( # nosec B603 B607 - git command with safe args
205
+ ["git", "branch", "-d", worktree.branch],
206
+ check=False,
207
+ cwd=self.base_path,
208
+ capture_output=True,
209
+ )
210
+
211
+ logger.info(f"Merged '{worktree.branch}' to {main_branch}")
212
+ return True, f"Merged '{worktree.branch}' to {main_branch}"
@@ -0,0 +1,16 @@
1
+ """Inbox system for MPM Commander.
2
+
3
+ Provides centralized event aggregation and display.
4
+ """
5
+
6
+ from .dedup import DedupEntry, EventDeduplicator
7
+ from .inbox import Inbox, InboxCounts
8
+ from .models import InboxItem
9
+
10
+ __all__ = [
11
+ "DedupEntry",
12
+ "EventDeduplicator",
13
+ "Inbox",
14
+ "InboxCounts",
15
+ "InboxItem",
16
+ ]
@@ -0,0 +1,128 @@
1
+ """Event deduplication logic for inbox system.
2
+
3
+ Prevents duplicate events within a configurable time window using
4
+ content hashing and time-based expiration.
5
+ """
6
+
7
+ import hashlib
8
+ from dataclasses import dataclass
9
+ from datetime import datetime, timedelta, timezone
10
+ from typing import Dict
11
+
12
+
13
+ @dataclass
14
+ class DedupEntry:
15
+ """Deduplication cache entry.
16
+
17
+ Tracks when an event was first seen and how many times it's appeared.
18
+
19
+ Attributes:
20
+ key: Unique deduplication key
21
+ first_seen: When this key was first encountered
22
+ count: Number of times this key has been seen
23
+ """
24
+
25
+ key: str
26
+ first_seen: datetime
27
+ count: int = 1
28
+
29
+
30
+ class EventDeduplicator:
31
+ """Prevent duplicate events within a time window.
32
+
33
+ Uses content hashing to detect duplicates and time-based expiration
34
+ to automatically clean up old entries.
35
+
36
+ The deduplication key is constructed from:
37
+ - Project ID
38
+ - Event type
39
+ - Title hash (first 8 chars of MD5)
40
+
41
+ Example:
42
+ >>> dedup = EventDeduplicator(window_seconds=60)
43
+ >>> dedup.is_duplicate("proj_123", "error", "Connection failed")
44
+ False # First occurrence
45
+ >>> dedup.is_duplicate("proj_123", "error", "Connection failed")
46
+ True # Duplicate within 60 seconds
47
+ """
48
+
49
+ def __init__(self, window_seconds: int = 60):
50
+ """Initialize deduplicator with time window.
51
+
52
+ Args:
53
+ window_seconds: Duration in seconds to consider events as duplicates.
54
+ Default is 60 seconds.
55
+ """
56
+ self.window = timedelta(seconds=window_seconds)
57
+ self._seen: Dict[str, DedupEntry] = {}
58
+
59
+ def make_key(self, project_id: str, event_type: str, title: str) -> str:
60
+ """Create deduplication key from event attributes.
61
+
62
+ Generates a key in the format: {project_id}:{event_type}:{title_hash}
63
+
64
+ Args:
65
+ project_id: Unique project identifier
66
+ event_type: Type of event (from EventType enum)
67
+ title: Event title text
68
+
69
+ Returns:
70
+ Composite key string for deduplication
71
+
72
+ Example:
73
+ >>> dedup = EventDeduplicator()
74
+ >>> dedup.make_key("proj_123", "error", "Connection failed")
75
+ 'proj_123:error:a1b2c3d4'
76
+ """
77
+ title_hash = hashlib.md5(title.encode(), usedforsecurity=False).hexdigest()[:8]
78
+ return f"{project_id}:{event_type}:{title_hash}"
79
+
80
+ def is_duplicate(self, project_id: str, event_type: str, title: str) -> bool:
81
+ """Check if this event is a duplicate within the window.
82
+
83
+ Args:
84
+ project_id: Unique project identifier
85
+ event_type: Type of event
86
+ title: Event title
87
+
88
+ Returns:
89
+ True if this is a duplicate, False if it's new
90
+
91
+ Side Effects:
92
+ - Increments count for duplicates
93
+ - Creates new entry for new events
94
+ - Cleans up expired entries
95
+
96
+ Example:
97
+ >>> dedup = EventDeduplicator(window_seconds=60)
98
+ >>> dedup.is_duplicate("proj_123", "error", "Timeout")
99
+ False # First occurrence
100
+ >>> dedup.is_duplicate("proj_123", "error", "Timeout")
101
+ True # Duplicate within window
102
+ """
103
+ self._cleanup_expired()
104
+ key = self.make_key(project_id, event_type, title)
105
+
106
+ if key in self._seen:
107
+ self._seen[key].count += 1
108
+ return True
109
+
110
+ self._seen[key] = DedupEntry(
111
+ key=key,
112
+ first_seen=datetime.now(timezone.utc),
113
+ )
114
+ return False
115
+
116
+ def _cleanup_expired(self) -> None:
117
+ """Remove entries older than the deduplication window.
118
+
119
+ Called automatically before each is_duplicate check to prevent
120
+ unbounded memory growth.
121
+
122
+ Side Effects:
123
+ Removes all entries where (now - first_seen) > window
124
+ """
125
+ now = datetime.now(timezone.utc)
126
+ expired = [k for k, v in self._seen.items() if now - v.first_seen > self.window]
127
+ for k in expired:
128
+ del self._seen[k]
@@ -0,0 +1,224 @@
1
+ """Centralized inbox for MPM Commander.
2
+
3
+ Aggregates events from all projects with filtering, sorting, and pagination.
4
+ """
5
+
6
+ import logging
7
+ from dataclasses import dataclass
8
+ from typing import List, Optional
9
+
10
+ from ..events.manager import EventManager
11
+ from ..models.events import Event, EventPriority, EventType
12
+ from ..registry import ProjectRegistry
13
+ from .dedup import EventDeduplicator
14
+ from .models import InboxItem
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ @dataclass
20
+ class InboxCounts:
21
+ """Count of events by priority.
22
+
23
+ Provides quick summary statistics for inbox state.
24
+
25
+ Attributes:
26
+ critical: Count of CRITICAL priority events
27
+ high: Count of HIGH priority events
28
+ normal: Count of NORMAL priority events
29
+ low: Count of LOW priority events
30
+ info: Count of INFO priority events
31
+ total: Total count of all events
32
+ """
33
+
34
+ critical: int = 0
35
+ high: int = 0
36
+ normal: int = 0
37
+ low: int = 0
38
+ info: int = 0
39
+ total: int = 0
40
+
41
+
42
+ class Inbox:
43
+ """Centralized inbox aggregating events from all projects.
44
+
45
+ Provides a unified view of all pending events with:
46
+ - Multi-level filtering (priority, project, event type)
47
+ - Pagination support
48
+ - Priority-based sorting
49
+ - Project metadata enrichment
50
+ - Deduplication
51
+
52
+ Example:
53
+ >>> inbox = Inbox(event_manager, project_registry)
54
+ >>> items = inbox.get_items(limit=10, priority=EventPriority.HIGH)
55
+ >>> counts = inbox.get_counts()
56
+ >>> print(f"Total pending: {counts.total}")
57
+ """
58
+
59
+ def __init__(
60
+ self,
61
+ event_manager: EventManager,
62
+ project_registry: ProjectRegistry,
63
+ dedup_window: int = 60,
64
+ ):
65
+ """Initialize inbox with dependencies.
66
+
67
+ Args:
68
+ event_manager: Event lifecycle manager
69
+ project_registry: Project registration system
70
+ dedup_window: Deduplication window in seconds (default: 60)
71
+ """
72
+ self.events = event_manager
73
+ self.projects = project_registry
74
+ self.deduplicator = EventDeduplicator(window_seconds=dedup_window)
75
+
76
+ def get_items(
77
+ self,
78
+ limit: int = 50,
79
+ offset: int = 0,
80
+ priority: Optional[EventPriority] = None,
81
+ project_id: Optional[str] = None,
82
+ event_type: Optional[EventType] = None,
83
+ ) -> List[InboxItem]:
84
+ """Get inbox items with optional filtering and pagination.
85
+
86
+ Applies filters in this order:
87
+ 1. Get all pending events (optionally for specific project)
88
+ 2. Filter by priority if specified
89
+ 3. Filter by event type if specified
90
+ 4. Sort by priority (high to low) then created_at (old to new)
91
+ 5. Paginate with limit and offset
92
+ 6. Enrich with project metadata
93
+
94
+ Args:
95
+ limit: Maximum number of items to return (default: 50)
96
+ offset: Number of items to skip for pagination (default: 0)
97
+ priority: Filter to specific priority level (optional)
98
+ project_id: Filter to specific project (optional)
99
+ event_type: Filter to specific event type (optional)
100
+
101
+ Returns:
102
+ List of enriched InboxItems, sorted and paginated
103
+
104
+ Example:
105
+ # Get first 20 critical events
106
+ >>> items = inbox.get_items(limit=20, priority=EventPriority.CRITICAL)
107
+
108
+ # Get high-priority errors for specific project
109
+ >>> items = inbox.get_items(
110
+ ... priority=EventPriority.HIGH,
111
+ ... project_id="proj_123",
112
+ ... event_type=EventType.ERROR
113
+ ... )
114
+
115
+ # Pagination: get items 50-100
116
+ >>> items = inbox.get_items(limit=50, offset=50)
117
+ """
118
+ # Get all pending events (optionally filtered by project)
119
+ pending = self.events.get_pending(project_id)
120
+
121
+ # Filter by priority
122
+ if priority:
123
+ pending = [e for e in pending if e.priority == priority]
124
+
125
+ # Filter by event type
126
+ if event_type:
127
+ pending = [e for e in pending if e.type == event_type]
128
+
129
+ # Sort by priority (CRITICAL first) then created_at (oldest first)
130
+ priority_order = [
131
+ EventPriority.CRITICAL,
132
+ EventPriority.HIGH,
133
+ EventPriority.NORMAL,
134
+ EventPriority.LOW,
135
+ EventPriority.INFO,
136
+ ]
137
+
138
+ def sort_key(event: Event):
139
+ pri_idx = (
140
+ priority_order.index(event.priority)
141
+ if event.priority in priority_order
142
+ else 99
143
+ )
144
+ return (pri_idx, event.created_at)
145
+
146
+ sorted_events = sorted(pending, key=sort_key)
147
+
148
+ # Paginate
149
+ paginated = sorted_events[offset : offset + limit]
150
+
151
+ # Enrich with project metadata
152
+ items = []
153
+ for event in paginated:
154
+ project = self.projects.get(event.project_id)
155
+ if project:
156
+ session_runtime = None
157
+ if event.session_id and event.session_id in project.sessions:
158
+ session_runtime = project.sessions[event.session_id].runtime
159
+
160
+ items.append(
161
+ InboxItem(
162
+ event=event,
163
+ project_name=project.name,
164
+ project_path=project.path,
165
+ session_runtime=session_runtime,
166
+ )
167
+ )
168
+
169
+ return items
170
+
171
+ def get_counts(self, project_id: Optional[str] = None) -> InboxCounts:
172
+ """Get count of pending events by priority.
173
+
174
+ Args:
175
+ project_id: If provided, only count events for this project
176
+
177
+ Returns:
178
+ InboxCounts with breakdown by priority and total
179
+
180
+ Example:
181
+ >>> counts = inbox.get_counts()
182
+ >>> print(f"Critical: {counts.critical}, Total: {counts.total}")
183
+
184
+ >>> project_counts = inbox.get_counts(project_id="proj_123")
185
+ """
186
+ pending = self.events.get_pending(project_id)
187
+
188
+ counts = InboxCounts()
189
+ for event in pending:
190
+ counts.total += 1
191
+ if event.priority == EventPriority.CRITICAL:
192
+ counts.critical += 1
193
+ elif event.priority == EventPriority.HIGH:
194
+ counts.high += 1
195
+ elif event.priority == EventPriority.NORMAL:
196
+ counts.normal += 1
197
+ elif event.priority == EventPriority.LOW:
198
+ counts.low += 1
199
+ elif event.priority == EventPriority.INFO:
200
+ counts.info += 1
201
+
202
+ return counts
203
+
204
+ def should_create_event(
205
+ self, project_id: str, event_type: EventType, title: str
206
+ ) -> bool:
207
+ """Check if event should be created (not a duplicate).
208
+
209
+ Uses deduplication to prevent creating duplicate events within
210
+ the configured time window.
211
+
212
+ Args:
213
+ project_id: Project raising the event
214
+ event_type: Type of event
215
+ title: Event title
216
+
217
+ Returns:
218
+ True if event should be created, False if it's a duplicate
219
+
220
+ Example:
221
+ >>> if inbox.should_create_event("proj_123", EventType.ERROR, "Timeout"):
222
+ ... event = event_manager.create(...)
223
+ """
224
+ return not self.deduplicator.is_duplicate(project_id, event_type.value, title)