claude-mpm 5.4.85__py3-none-any.whl → 5.6.76__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +8 -5
  3. claude_mpm/agents/{CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md → CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md} +14 -6
  4. claude_mpm/agents/PM_INSTRUCTIONS.md +109 -706
  5. claude_mpm/agents/WORKFLOW.md +2 -0
  6. claude_mpm/agents/templates/circuit-breakers.md +26 -17
  7. claude_mpm/auth/__init__.py +35 -0
  8. claude_mpm/auth/callback_server.py +328 -0
  9. claude_mpm/auth/models.py +104 -0
  10. claude_mpm/auth/oauth_manager.py +266 -0
  11. claude_mpm/auth/providers/__init__.py +12 -0
  12. claude_mpm/auth/providers/base.py +165 -0
  13. claude_mpm/auth/providers/google.py +261 -0
  14. claude_mpm/auth/token_storage.py +252 -0
  15. claude_mpm/cli/commands/autotodos.py +566 -0
  16. claude_mpm/cli/commands/commander.py +216 -0
  17. claude_mpm/cli/commands/hook_errors.py +60 -60
  18. claude_mpm/cli/commands/mcp.py +29 -17
  19. claude_mpm/cli/commands/mcp_command_router.py +39 -0
  20. claude_mpm/cli/commands/mcp_service_commands.py +304 -0
  21. claude_mpm/cli/commands/monitor.py +2 -2
  22. claude_mpm/cli/commands/mpm_init/core.py +2 -2
  23. claude_mpm/cli/commands/oauth.py +481 -0
  24. claude_mpm/cli/commands/run.py +35 -3
  25. claude_mpm/cli/commands/skill_source.py +51 -2
  26. claude_mpm/cli/commands/skills.py +5 -3
  27. claude_mpm/cli/executor.py +128 -16
  28. claude_mpm/cli/helpers.py +1 -1
  29. claude_mpm/cli/parsers/base_parser.py +84 -1
  30. claude_mpm/cli/parsers/commander_parser.py +116 -0
  31. claude_mpm/cli/parsers/mcp_parser.py +79 -0
  32. claude_mpm/cli/parsers/oauth_parser.py +165 -0
  33. claude_mpm/cli/parsers/run_parser.py +10 -0
  34. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  35. claude_mpm/cli/parsers/skills_parser.py +5 -0
  36. claude_mpm/cli/startup.py +345 -40
  37. claude_mpm/cli/startup_display.py +76 -7
  38. claude_mpm/cli/startup_logging.py +2 -2
  39. claude_mpm/cli/startup_migrations.py +236 -0
  40. claude_mpm/cli/utils.py +7 -3
  41. claude_mpm/commander/__init__.py +78 -0
  42. claude_mpm/commander/adapters/__init__.py +60 -0
  43. claude_mpm/commander/adapters/auggie.py +260 -0
  44. claude_mpm/commander/adapters/base.py +288 -0
  45. claude_mpm/commander/adapters/claude_code.py +392 -0
  46. claude_mpm/commander/adapters/codex.py +237 -0
  47. claude_mpm/commander/adapters/communication.py +366 -0
  48. claude_mpm/commander/adapters/example_usage.py +310 -0
  49. claude_mpm/commander/adapters/mpm.py +389 -0
  50. claude_mpm/commander/adapters/registry.py +204 -0
  51. claude_mpm/commander/api/__init__.py +16 -0
  52. claude_mpm/commander/api/app.py +121 -0
  53. claude_mpm/commander/api/errors.py +133 -0
  54. claude_mpm/commander/api/routes/__init__.py +8 -0
  55. claude_mpm/commander/api/routes/events.py +184 -0
  56. claude_mpm/commander/api/routes/inbox.py +171 -0
  57. claude_mpm/commander/api/routes/messages.py +148 -0
  58. claude_mpm/commander/api/routes/projects.py +271 -0
  59. claude_mpm/commander/api/routes/sessions.py +226 -0
  60. claude_mpm/commander/api/routes/work.py +296 -0
  61. claude_mpm/commander/api/schemas.py +186 -0
  62. claude_mpm/commander/chat/__init__.py +7 -0
  63. claude_mpm/commander/chat/cli.py +149 -0
  64. claude_mpm/commander/chat/commands.py +124 -0
  65. claude_mpm/commander/chat/repl.py +1957 -0
  66. claude_mpm/commander/config.py +51 -0
  67. claude_mpm/commander/config_loader.py +115 -0
  68. claude_mpm/commander/core/__init__.py +10 -0
  69. claude_mpm/commander/core/block_manager.py +325 -0
  70. claude_mpm/commander/core/response_manager.py +323 -0
  71. claude_mpm/commander/daemon.py +603 -0
  72. claude_mpm/commander/env_loader.py +59 -0
  73. claude_mpm/commander/events/__init__.py +26 -0
  74. claude_mpm/commander/events/manager.py +392 -0
  75. claude_mpm/commander/frameworks/__init__.py +12 -0
  76. claude_mpm/commander/frameworks/base.py +233 -0
  77. claude_mpm/commander/frameworks/claude_code.py +58 -0
  78. claude_mpm/commander/frameworks/mpm.py +57 -0
  79. claude_mpm/commander/git/__init__.py +5 -0
  80. claude_mpm/commander/git/worktree_manager.py +212 -0
  81. claude_mpm/commander/inbox/__init__.py +16 -0
  82. claude_mpm/commander/inbox/dedup.py +128 -0
  83. claude_mpm/commander/inbox/inbox.py +224 -0
  84. claude_mpm/commander/inbox/models.py +70 -0
  85. claude_mpm/commander/instance_manager.py +868 -0
  86. claude_mpm/commander/llm/__init__.py +6 -0
  87. claude_mpm/commander/llm/openrouter_client.py +167 -0
  88. claude_mpm/commander/llm/summarizer.py +70 -0
  89. claude_mpm/commander/memory/__init__.py +45 -0
  90. claude_mpm/commander/memory/compression.py +347 -0
  91. claude_mpm/commander/memory/embeddings.py +230 -0
  92. claude_mpm/commander/memory/entities.py +310 -0
  93. claude_mpm/commander/memory/example_usage.py +290 -0
  94. claude_mpm/commander/memory/integration.py +325 -0
  95. claude_mpm/commander/memory/search.py +381 -0
  96. claude_mpm/commander/memory/store.py +657 -0
  97. claude_mpm/commander/models/__init__.py +18 -0
  98. claude_mpm/commander/models/events.py +127 -0
  99. claude_mpm/commander/models/project.py +162 -0
  100. claude_mpm/commander/models/work.py +214 -0
  101. claude_mpm/commander/parsing/__init__.py +20 -0
  102. claude_mpm/commander/parsing/extractor.py +132 -0
  103. claude_mpm/commander/parsing/output_parser.py +270 -0
  104. claude_mpm/commander/parsing/patterns.py +100 -0
  105. claude_mpm/commander/persistence/__init__.py +11 -0
  106. claude_mpm/commander/persistence/event_store.py +274 -0
  107. claude_mpm/commander/persistence/state_store.py +403 -0
  108. claude_mpm/commander/persistence/work_store.py +164 -0
  109. claude_mpm/commander/polling/__init__.py +13 -0
  110. claude_mpm/commander/polling/event_detector.py +104 -0
  111. claude_mpm/commander/polling/output_buffer.py +49 -0
  112. claude_mpm/commander/polling/output_poller.py +153 -0
  113. claude_mpm/commander/project_session.py +268 -0
  114. claude_mpm/commander/proxy/__init__.py +12 -0
  115. claude_mpm/commander/proxy/formatter.py +89 -0
  116. claude_mpm/commander/proxy/output_handler.py +191 -0
  117. claude_mpm/commander/proxy/relay.py +155 -0
  118. claude_mpm/commander/registry.py +410 -0
  119. claude_mpm/commander/runtime/__init__.py +10 -0
  120. claude_mpm/commander/runtime/executor.py +191 -0
  121. claude_mpm/commander/runtime/monitor.py +346 -0
  122. claude_mpm/commander/session/__init__.py +6 -0
  123. claude_mpm/commander/session/context.py +81 -0
  124. claude_mpm/commander/session/manager.py +59 -0
  125. claude_mpm/commander/tmux_orchestrator.py +362 -0
  126. claude_mpm/commander/web/__init__.py +1 -0
  127. claude_mpm/commander/work/__init__.py +30 -0
  128. claude_mpm/commander/work/executor.py +207 -0
  129. claude_mpm/commander/work/queue.py +405 -0
  130. claude_mpm/commander/workflow/__init__.py +27 -0
  131. claude_mpm/commander/workflow/event_handler.py +241 -0
  132. claude_mpm/commander/workflow/notifier.py +146 -0
  133. claude_mpm/commands/mpm-config.md +8 -0
  134. claude_mpm/commands/mpm-doctor.md +8 -0
  135. claude_mpm/commands/mpm-help.md +8 -0
  136. claude_mpm/commands/mpm-init.md +8 -0
  137. claude_mpm/commands/mpm-monitor.md +8 -0
  138. claude_mpm/commands/mpm-organize.md +8 -0
  139. claude_mpm/commands/mpm-postmortem.md +8 -0
  140. claude_mpm/commands/mpm-session-resume.md +9 -1
  141. claude_mpm/commands/mpm-status.md +8 -0
  142. claude_mpm/commands/mpm-ticket-view.md +8 -0
  143. claude_mpm/commands/mpm-version.md +8 -0
  144. claude_mpm/commands/mpm.md +8 -0
  145. claude_mpm/config/agent_presets.py +8 -7
  146. claude_mpm/config/skill_sources.py +16 -0
  147. claude_mpm/constants.py +5 -0
  148. claude_mpm/core/claude_runner.py +152 -0
  149. claude_mpm/core/config.py +35 -22
  150. claude_mpm/core/config_constants.py +74 -9
  151. claude_mpm/core/constants.py +56 -12
  152. claude_mpm/core/hook_manager.py +53 -4
  153. claude_mpm/core/interactive_session.py +5 -4
  154. claude_mpm/core/logger.py +26 -9
  155. claude_mpm/core/logging_utils.py +39 -13
  156. claude_mpm/core/network_config.py +148 -0
  157. claude_mpm/core/oneshot_session.py +7 -6
  158. claude_mpm/core/output_style_manager.py +52 -12
  159. claude_mpm/core/socketio_pool.py +47 -15
  160. claude_mpm/core/unified_config.py +10 -6
  161. claude_mpm/core/unified_paths.py +68 -80
  162. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  163. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  164. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cs_tUR18.js → 1WZnGYqX.js} +1 -1
  165. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CDuw-vjf.js → 67pF3qNn.js} +1 -1
  166. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bTOqqlTd.js → 6RxdMKe4.js} +1 -1
  167. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DwBR2MJi.js → 8cZrfX0h.js} +1 -1
  168. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{ZGh7QtNv.js → 9a6T2nm-.js} +1 -1
  169. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D9lljYKQ.js → B443AUzu.js} +1 -1
  170. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{RJiighC3.js → B8AwtY2H.js} +1 -1
  171. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uuIeMWc-.js → BF15LAsF.js} +1 -1
  172. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D3k0OPJN.js → BRcwIQNr.js} +1 -1
  173. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CyWMqx4W.js → BV6nKitt.js} +1 -1
  174. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CiIAseT4.js → BViJ8lZt.js} +5 -5
  175. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CBBdVcY8.js → BcQ-Q0FE.js} +1 -1
  176. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BovzEFCE.js → Bpyvgze_.js} +1 -1
  177. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  178. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  179. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{eNVUfhuA.js → C3rbW_a-.js} +1 -1
  180. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{GYwsonyD.js → C8WYN38h.js} +1 -1
  181. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BIF9m_hv.js → C9I8FlXH.js} +1 -1
  182. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B0uc0UOD.js → CIQcWgO2.js} +3 -3
  183. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Be7GpZd6.js → CIctN7YN.js} +1 -1
  184. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Bh0LDWpI.js → CKrS_JZW.js} +2 -2
  185. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DUrLdbGD.js → CR6P9C4A.js} +1 -1
  186. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7xVLGWV.js → CRRR9MD_.js} +1 -1
  187. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  188. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dhb8PKl3.js → CSXtMOf0.js} +1 -1
  189. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BPYeabCQ.js → CT-sbxSk.js} +1 -1
  190. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{sQeU3Y1z.js → CWm6DJsp.js} +1 -1
  191. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CnA0NrzZ.js → CpqQ1Kzn.js} +1 -1
  192. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4B-KCzX.js → D2nGpDRe.js} +1 -1
  193. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DGkLK5U1.js → D9iCMida.js} +1 -1
  194. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BofRWZRR.js → D9ykgMoY.js} +1 -1
  195. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DmxopI1J.js → DL2Ldur1.js} +1 -1
  196. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C30mlcqg.js → DPfltzjH.js} +1 -1
  197. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Vzk33B_K.js → DR8nis88.js} +2 -2
  198. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DI7hHRFL.js → DUliQN2b.js} +1 -1
  199. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4JcI4KD.js → DXlhR01x.js} +1 -1
  200. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bT1r9zLR.js → D_lyTybS.js} +1 -1
  201. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DZX00Y4g.js → DngoTTgh.js} +1 -1
  202. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzZX-COe.js → DqkmHtDC.js} +1 -1
  203. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7RN905-.js → DsDh8EYs.js} +1 -1
  204. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DLVjFsZ3.js → DypDmXgd.js} +1 -1
  205. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{iEWssX7S.js → IPYC-LnN.js} +1 -1
  206. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  207. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DaimHw_p.js → JpevfAFt.js} +1 -1
  208. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DY1XQ8fi.js → R8CEIRAd.js} +1 -1
  209. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dle-35c7.js → Zxy7qc-l.js} +2 -2
  210. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  211. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C_Usid8X.js → qtd3IeO4.js} +2 -2
  212. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzeYkLYB.js → ulBFON_C.js} +2 -2
  213. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cfqx1Qun.js → wQVh1CoA.js} +1 -1
  214. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/{app.D6-I5TpK.js → app.Dr7t0z2J.js} +2 -2
  215. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  216. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.m1gL8KXf.js → 0.RgBboRvH.js} +1 -1
  217. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{1.CgNOuw-d.js → 1.DG-KkbDf.js} +1 -1
  218. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  219. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
  220. claude_mpm/dashboard/static/svelte-build/index.html +9 -9
  221. claude_mpm/experimental/cli_enhancements.py +2 -1
  222. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  223. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  224. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
  225. claude_mpm/hooks/claude_hooks/event_handlers.py +466 -136
  226. claude_mpm/hooks/claude_hooks/hook_handler.py +204 -104
  227. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  228. claude_mpm/hooks/claude_hooks/installer.py +291 -59
  229. claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
  230. claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
  231. claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
  232. claude_mpm/hooks/claude_hooks/services/connection_manager.py +41 -26
  233. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
  234. claude_mpm/hooks/claude_hooks/services/container.py +326 -0
  235. claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
  236. claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
  237. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
  238. claude_mpm/hooks/session_resume_hook.py +89 -1
  239. claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
  240. claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
  241. claude_mpm/init.py +22 -15
  242. claude_mpm/mcp/__init__.py +9 -0
  243. claude_mpm/mcp/google_workspace_server.py +610 -0
  244. claude_mpm/scripts/claude-hook-handler.sh +46 -19
  245. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  246. claude_mpm/services/agents/agent_selection_service.py +2 -2
  247. claude_mpm/services/agents/cache_git_manager.py +1 -1
  248. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +3 -0
  249. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  250. claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
  251. claude_mpm/services/cli/__init__.py +3 -0
  252. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  253. claude_mpm/services/cli/session_resume_helper.py +10 -2
  254. claude_mpm/services/command_deployment_service.py +44 -26
  255. claude_mpm/services/delegation_detector.py +175 -0
  256. claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
  257. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  258. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  259. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  260. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  261. claude_mpm/services/diagnostics/models.py +14 -1
  262. claude_mpm/services/event_log.py +325 -0
  263. claude_mpm/services/hook_installer_service.py +77 -8
  264. claude_mpm/services/infrastructure/__init__.py +4 -0
  265. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  266. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  267. claude_mpm/services/mcp_config_manager.py +99 -19
  268. claude_mpm/services/mcp_service_registry.py +294 -0
  269. claude_mpm/services/monitor/daemon_manager.py +15 -4
  270. claude_mpm/services/monitor/management/lifecycle.py +8 -2
  271. claude_mpm/services/monitor/server.py +111 -16
  272. claude_mpm/services/pm_skills_deployer.py +261 -87
  273. claude_mpm/services/skills/git_skill_source_manager.py +130 -10
  274. claude_mpm/services/skills/selective_skill_deployer.py +142 -16
  275. claude_mpm/services/skills/skill_discovery_service.py +74 -4
  276. claude_mpm/services/skills_deployer.py +31 -5
  277. claude_mpm/services/socketio/handlers/hook.py +14 -7
  278. claude_mpm/services/socketio/server/main.py +12 -4
  279. claude_mpm/skills/__init__.py +2 -1
  280. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  281. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  282. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  283. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  284. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  285. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  286. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  287. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  288. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  289. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  290. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  291. claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
  292. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  293. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  294. claude_mpm/skills/bundled/pm/{pm-teaching-mode → mpm-teaching-mode}/SKILL.md +2 -2
  295. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  296. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  297. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  298. claude_mpm/skills/registry.py +295 -90
  299. claude_mpm/skills/skill_manager.py +4 -4
  300. claude_mpm-5.6.76.dist-info/METADATA +416 -0
  301. {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/RECORD +312 -175
  302. {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/WHEEL +1 -1
  303. {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/entry_points.txt +2 -0
  304. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +0 -1
  305. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +0 -1
  306. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +0 -1
  307. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +0 -24
  308. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +0 -1
  309. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +0 -1
  310. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +0 -323
  311. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +0 -1
  312. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +0 -1
  313. claude_mpm-5.4.85.dist-info/METADATA +0 -1023
  314. /claude_mpm/skills/bundled/pm/{pm-bug-reporting/pm-bug-reporting.md → mpm-bug-reporting/SKILL.md} +0 -0
  315. /claude_mpm/skills/bundled/pm/{pm-delegation-patterns → mpm-delegation-patterns}/SKILL.md +0 -0
  316. /claude_mpm/skills/bundled/pm/{pm-git-file-tracking → mpm-git-file-tracking}/SKILL.md +0 -0
  317. /claude_mpm/skills/bundled/pm/{pm-pr-workflow → mpm-pr-workflow}/SKILL.md +0 -0
  318. /claude_mpm/skills/bundled/pm/{pm-ticketing-integration → mpm-ticketing-integration}/SKILL.md +0 -0
  319. /claude_mpm/skills/bundled/pm/{pm-verification-protocols → mpm-verification-protocols}/SKILL.md +0 -0
  320. {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/licenses/LICENSE +0 -0
  321. {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  322. {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,148 @@
1
+ """Message and thread management endpoints for MPM Commander API.
2
+
3
+ This module implements REST endpoints for sending messages and retrieving
4
+ conversation threads for projects.
5
+ """
6
+
7
+ import uuid
8
+ from typing import List
9
+
10
+ from fastapi import APIRouter, Request
11
+
12
+ from ...models import ThreadMessage
13
+ from ..errors import ProjectNotFoundError
14
+ from ..schemas import MessageResponse, SendMessageRequest
15
+
16
+ router = APIRouter()
17
+
18
+
19
+ def _get_registry(request: Request):
20
+ """Get registry instance from app.state."""
21
+ if not hasattr(request.app.state, "registry") or request.app.state.registry is None:
22
+ raise RuntimeError("Registry not initialized")
23
+ return request.app.state.registry
24
+
25
+
26
+ def _message_to_response(message: ThreadMessage) -> MessageResponse:
27
+ """Convert ThreadMessage model to MessageResponse schema.
28
+
29
+ Args:
30
+ message: ThreadMessage instance
31
+
32
+ Returns:
33
+ MessageResponse with message data
34
+ """
35
+ return MessageResponse(
36
+ id=message.id,
37
+ role=message.role,
38
+ content=message.content,
39
+ session_id=message.session_id,
40
+ timestamp=message.timestamp,
41
+ )
42
+
43
+
44
+ @router.get("/projects/{project_id}/thread", response_model=List[MessageResponse])
45
+ async def get_thread(request: Request, project_id: str) -> List[MessageResponse]:
46
+ """Get conversation thread for a project.
47
+
48
+ Returns all messages in chronological order.
49
+
50
+ Args:
51
+ project_id: Unique project identifier
52
+
53
+ Returns:
54
+ List of messages in thread (may be empty)
55
+
56
+ Raises:
57
+ ProjectNotFoundError: If project_id doesn't exist
58
+
59
+ Example:
60
+ GET /api/projects/abc-123/thread
61
+ Response: [
62
+ {
63
+ "id": "msg-1",
64
+ "role": "user",
65
+ "content": "Fix the login bug",
66
+ "session_id": null,
67
+ "timestamp": "2025-01-12T10:00:00Z"
68
+ },
69
+ {
70
+ "id": "msg-2",
71
+ "role": "assistant",
72
+ "content": "I'll investigate the login issue",
73
+ "session_id": "sess-456",
74
+ "timestamp": "2025-01-12T10:00:30Z"
75
+ }
76
+ ]
77
+ """
78
+ registry = _get_registry(request)
79
+ project = registry.get(project_id)
80
+
81
+ if project is None:
82
+ raise ProjectNotFoundError(project_id)
83
+
84
+ # Convert thread messages to responses
85
+ return [_message_to_response(m) for m in project.thread]
86
+
87
+
88
+ @router.post(
89
+ "/projects/{project_id}/messages", response_model=MessageResponse, status_code=201
90
+ )
91
+ async def send_message(
92
+ request: Request, project_id: str, req: SendMessageRequest
93
+ ) -> MessageResponse:
94
+ """Send a message to a project's active session.
95
+
96
+ Adds message to conversation thread and sends to specified or active session.
97
+
98
+ Args:
99
+ project_id: Unique project identifier
100
+ req: Message request with content and optional session_id
101
+
102
+ Returns:
103
+ Created message information
104
+
105
+ Raises:
106
+ ProjectNotFoundError: If project_id doesn't exist
107
+
108
+ Example:
109
+ POST /api/projects/abc-123/messages
110
+ Body: {
111
+ "content": "Fix the login bug",
112
+ "session_id": "sess-456"
113
+ }
114
+ Response: {
115
+ "id": "msg-1",
116
+ "role": "user",
117
+ "content": "Fix the login bug",
118
+ "session_id": "sess-456",
119
+ "timestamp": "2025-01-12T10:00:00Z"
120
+ }
121
+ """
122
+ registry = _get_registry(request)
123
+ project = registry.get(project_id)
124
+
125
+ if project is None:
126
+ raise ProjectNotFoundError(project_id)
127
+
128
+ # Generate message ID
129
+ message_id = str(uuid.uuid4())
130
+
131
+ # Create message object
132
+ message = ThreadMessage(
133
+ id=message_id,
134
+ role="user",
135
+ content=req.content,
136
+ session_id=req.session_id,
137
+ )
138
+
139
+ # Add to project thread
140
+ project.thread.append(message)
141
+
142
+ # Update last activity
143
+ registry.touch(project_id)
144
+
145
+ # TODO: Send to session/runtime adapter (Phase 2)
146
+ # For Phase 1, message is just stored in thread
147
+
148
+ return _message_to_response(message)
@@ -0,0 +1,271 @@
1
+ """Project management endpoints for MPM Commander API.
2
+
3
+ This module implements REST endpoints for registering, listing, and managing
4
+ projects in the MPM Commander.
5
+ """
6
+
7
+ from pathlib import Path
8
+ from typing import List
9
+
10
+ from fastapi import APIRouter, Request, Response
11
+
12
+ from ...models import ProjectState
13
+ from ..errors import InvalidPathError, ProjectAlreadyExistsError, ProjectNotFoundError
14
+ from ..schemas import ProjectResponse, RegisterProjectRequest, SessionResponse
15
+
16
+ router = APIRouter()
17
+
18
+
19
+ def _get_registry(request: Request):
20
+ """Get registry instance from app.state."""
21
+ if not hasattr(request.app.state, "registry") or request.app.state.registry is None:
22
+ raise RuntimeError("Registry not initialized")
23
+ return request.app.state.registry
24
+
25
+
26
+ def _project_to_response(project) -> ProjectResponse:
27
+ """Convert Project model to ProjectResponse schema.
28
+
29
+ Args:
30
+ project: Project instance
31
+
32
+ Returns:
33
+ ProjectResponse with all project data
34
+ """
35
+ # Convert sessions dict to list of SessionResponse
36
+ session_responses = [
37
+ SessionResponse(
38
+ id=session.id,
39
+ project_id=session.project_id,
40
+ runtime=session.runtime,
41
+ tmux_target=session.tmux_target,
42
+ status=session.status,
43
+ created_at=session.created_at,
44
+ )
45
+ for session in project.sessions.values()
46
+ ]
47
+
48
+ return ProjectResponse(
49
+ id=project.id,
50
+ path=project.path,
51
+ name=project.name,
52
+ state=project.state.value,
53
+ state_reason=project.state_reason,
54
+ sessions=session_responses,
55
+ pending_events_count=len(project.pending_events),
56
+ last_activity=project.last_activity,
57
+ created_at=project.created_at,
58
+ )
59
+
60
+
61
+ @router.get("/projects", response_model=List[ProjectResponse])
62
+ async def list_projects(request: Request) -> List[ProjectResponse]:
63
+ """List all registered projects.
64
+
65
+ Returns:
66
+ List of project information (may be empty)
67
+
68
+ Example:
69
+ GET /api/projects
70
+ Response: [
71
+ {
72
+ "id": "abc-123",
73
+ "path": "/Users/user/projects/my-app",
74
+ "name": "my-app",
75
+ "state": "idle",
76
+ "state_reason": null,
77
+ "sessions": [],
78
+ "pending_events_count": 0,
79
+ "last_activity": "2025-01-12T10:00:00Z",
80
+ "created_at": "2025-01-12T09:00:00Z"
81
+ }
82
+ ]
83
+ """
84
+ registry = _get_registry(request)
85
+ projects = registry.list_all()
86
+ return [_project_to_response(p) for p in projects]
87
+
88
+
89
+ @router.get("/projects/{project_id}", response_model=ProjectResponse)
90
+ async def get_project(request: Request, project_id: str) -> ProjectResponse:
91
+ """Get project details by ID.
92
+
93
+ Args:
94
+ project_id: Unique project identifier
95
+
96
+ Returns:
97
+ Project information
98
+
99
+ Raises:
100
+ ProjectNotFoundError: If project_id doesn't exist
101
+
102
+ Example:
103
+ GET /api/projects/abc-123
104
+ Response: {
105
+ "id": "abc-123",
106
+ "path": "/Users/user/projects/my-app",
107
+ "name": "my-app",
108
+ "state": "idle",
109
+ ...
110
+ }
111
+ """
112
+ registry = _get_registry(request)
113
+ project = registry.get(project_id)
114
+
115
+ if project is None:
116
+ raise ProjectNotFoundError(project_id)
117
+
118
+ return _project_to_response(project)
119
+
120
+
121
+ @router.post("/projects", response_model=ProjectResponse, status_code=201)
122
+ async def register_project(
123
+ request: Request, req: RegisterProjectRequest
124
+ ) -> ProjectResponse:
125
+ """Register a new project.
126
+
127
+ Args:
128
+ req: Registration request with path and optional name
129
+
130
+ Returns:
131
+ Newly registered project information
132
+
133
+ Raises:
134
+ InvalidPathError: If path doesn't exist or isn't a directory
135
+ ProjectAlreadyExistsError: If path already registered
136
+
137
+ Example:
138
+ POST /api/projects
139
+ Body: {
140
+ "path": "/Users/user/projects/my-app",
141
+ "name": "My App"
142
+ }
143
+ Response: {
144
+ "id": "abc-123",
145
+ "path": "/Users/user/projects/my-app",
146
+ "name": "My App",
147
+ "state": "idle",
148
+ ...
149
+ }
150
+ """
151
+ registry = _get_registry(request)
152
+
153
+ # Validate path exists and is directory
154
+ path_obj = Path(req.path)
155
+ if not path_obj.exists() or not path_obj.is_dir():
156
+ raise InvalidPathError(req.path)
157
+
158
+ try:
159
+ project = registry.register(req.path, req.name, req.project_id)
160
+ return _project_to_response(project)
161
+ except ValueError as e:
162
+ # Registry raises ValueError for duplicate registration
163
+ error_msg = str(e)
164
+ if "already registered" in error_msg.lower():
165
+ raise ProjectAlreadyExistsError(req.path) from e
166
+ # Re-raise as InvalidPathError for other validation errors
167
+ raise InvalidPathError(req.path) from e
168
+
169
+
170
+ @router.delete("/projects/{project_id}", status_code=204)
171
+ async def unregister_project(request: Request, project_id: str) -> Response:
172
+ """Unregister a project.
173
+
174
+ Args:
175
+ project_id: Unique project identifier
176
+
177
+ Returns:
178
+ Empty response with 204 status
179
+
180
+ Raises:
181
+ ProjectNotFoundError: If project_id doesn't exist
182
+
183
+ Example:
184
+ DELETE /api/projects/abc-123
185
+ Response: 204 No Content
186
+ """
187
+ registry = _get_registry(request)
188
+
189
+ try:
190
+ registry.unregister(project_id)
191
+ return Response(status_code=204)
192
+ except KeyError as e:
193
+ raise ProjectNotFoundError(project_id) from e
194
+
195
+
196
+ @router.post("/projects/{project_id}/pause", response_model=ProjectResponse)
197
+ async def pause_project(request: Request, project_id: str) -> ProjectResponse:
198
+ """Pause a project.
199
+
200
+ Sets project state to PAUSED to prevent automatic work processing.
201
+
202
+ Args:
203
+ project_id: Unique project identifier
204
+
205
+ Returns:
206
+ Updated project information
207
+
208
+ Raises:
209
+ ProjectNotFoundError: If project_id doesn't exist
210
+
211
+ Example:
212
+ POST /api/projects/abc-123/pause
213
+ Response: {
214
+ "id": "abc-123",
215
+ "state": "paused",
216
+ "state_reason": "Manually paused via API",
217
+ ...
218
+ }
219
+ """
220
+ registry = _get_registry(request)
221
+ project = registry.get(project_id)
222
+
223
+ if project is None:
224
+ raise ProjectNotFoundError(project_id)
225
+
226
+ registry.update_state(
227
+ project_id,
228
+ ProjectState.PAUSED,
229
+ reason="Manually paused via API",
230
+ )
231
+
232
+ return _project_to_response(project)
233
+
234
+
235
+ @router.post("/projects/{project_id}/resume", response_model=ProjectResponse)
236
+ async def resume_project(request: Request, project_id: str) -> ProjectResponse:
237
+ """Resume a paused project.
238
+
239
+ Sets project state back to IDLE to allow work processing.
240
+
241
+ Args:
242
+ project_id: Unique project identifier
243
+
244
+ Returns:
245
+ Updated project information
246
+
247
+ Raises:
248
+ ProjectNotFoundError: If project_id doesn't exist
249
+
250
+ Example:
251
+ POST /api/projects/abc-123/resume
252
+ Response: {
253
+ "id": "abc-123",
254
+ "state": "idle",
255
+ "state_reason": "Resumed via API",
256
+ ...
257
+ }
258
+ """
259
+ registry = _get_registry(request)
260
+ project = registry.get(project_id)
261
+
262
+ if project is None:
263
+ raise ProjectNotFoundError(project_id)
264
+
265
+ registry.update_state(
266
+ project_id,
267
+ ProjectState.IDLE,
268
+ reason="Resumed via API",
269
+ )
270
+
271
+ return _project_to_response(project)
@@ -0,0 +1,226 @@
1
+ """Session management endpoints for MPM Commander API.
2
+
3
+ This module implements REST endpoints for creating and managing tool sessions
4
+ (Claude Code, Aider, etc.) within projects.
5
+ """
6
+
7
+ import logging
8
+ import subprocess # nosec B404 - needed for tmux error handling
9
+ import uuid
10
+ from typing import List
11
+
12
+ from fastapi import APIRouter, Request, Response
13
+
14
+ from ...models import ToolSession
15
+ from ..errors import (
16
+ InvalidRuntimeError,
17
+ ProjectNotFoundError,
18
+ SessionNotFoundError,
19
+ TmuxNoSpaceError,
20
+ )
21
+ from ..schemas import CreateSessionRequest, SessionResponse
22
+
23
+ router = APIRouter()
24
+ logger = logging.getLogger(__name__)
25
+
26
+ # Valid runtime adapters (Phase 1: claude-code only)
27
+ VALID_RUNTIMES = {"claude-code"}
28
+
29
+
30
+ def _get_registry(request: Request):
31
+ """Get registry instance from app.state."""
32
+ if not hasattr(request.app.state, "registry") or request.app.state.registry is None:
33
+ raise RuntimeError("Registry not initialized")
34
+ return request.app.state.registry
35
+
36
+
37
+ def _get_tmux(request: Request):
38
+ """Get tmux orchestrator instance from app.state."""
39
+ if not hasattr(request.app.state, "tmux") or request.app.state.tmux is None:
40
+ raise RuntimeError("Tmux orchestrator not initialized")
41
+ return request.app.state.tmux
42
+
43
+
44
+ def _session_to_response(session: ToolSession) -> SessionResponse:
45
+ """Convert ToolSession model to SessionResponse schema.
46
+
47
+ Args:
48
+ session: ToolSession instance
49
+
50
+ Returns:
51
+ SessionResponse with session data
52
+ """
53
+ return SessionResponse(
54
+ id=session.id,
55
+ project_id=session.project_id,
56
+ runtime=session.runtime,
57
+ tmux_target=session.tmux_target,
58
+ status=session.status,
59
+ created_at=session.created_at,
60
+ )
61
+
62
+
63
+ @router.get("/projects/{project_id}/sessions", response_model=List[SessionResponse])
64
+ async def list_sessions(request: Request, project_id: str) -> List[SessionResponse]:
65
+ """List all sessions for a project.
66
+
67
+ Args:
68
+ project_id: Unique project identifier
69
+
70
+ Returns:
71
+ List of session information (may be empty)
72
+
73
+ Raises:
74
+ ProjectNotFoundError: If project_id doesn't exist
75
+
76
+ Example:
77
+ GET /api/projects/abc-123/sessions
78
+ Response: [
79
+ {
80
+ "id": "sess-456",
81
+ "project_id": "abc-123",
82
+ "runtime": "claude-code",
83
+ "tmux_target": "%1",
84
+ "status": "running",
85
+ "created_at": "2025-01-12T10:00:00Z"
86
+ }
87
+ ]
88
+ """
89
+ registry = _get_registry(request)
90
+ project = registry.get(project_id)
91
+
92
+ if project is None:
93
+ raise ProjectNotFoundError(project_id)
94
+
95
+ # Convert sessions dict to list of responses
96
+ return [_session_to_response(s) for s in project.sessions.values()]
97
+
98
+
99
+ @router.post(
100
+ "/projects/{project_id}/sessions", response_model=SessionResponse, status_code=201
101
+ )
102
+ async def create_session(
103
+ request: Request, project_id: str, req: CreateSessionRequest
104
+ ) -> SessionResponse:
105
+ """Create a new session for a project.
106
+
107
+ Creates a new tmux pane and initializes the specified runtime adapter.
108
+
109
+ Args:
110
+ project_id: Unique project identifier
111
+ req: Session creation request
112
+
113
+ Returns:
114
+ Newly created session information
115
+
116
+ Raises:
117
+ ProjectNotFoundError: If project_id doesn't exist
118
+ InvalidRuntimeError: If runtime is not supported
119
+ TmuxNoSpaceError: If tmux has no space for new pane
120
+
121
+ Example:
122
+ POST /api/projects/abc-123/sessions
123
+ Body: {
124
+ "runtime": "claude-code",
125
+ "agent_prompt": "You are a helpful coding assistant"
126
+ }
127
+ Response: {
128
+ "id": "sess-456",
129
+ "project_id": "abc-123",
130
+ "runtime": "claude-code",
131
+ "tmux_target": "%1",
132
+ "status": "initializing",
133
+ "created_at": "2025-01-12T10:00:00Z"
134
+ }
135
+ """
136
+ registry = _get_registry(request)
137
+ tmux_orch = _get_tmux(request)
138
+
139
+ # Validate project exists
140
+ project = registry.get(project_id)
141
+ if project is None:
142
+ raise ProjectNotFoundError(project_id)
143
+
144
+ # Validate runtime
145
+ if req.runtime not in VALID_RUNTIMES:
146
+ raise InvalidRuntimeError(req.runtime)
147
+
148
+ # Generate session ID
149
+ session_id = str(uuid.uuid4())
150
+
151
+ # Create tmux pane for session
152
+ try:
153
+ tmux_target = tmux_orch.create_pane(
154
+ pane_id=f"{project.name}-{req.runtime}",
155
+ working_dir=project.path,
156
+ )
157
+ except subprocess.CalledProcessError as e:
158
+ stderr = e.stderr.decode() if e.stderr else ""
159
+ if "no space for new pane" in stderr.lower():
160
+ raise TmuxNoSpaceError() from None
161
+ raise # Re-raise other subprocess errors
162
+
163
+ # Create session object
164
+ session = ToolSession(
165
+ id=session_id,
166
+ project_id=project_id,
167
+ runtime=req.runtime,
168
+ tmux_target=tmux_target,
169
+ status="initializing",
170
+ )
171
+
172
+ # Add session to project
173
+ registry.add_session(project_id, session)
174
+
175
+ # TODO: Start runtime adapter in pane (Phase 2)
176
+ # For Phase 1, session stays in "initializing" state
177
+
178
+ return _session_to_response(session)
179
+
180
+
181
+ @router.delete("/sessions/{session_id}", status_code=204)
182
+ async def stop_session(request: Request, session_id: str) -> Response:
183
+ """Stop and remove a session.
184
+
185
+ Kills the tmux pane and removes the session from its project.
186
+
187
+ Args:
188
+ session_id: Unique session identifier
189
+
190
+ Returns:
191
+ Empty response with 204 status
192
+
193
+ Raises:
194
+ SessionNotFoundError: If session_id doesn't exist
195
+
196
+ Example:
197
+ DELETE /api/sessions/sess-456
198
+ Response: 204 No Content
199
+ """
200
+ registry = _get_registry(request)
201
+ tmux_orch = _get_tmux(request)
202
+
203
+ # Find session across all projects
204
+ session = None
205
+ parent_project_id = None
206
+
207
+ for project in registry.list_all():
208
+ if session_id in project.sessions:
209
+ session = project.sessions[session_id]
210
+ parent_project_id = project.id
211
+ break
212
+
213
+ if session is None or parent_project_id is None:
214
+ raise SessionNotFoundError(session_id)
215
+
216
+ # Kill tmux pane
217
+ try:
218
+ tmux_orch.kill_pane(session.tmux_target)
219
+ except Exception as e:
220
+ # Pane may already be dead, continue with cleanup
221
+ logger.debug("Failed to kill pane (may already be dead): %s", e)
222
+
223
+ # Remove session from project
224
+ registry.remove_session(parent_project_id, session_id)
225
+
226
+ return Response(status_code=204)