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,6 @@
1
+ """LLM integration for Commander chat interface and summarization."""
2
+
3
+ from .openrouter_client import OpenRouterClient, OpenRouterConfig
4
+ from .summarizer import OutputSummarizer
5
+
6
+ __all__ = ["OpenRouterClient", "OpenRouterConfig", "OutputSummarizer"]
@@ -0,0 +1,167 @@
1
+ """OpenRouter LLM client for Commander chat interface."""
2
+
3
+ import os
4
+ from dataclasses import dataclass
5
+ from typing import AsyncIterator
6
+
7
+ import httpx
8
+
9
+
10
+ @dataclass
11
+ class OpenRouterConfig:
12
+ """Configuration for OpenRouter API client."""
13
+
14
+ api_key: str | None = None # Falls back to OPENROUTER_API_KEY env
15
+ model: str = "anthropic/claude-3.5-sonnet"
16
+ base_url: str = "https://openrouter.ai/api/v1"
17
+ max_tokens: int = 4096
18
+ temperature: float = 0.7
19
+
20
+
21
+ class OpenRouterClient:
22
+ """Async client for OpenRouter API."""
23
+
24
+ def __init__(self, config: OpenRouterConfig | None = None):
25
+ """Initialize client with config.
26
+
27
+ Args:
28
+ config: OpenRouter configuration. Defaults to OpenRouterConfig().
29
+
30
+ Raises:
31
+ ValueError: If OPENROUTER_API_KEY is not set.
32
+ """
33
+ self.config = config or OpenRouterConfig()
34
+ self._api_key = self.config.api_key or os.getenv("OPENROUTER_API_KEY")
35
+ if not self._api_key:
36
+ raise ValueError("OPENROUTER_API_KEY not set")
37
+
38
+ async def chat(self, messages: list[dict], system: str | None = None) -> str:
39
+ """Send chat completion request, return response content.
40
+
41
+ Args:
42
+ messages: List of message dicts with 'role' and 'content' keys.
43
+ system: Optional system prompt.
44
+
45
+ Returns:
46
+ Response content from the model.
47
+
48
+ Raises:
49
+ httpx.HTTPStatusError: If API request fails.
50
+ """
51
+ async with httpx.AsyncClient() as client:
52
+ # Build request payload
53
+ payload = {
54
+ "model": self.config.model,
55
+ "messages": messages,
56
+ "max_tokens": self.config.max_tokens,
57
+ "temperature": self.config.temperature,
58
+ }
59
+
60
+ if system:
61
+ payload["system"] = system
62
+
63
+ # Send request
64
+ response = await client.post(
65
+ f"{self.config.base_url}/chat/completions",
66
+ headers={
67
+ "Authorization": f"Bearer {self._api_key}",
68
+ "Content-Type": "application/json",
69
+ },
70
+ json=payload,
71
+ timeout=30.0,
72
+ )
73
+ response.raise_for_status()
74
+
75
+ # Extract content from response
76
+ data = response.json()
77
+ return data["choices"][0]["message"]["content"]
78
+
79
+ async def chat_stream(
80
+ self, messages: list[dict], system: str | None = None
81
+ ) -> AsyncIterator[str]:
82
+ """Stream chat completion, yield chunks.
83
+
84
+ Args:
85
+ messages: List of message dicts with 'role' and 'content' keys.
86
+ system: Optional system prompt.
87
+
88
+ Yields:
89
+ Content chunks from the streaming response.
90
+
91
+ Raises:
92
+ httpx.HTTPStatusError: If API request fails.
93
+ """
94
+ async with httpx.AsyncClient() as client:
95
+ # Build request payload
96
+ payload = {
97
+ "model": self.config.model,
98
+ "messages": messages,
99
+ "max_tokens": self.config.max_tokens,
100
+ "temperature": self.config.temperature,
101
+ "stream": True,
102
+ }
103
+
104
+ if system:
105
+ payload["system"] = system
106
+
107
+ # Send streaming request
108
+ async with client.stream(
109
+ "POST",
110
+ f"{self.config.base_url}/chat/completions",
111
+ headers={
112
+ "Authorization": f"Bearer {self._api_key}",
113
+ "Content-Type": "application/json",
114
+ },
115
+ json=payload,
116
+ timeout=30.0,
117
+ ) as response:
118
+ response.raise_for_status()
119
+
120
+ # Parse SSE stream
121
+ async for line in response.aiter_lines():
122
+ if not line.strip():
123
+ continue
124
+
125
+ # SSE format: "data: {json}"
126
+ if line.startswith("data: "):
127
+ data_str = line[6:] # Remove "data: " prefix
128
+
129
+ # Check for stream end
130
+ if data_str == "[DONE]":
131
+ break
132
+
133
+ # Parse JSON chunk
134
+ import json
135
+
136
+ try:
137
+ data = json.loads(data_str)
138
+ delta = data["choices"][0].get("delta", {})
139
+ if "content" in delta:
140
+ yield delta["content"]
141
+ except (json.JSONDecodeError, KeyError, IndexError):
142
+ # Skip malformed chunks
143
+ continue
144
+
145
+ async def summarize(self, text: str, max_length: int = 500) -> str:
146
+ """Summarize text to max_length characters.
147
+
148
+ Args:
149
+ text: Text to summarize.
150
+ max_length: Maximum length of summary in characters.
151
+
152
+ Returns:
153
+ Summarized text.
154
+ """
155
+ messages = [
156
+ {
157
+ "role": "user",
158
+ "content": f"Summarize the following text in approximately {max_length} characters or less:\n\n{text}",
159
+ }
160
+ ]
161
+
162
+ system = (
163
+ "You are a concise summarization assistant. "
164
+ "Provide clear, accurate summaries that capture the key points."
165
+ )
166
+
167
+ return await self.chat(messages, system=system)
@@ -0,0 +1,70 @@
1
+ """Summarizes Claude Code output for user display."""
2
+
3
+ from .openrouter_client import OpenRouterClient
4
+
5
+
6
+ class OutputSummarizer:
7
+ """Summarizes long output from Claude Code instances."""
8
+
9
+ def __init__(self, client: OpenRouterClient):
10
+ """Initialize with OpenRouter client.
11
+
12
+ Args:
13
+ client: OpenRouterClient instance for LLM requests.
14
+ """
15
+ self.client = client
16
+
17
+ async def summarize(self, output: str, context: str | None = None) -> str:
18
+ """Summarize Claude Code output.
19
+
20
+ Args:
21
+ output: Raw output from Claude Code.
22
+ context: Optional context about what was requested.
23
+
24
+ Returns:
25
+ Concise summary of the output.
26
+ """
27
+ # Build summarization prompt
28
+ if context:
29
+ prompt = f"""Summarize the following Claude Code output.
30
+
31
+ Context: {context}
32
+
33
+ Output:
34
+ {output}
35
+
36
+ Provide a concise summary (2-3 sentences) that captures:
37
+ 1. What action was taken
38
+ 2. The key result or outcome
39
+ 3. Any important warnings or next steps
40
+
41
+ Summary:"""
42
+ else:
43
+ prompt = f"""Summarize the following Claude Code output in 2-3 sentences.
44
+
45
+ Output:
46
+ {output}
47
+
48
+ Summary:"""
49
+
50
+ messages = [{"role": "user", "content": prompt}]
51
+
52
+ system = (
53
+ "You are a technical summarization assistant. "
54
+ "Provide clear, concise summaries of command output and code execution results. "
55
+ "Focus on actionable information and key outcomes."
56
+ )
57
+
58
+ return await self.client.chat(messages, system=system)
59
+
60
+ def needs_summarization(self, output: str, threshold: int = 500) -> bool:
61
+ """Check if output is long enough to warrant summarization.
62
+
63
+ Args:
64
+ output: Output text to check.
65
+ threshold: Character count threshold for summarization.
66
+
67
+ Returns:
68
+ True if output exceeds threshold, False otherwise.
69
+ """
70
+ return len(output) > threshold
@@ -0,0 +1,45 @@
1
+ """Conversation memory system for Commander.
2
+
3
+ This module provides semantic search, storage, and context compression
4
+ for all Claude Code instance conversations.
5
+
6
+ Key Components:
7
+ - ConversationStore: CRUD operations for conversations
8
+ - EmbeddingService: Generate vector embeddings
9
+ - SemanticSearch: Query conversations semantically
10
+ - ContextCompressor: Summarize conversations for context
11
+ - EntityExtractor: Extract files, functions, errors
12
+
13
+ Example:
14
+ >>> from claude_mpm.commander.memory import (
15
+ ... ConversationStore,
16
+ ... EmbeddingService,
17
+ ... SemanticSearch,
18
+ ... ContextCompressor,
19
+ ... )
20
+ >>> store = ConversationStore()
21
+ >>> embeddings = EmbeddingService()
22
+ >>> search = SemanticSearch(store, embeddings)
23
+ >>> results = await search.search("how did we fix the login bug?")
24
+ """
25
+
26
+ from .compression import ContextCompressor
27
+ from .embeddings import EmbeddingService
28
+ from .entities import Entity, EntityExtractor, EntityType
29
+ from .integration import MemoryIntegration
30
+ from .search import SearchResult, SemanticSearch
31
+ from .store import Conversation, ConversationMessage, ConversationStore
32
+
33
+ __all__ = [
34
+ "ContextCompressor",
35
+ "Conversation",
36
+ "ConversationMessage",
37
+ "ConversationStore",
38
+ "EmbeddingService",
39
+ "Entity",
40
+ "EntityExtractor",
41
+ "EntityType",
42
+ "MemoryIntegration",
43
+ "SearchResult",
44
+ "SemanticSearch",
45
+ ]
@@ -0,0 +1,347 @@
1
+ """Context compression and conversation summarization.
2
+
3
+ Compresses long conversations into concise summaries for efficient context
4
+ loading when resuming sessions or searching past work.
5
+ """
6
+
7
+ import logging
8
+ from typing import List, Optional
9
+
10
+ from ..llm.openrouter_client import OpenRouterClient
11
+ from .store import Conversation, ConversationMessage
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class ContextCompressor:
17
+ """Compress conversations into summaries for context loading.
18
+
19
+ Uses cheap LLM (mistral-small) to generate summaries of conversations
20
+ and compress multiple conversations into context strings.
21
+
22
+ Attributes:
23
+ client: OpenRouterClient for LLM requests
24
+ summary_threshold: Minimum messages to trigger summarization
25
+ max_context_tokens: Maximum tokens for compressed context
26
+
27
+ Example:
28
+ >>> compressor = ContextCompressor(client)
29
+ >>> summary = await compressor.summarize(messages)
30
+ >>> context = await compressor.compress_for_context(
31
+ ... conversations,
32
+ ... max_tokens=4000
33
+ ... )
34
+ """
35
+
36
+ def __init__(
37
+ self,
38
+ client: OpenRouterClient,
39
+ summary_threshold: int = 10,
40
+ max_context_tokens: int = 4000,
41
+ ):
42
+ """Initialize context compressor.
43
+
44
+ Args:
45
+ client: OpenRouterClient for LLM requests
46
+ summary_threshold: Minimum messages to summarize
47
+ max_context_tokens: Maximum tokens for context string
48
+ """
49
+ self.client = client
50
+ self.summary_threshold = summary_threshold
51
+ self.max_context_tokens = max_context_tokens
52
+
53
+ logger.info(
54
+ "ContextCompressor initialized (threshold: %d msgs, max_tokens: %d)",
55
+ summary_threshold,
56
+ max_context_tokens,
57
+ )
58
+
59
+ async def summarize(
60
+ self,
61
+ messages: List[ConversationMessage],
62
+ focus: Optional[str] = None,
63
+ ) -> str:
64
+ """Generate summary of conversation messages.
65
+
66
+ Args:
67
+ messages: List of messages to summarize
68
+ focus: Optional focus area (e.g., "bug fixes", "API changes")
69
+
70
+ Returns:
71
+ Concise summary (2-4 sentences)
72
+
73
+ Example:
74
+ >>> summary = await compressor.summarize(messages)
75
+ >>> print(summary)
76
+ "Fixed login authentication bug in src/auth.py by updating token validation..."
77
+ """
78
+ if len(messages) < 2:
79
+ # Too short to summarize
80
+ return messages[0].content if messages else ""
81
+
82
+ # Build conversation text
83
+ conversation_text = self._format_messages(messages)
84
+
85
+ # Build summarization prompt
86
+ if focus:
87
+ prompt = f"""Summarize the following conversation, focusing on: {focus}
88
+
89
+ Conversation:
90
+ {conversation_text}
91
+
92
+ Provide a concise summary (2-4 sentences) that captures:
93
+ 1. What was the main task or problem
94
+ 2. What actions were taken
95
+ 3. What was the outcome or current status
96
+ 4. Any important files, functions, or errors mentioned
97
+
98
+ Summary:"""
99
+ else:
100
+ prompt = f"""Summarize the following conversation in 2-4 sentences.
101
+
102
+ Conversation:
103
+ {conversation_text}
104
+
105
+ Focus on:
106
+ 1. What was the main task or problem
107
+ 2. What actions were taken
108
+ 3. What was the outcome or current status
109
+
110
+ Summary:"""
111
+
112
+ messages_for_llm = [{"role": "user", "content": prompt}]
113
+
114
+ system = (
115
+ "You are a technical summarization assistant. "
116
+ "Provide clear, concise summaries of development conversations. "
117
+ "Focus on actionable information and key outcomes."
118
+ )
119
+
120
+ summary = await self.client.chat(messages_for_llm, system=system)
121
+ logger.debug(
122
+ "Generated summary (%d chars) from %d messages", len(summary), len(messages)
123
+ )
124
+
125
+ return summary.strip()
126
+
127
+ async def compress_for_context(
128
+ self,
129
+ conversations: List[Conversation],
130
+ max_tokens: Optional[int] = None,
131
+ prioritize_recent: bool = True,
132
+ ) -> str:
133
+ """Compress multiple conversations into context string.
134
+
135
+ Prioritizes recent conversations and uses summaries for older ones
136
+ to fit within token budget.
137
+
138
+ Args:
139
+ conversations: List of conversations to compress
140
+ max_tokens: Maximum tokens (default: self.max_context_tokens)
141
+ prioritize_recent: Whether to prioritize recent conversations
142
+
143
+ Returns:
144
+ Compressed context string ready for LLM input
145
+
146
+ Example:
147
+ >>> context = await compressor.compress_for_context(
148
+ ... conversations,
149
+ ... max_tokens=4000
150
+ ... )
151
+ >>> print(f"Context: {len(context)} chars")
152
+ """
153
+ if max_tokens is None:
154
+ max_tokens = self.max_context_tokens
155
+
156
+ # Sort by recency if prioritizing
157
+ if prioritize_recent:
158
+ conversations = sorted(
159
+ conversations, key=lambda c: c.updated_at, reverse=True
160
+ )
161
+
162
+ # Build context incrementally
163
+ context_parts = []
164
+ current_tokens = 0
165
+
166
+ for conv in conversations:
167
+ # Use summary if available, else generate one
168
+ if conv.summary:
169
+ summary_text = conv.summary
170
+ elif len(conv.messages) >= self.summary_threshold:
171
+ # Generate summary on-the-fly
172
+ summary_text = await self.summarize(conv.messages)
173
+ else:
174
+ # Use full conversation for short ones
175
+ summary_text = conv.get_full_text()
176
+
177
+ # Format conversation section
178
+ section = self._format_conversation_section(conv, summary_text)
179
+ section_tokens = len(section) // 4 # Rough approximation
180
+
181
+ # Check if adding this would exceed budget
182
+ if current_tokens + section_tokens > max_tokens:
183
+ # Try to fit summary only
184
+ short_summary = summary_text.split(". ")[0] + "."
185
+ short_section = self._format_conversation_section(conv, short_summary)
186
+ short_tokens = len(short_section) // 4
187
+
188
+ if current_tokens + short_tokens <= max_tokens:
189
+ context_parts.append(short_section)
190
+ current_tokens += short_tokens
191
+ else:
192
+ # Can't fit any more, stop
193
+ break
194
+ else:
195
+ context_parts.append(section)
196
+ current_tokens += section_tokens
197
+
198
+ context = "\n\n---\n\n".join(context_parts)
199
+
200
+ logger.info(
201
+ "Compressed %d conversations into context (%d chars, ~%d tokens)",
202
+ len(context_parts),
203
+ len(context),
204
+ current_tokens,
205
+ )
206
+
207
+ return context
208
+
209
+ def needs_summarization(self, messages: List[ConversationMessage]) -> bool:
210
+ """Check if conversation needs summarization.
211
+
212
+ Args:
213
+ messages: List of messages to check
214
+
215
+ Returns:
216
+ True if message count exceeds threshold
217
+
218
+ Example:
219
+ >>> if compressor.needs_summarization(messages):
220
+ ... summary = await compressor.summarize(messages)
221
+ """
222
+ return len(messages) >= self.summary_threshold
223
+
224
+ def _format_messages(
225
+ self,
226
+ messages: List[ConversationMessage],
227
+ max_messages: Optional[int] = None,
228
+ ) -> str:
229
+ """Format messages as text for summarization.
230
+
231
+ Args:
232
+ messages: Messages to format
233
+ max_messages: Maximum messages to include
234
+
235
+ Returns:
236
+ Formatted conversation text
237
+ """
238
+ if max_messages:
239
+ messages = messages[:max_messages]
240
+
241
+ lines = []
242
+ for msg in messages:
243
+ # Format: ROLE: content
244
+ lines.append(f"{msg.role.upper()}: {msg.content}")
245
+
246
+ return "\n\n".join(lines)
247
+
248
+ def _format_conversation_section(
249
+ self, conversation: Conversation, summary: str
250
+ ) -> str:
251
+ """Format conversation section for context string.
252
+
253
+ Args:
254
+ conversation: Conversation to format
255
+ summary: Summary or full text
256
+
257
+ Returns:
258
+ Formatted section with metadata
259
+ """
260
+ # Format timestamp
261
+ timestamp = conversation.updated_at.strftime("%Y-%m-%d %H:%M")
262
+
263
+ # Build section
264
+ return f"""## Conversation: {conversation.id}
265
+ **Project:** {conversation.project_id}
266
+ **Instance:** {conversation.instance_name}
267
+ **Updated:** {timestamp}
268
+ **Messages:** {conversation.message_count}
269
+
270
+ {summary}"""
271
+
272
+ async def auto_summarize_conversation(
273
+ self, conversation: Conversation
274
+ ) -> Optional[str]:
275
+ """Automatically summarize conversation if needed.
276
+
277
+ Checks if conversation needs summarization and generates one if so.
278
+ Updates the conversation's summary field but does NOT save to store.
279
+
280
+ Args:
281
+ conversation: Conversation to summarize
282
+
283
+ Returns:
284
+ Summary if generated, None if not needed
285
+
286
+ Example:
287
+ >>> summary = await compressor.auto_summarize_conversation(conv)
288
+ >>> if summary:
289
+ ... conv.summary = summary
290
+ ... await store.save(conv)
291
+ """
292
+ if not self.needs_summarization(conversation.messages):
293
+ logger.debug(
294
+ "Conversation %s too short to summarize (%d messages)",
295
+ conversation.id,
296
+ len(conversation.messages),
297
+ )
298
+ return None
299
+
300
+ if conversation.summary:
301
+ logger.debug("Conversation %s already has summary", conversation.id)
302
+ return conversation.summary
303
+
304
+ # Generate summary
305
+ summary = await self.summarize(conversation.messages)
306
+ logger.info("Auto-generated summary for conversation %s", conversation.id)
307
+
308
+ return summary
309
+
310
+ async def update_summary_if_stale(
311
+ self,
312
+ conversation: Conversation,
313
+ message_threshold: int = 5,
314
+ ) -> Optional[str]:
315
+ """Update summary if conversation has grown significantly.
316
+
317
+ Args:
318
+ conversation: Conversation to check
319
+ message_threshold: New messages required to trigger update
320
+
321
+ Returns:
322
+ Updated summary if regenerated, None otherwise
323
+
324
+ Example:
325
+ >>> updated = await compressor.update_summary_if_stale(conv)
326
+ >>> if updated:
327
+ ... conv.summary = updated
328
+ ... await store.save(conv)
329
+ """
330
+ if not conversation.summary:
331
+ # No existing summary, generate one
332
+ return await self.auto_summarize_conversation(conversation)
333
+
334
+ # Check if conversation has grown significantly
335
+ # (Simple heuristic: if more than threshold messages since last summarization)
336
+ # In practice, you'd track when summary was generated
337
+ if len(conversation.messages) < self.summary_threshold + message_threshold:
338
+ return None
339
+
340
+ # Regenerate summary
341
+ logger.info(
342
+ "Regenerating stale summary for conversation %s (%d messages)",
343
+ conversation.id,
344
+ len(conversation.messages),
345
+ )
346
+
347
+ return await self.summarize(conversation.messages)