claude-mpm 5.4.55__py3-none-any.whl → 5.6.1__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 (401) 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 +111 -686
  6. claude_mpm/agents/WORKFLOW.md +2 -0
  7. claude_mpm/agents/templates/circuit-breakers.md +26 -17
  8. claude_mpm/cli/__init__.py +5 -1
  9. claude_mpm/cli/commands/agents.py +2 -4
  10. claude_mpm/cli/commands/agents_reconcile.py +197 -0
  11. claude_mpm/cli/commands/autotodos.py +566 -0
  12. claude_mpm/cli/commands/commander.py +46 -0
  13. claude_mpm/cli/commands/configure.py +620 -21
  14. claude_mpm/cli/commands/hook_errors.py +60 -60
  15. claude_mpm/cli/commands/monitor.py +2 -2
  16. claude_mpm/cli/commands/mpm_init/core.py +2 -2
  17. claude_mpm/cli/commands/run.py +35 -3
  18. claude_mpm/cli/commands/skills.py +166 -14
  19. claude_mpm/cli/executor.py +120 -16
  20. claude_mpm/cli/interactive/__init__.py +10 -0
  21. claude_mpm/cli/interactive/agent_wizard.py +30 -50
  22. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  23. claude_mpm/cli/interactive/skill_selector.py +481 -0
  24. claude_mpm/cli/parsers/base_parser.py +76 -1
  25. claude_mpm/cli/parsers/commander_parser.py +83 -0
  26. claude_mpm/cli/parsers/run_parser.py +10 -0
  27. claude_mpm/cli/startup.py +276 -403
  28. claude_mpm/cli/startup_display.py +72 -5
  29. claude_mpm/cli/startup_logging.py +2 -2
  30. claude_mpm/cli/utils.py +7 -3
  31. claude_mpm/commander/__init__.py +72 -0
  32. claude_mpm/commander/adapters/__init__.py +31 -0
  33. claude_mpm/commander/adapters/base.py +191 -0
  34. claude_mpm/commander/adapters/claude_code.py +361 -0
  35. claude_mpm/commander/adapters/communication.py +366 -0
  36. claude_mpm/commander/api/__init__.py +16 -0
  37. claude_mpm/commander/api/app.py +105 -0
  38. claude_mpm/commander/api/errors.py +112 -0
  39. claude_mpm/commander/api/routes/__init__.py +8 -0
  40. claude_mpm/commander/api/routes/events.py +184 -0
  41. claude_mpm/commander/api/routes/inbox.py +171 -0
  42. claude_mpm/commander/api/routes/messages.py +148 -0
  43. claude_mpm/commander/api/routes/projects.py +271 -0
  44. claude_mpm/commander/api/routes/sessions.py +215 -0
  45. claude_mpm/commander/api/routes/work.py +260 -0
  46. claude_mpm/commander/api/schemas.py +182 -0
  47. claude_mpm/commander/chat/__init__.py +7 -0
  48. claude_mpm/commander/chat/cli.py +107 -0
  49. claude_mpm/commander/chat/commands.py +96 -0
  50. claude_mpm/commander/chat/repl.py +310 -0
  51. claude_mpm/commander/config.py +49 -0
  52. claude_mpm/commander/config_loader.py +115 -0
  53. claude_mpm/commander/daemon.py +398 -0
  54. claude_mpm/commander/events/__init__.py +26 -0
  55. claude_mpm/commander/events/manager.py +332 -0
  56. claude_mpm/commander/frameworks/__init__.py +12 -0
  57. claude_mpm/commander/frameworks/base.py +143 -0
  58. claude_mpm/commander/frameworks/claude_code.py +58 -0
  59. claude_mpm/commander/frameworks/mpm.py +62 -0
  60. claude_mpm/commander/inbox/__init__.py +16 -0
  61. claude_mpm/commander/inbox/dedup.py +128 -0
  62. claude_mpm/commander/inbox/inbox.py +224 -0
  63. claude_mpm/commander/inbox/models.py +70 -0
  64. claude_mpm/commander/instance_manager.py +337 -0
  65. claude_mpm/commander/llm/__init__.py +6 -0
  66. claude_mpm/commander/llm/openrouter_client.py +167 -0
  67. claude_mpm/commander/llm/summarizer.py +70 -0
  68. claude_mpm/commander/models/__init__.py +18 -0
  69. claude_mpm/commander/models/events.py +121 -0
  70. claude_mpm/commander/models/project.py +162 -0
  71. claude_mpm/commander/models/work.py +214 -0
  72. claude_mpm/commander/parsing/__init__.py +20 -0
  73. claude_mpm/commander/parsing/extractor.py +132 -0
  74. claude_mpm/commander/parsing/output_parser.py +270 -0
  75. claude_mpm/commander/parsing/patterns.py +100 -0
  76. claude_mpm/commander/persistence/__init__.py +11 -0
  77. claude_mpm/commander/persistence/event_store.py +274 -0
  78. claude_mpm/commander/persistence/state_store.py +309 -0
  79. claude_mpm/commander/persistence/work_store.py +164 -0
  80. claude_mpm/commander/polling/__init__.py +13 -0
  81. claude_mpm/commander/polling/event_detector.py +104 -0
  82. claude_mpm/commander/polling/output_buffer.py +49 -0
  83. claude_mpm/commander/polling/output_poller.py +153 -0
  84. claude_mpm/commander/project_session.py +268 -0
  85. claude_mpm/commander/proxy/__init__.py +12 -0
  86. claude_mpm/commander/proxy/formatter.py +89 -0
  87. claude_mpm/commander/proxy/output_handler.py +191 -0
  88. claude_mpm/commander/proxy/relay.py +155 -0
  89. claude_mpm/commander/registry.py +404 -0
  90. claude_mpm/commander/runtime/__init__.py +10 -0
  91. claude_mpm/commander/runtime/executor.py +191 -0
  92. claude_mpm/commander/runtime/monitor.py +316 -0
  93. claude_mpm/commander/session/__init__.py +6 -0
  94. claude_mpm/commander/session/context.py +81 -0
  95. claude_mpm/commander/session/manager.py +59 -0
  96. claude_mpm/commander/tmux_orchestrator.py +361 -0
  97. claude_mpm/commander/web/__init__.py +1 -0
  98. claude_mpm/commander/work/__init__.py +30 -0
  99. claude_mpm/commander/work/executor.py +189 -0
  100. claude_mpm/commander/work/queue.py +405 -0
  101. claude_mpm/commander/workflow/__init__.py +27 -0
  102. claude_mpm/commander/workflow/event_handler.py +219 -0
  103. claude_mpm/commander/workflow/notifier.py +146 -0
  104. claude_mpm/commands/mpm-config.md +8 -0
  105. claude_mpm/commands/mpm-doctor.md +8 -0
  106. claude_mpm/commands/mpm-help.md +8 -0
  107. claude_mpm/commands/mpm-init.md +8 -0
  108. claude_mpm/commands/mpm-monitor.md +8 -0
  109. claude_mpm/commands/mpm-organize.md +8 -0
  110. claude_mpm/commands/mpm-postmortem.md +8 -0
  111. claude_mpm/commands/mpm-session-resume.md +9 -1
  112. claude_mpm/commands/mpm-status.md +8 -0
  113. claude_mpm/commands/mpm-ticket-view.md +8 -0
  114. claude_mpm/commands/mpm-version.md +8 -0
  115. claude_mpm/commands/mpm.md +8 -0
  116. claude_mpm/config/agent_presets.py +8 -7
  117. claude_mpm/constants.py +1 -0
  118. claude_mpm/core/claude_runner.py +2 -2
  119. claude_mpm/core/config.py +5 -0
  120. claude_mpm/core/hook_manager.py +51 -3
  121. claude_mpm/core/interactive_session.py +7 -7
  122. claude_mpm/core/logger.py +10 -7
  123. claude_mpm/core/logging_utils.py +4 -2
  124. claude_mpm/core/output_style_manager.py +31 -13
  125. claude_mpm/core/unified_config.py +54 -8
  126. claude_mpm/core/unified_paths.py +30 -13
  127. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  128. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  129. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cs_tUR18.js → 1WZnGYqX.js} +1 -1
  130. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CDuw-vjf.js → 67pF3qNn.js} +1 -1
  131. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bTOqqlTd.js → 6RxdMKe4.js} +1 -1
  132. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DwBR2MJi.js → 8cZrfX0h.js} +1 -1
  133. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{ZGh7QtNv.js → 9a6T2nm-.js} +1 -1
  134. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D9lljYKQ.js → B443AUzu.js} +1 -1
  135. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{RJiighC3.js → B8AwtY2H.js} +1 -1
  136. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uuIeMWc-.js → BF15LAsF.js} +1 -1
  137. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D3k0OPJN.js → BRcwIQNr.js} +1 -1
  138. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CyWMqx4W.js → BV6nKitt.js} +1 -1
  139. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CiIAseT4.js → BViJ8lZt.js} +5 -5
  140. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CBBdVcY8.js → BcQ-Q0FE.js} +1 -1
  141. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BovzEFCE.js → Bpyvgze_.js} +1 -1
  142. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  143. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  144. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{eNVUfhuA.js → C3rbW_a-.js} +1 -1
  145. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{GYwsonyD.js → C8WYN38h.js} +1 -1
  146. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BIF9m_hv.js → C9I8FlXH.js} +1 -1
  147. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B0uc0UOD.js → CIQcWgO2.js} +3 -3
  148. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Be7GpZd6.js → CIctN7YN.js} +1 -1
  149. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Bh0LDWpI.js → CKrS_JZW.js} +2 -2
  150. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DUrLdbGD.js → CR6P9C4A.js} +1 -1
  151. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7xVLGWV.js → CRRR9MD_.js} +1 -1
  152. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  153. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dhb8PKl3.js → CSXtMOf0.js} +1 -1
  154. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BPYeabCQ.js → CT-sbxSk.js} +1 -1
  155. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{sQeU3Y1z.js → CWm6DJsp.js} +1 -1
  156. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CnA0NrzZ.js → CpqQ1Kzn.js} +1 -1
  157. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4B-KCzX.js → D2nGpDRe.js} +1 -1
  158. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DGkLK5U1.js → D9iCMida.js} +1 -1
  159. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BofRWZRR.js → D9ykgMoY.js} +1 -1
  160. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DmxopI1J.js → DL2Ldur1.js} +1 -1
  161. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C30mlcqg.js → DPfltzjH.js} +1 -1
  162. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Vzk33B_K.js → DR8nis88.js} +2 -2
  163. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DI7hHRFL.js → DUliQN2b.js} +1 -1
  164. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4JcI4KD.js → DXlhR01x.js} +1 -1
  165. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bT1r9zLR.js → D_lyTybS.js} +1 -1
  166. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DZX00Y4g.js → DngoTTgh.js} +1 -1
  167. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzZX-COe.js → DqkmHtDC.js} +1 -1
  168. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7RN905-.js → DsDh8EYs.js} +1 -1
  169. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DLVjFsZ3.js → DypDmXgd.js} +1 -1
  170. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{iEWssX7S.js → IPYC-LnN.js} +1 -1
  171. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  172. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DaimHw_p.js → JpevfAFt.js} +1 -1
  173. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DY1XQ8fi.js → R8CEIRAd.js} +1 -1
  174. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dle-35c7.js → Zxy7qc-l.js} +2 -2
  175. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  176. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C_Usid8X.js → qtd3IeO4.js} +2 -2
  177. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzeYkLYB.js → ulBFON_C.js} +2 -2
  178. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cfqx1Qun.js → wQVh1CoA.js} +1 -1
  179. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/{app.D6-I5TpK.js → app.Dr7t0z2J.js} +2 -2
  180. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  181. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.m1gL8KXf.js → 0.RgBboRvH.js} +1 -1
  182. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{1.CgNOuw-d.js → 1.DG-KkbDf.js} +1 -1
  183. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  184. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
  185. claude_mpm/dashboard/static/svelte-build/index.html +9 -9
  186. claude_mpm/experimental/cli_enhancements.py +2 -1
  187. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  188. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  189. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +486 -0
  190. claude_mpm/hooks/claude_hooks/event_handlers.py +250 -11
  191. claude_mpm/hooks/claude_hooks/hook_handler.py +106 -89
  192. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  193. claude_mpm/hooks/claude_hooks/installer.py +69 -5
  194. claude_mpm/hooks/claude_hooks/response_tracking.py +3 -1
  195. claude_mpm/hooks/claude_hooks/services/connection_manager.py +20 -0
  196. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +14 -77
  197. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +30 -6
  198. claude_mpm/hooks/session_resume_hook.py +85 -1
  199. claude_mpm/init.py +1 -1
  200. claude_mpm/scripts/claude-hook-handler.sh +36 -10
  201. claude_mpm/scripts/start_activity_logging.py +0 -0
  202. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  203. claude_mpm/services/agents/cache_git_manager.py +1 -1
  204. claude_mpm/services/agents/deployment/agent_template_builder.py +8 -0
  205. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  206. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +3 -0
  207. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  208. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  209. claude_mpm/services/agents/sources/git_source_sync_service.py +7 -4
  210. claude_mpm/services/agents/startup_sync.py +5 -2
  211. claude_mpm/services/cli/__init__.py +3 -0
  212. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  213. claude_mpm/services/cli/session_resume_helper.py +10 -2
  214. claude_mpm/services/delegation_detector.py +175 -0
  215. claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
  216. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  217. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  218. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  219. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  220. claude_mpm/services/diagnostics/models.py +14 -1
  221. claude_mpm/services/event_log.py +325 -0
  222. claude_mpm/services/infrastructure/__init__.py +4 -0
  223. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  224. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  225. claude_mpm/services/monitor/daemon_manager.py +15 -4
  226. claude_mpm/services/monitor/management/lifecycle.py +8 -2
  227. claude_mpm/services/monitor/server.py +106 -16
  228. claude_mpm/services/pm_skills_deployer.py +261 -85
  229. claude_mpm/services/skills/git_skill_source_manager.py +75 -10
  230. claude_mpm/services/skills/selective_skill_deployer.py +177 -80
  231. claude_mpm/services/skills/skill_discovery_service.py +57 -3
  232. claude_mpm/services/socketio/handlers/hook.py +14 -7
  233. claude_mpm/services/socketio/server/main.py +12 -4
  234. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  235. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  236. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  237. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  238. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  239. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  240. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  241. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  242. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  243. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  244. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  245. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  246. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  247. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  248. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  249. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  250. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  251. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  252. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  253. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  254. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  255. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  256. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  257. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  258. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  259. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  260. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  261. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  262. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  263. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  264. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  265. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  266. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  267. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  268. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  269. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  270. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  271. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  272. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  273. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  274. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  275. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  276. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  277. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  278. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  279. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  280. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  281. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  282. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  283. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  284. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  285. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  286. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  287. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  288. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  289. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  290. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  291. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  292. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  293. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  294. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  295. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  296. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  297. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  298. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  299. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  300. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  301. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  302. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  303. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  304. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  305. claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
  306. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  307. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  308. claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
  309. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  310. claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
  311. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  312. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  313. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  314. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  315. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  316. claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
  317. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  318. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  319. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  320. claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
  321. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  322. claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
  323. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  324. claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
  325. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  326. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  327. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  328. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  329. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  330. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  331. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  332. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  333. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  334. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  335. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  336. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  337. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  338. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  339. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  340. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  341. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  342. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  343. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  344. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  345. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  346. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  347. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  348. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  349. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  350. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  351. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  352. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  353. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  354. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  355. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  356. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  357. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  358. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  359. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  360. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  361. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  362. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  363. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  364. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  365. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  366. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  367. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  368. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  369. claude_mpm/skills/skill_manager.py +4 -4
  370. claude_mpm/utils/agent_dependency_loader.py +103 -4
  371. claude_mpm/utils/robust_installer.py +45 -24
  372. claude_mpm-5.6.1.dist-info/METADATA +391 -0
  373. {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/RECORD +377 -166
  374. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +0 -1
  375. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +0 -1
  376. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +0 -1
  377. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +0 -24
  378. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +0 -1
  379. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +0 -1
  380. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +0 -323
  381. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +0 -1
  382. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +0 -1
  383. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  384. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  385. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  386. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  387. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  388. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  389. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  390. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  391. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  392. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  393. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  394. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  395. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  396. claude_mpm-5.4.55.dist-info/METADATA +0 -999
  397. {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/WHEEL +0 -0
  398. {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/entry_points.txt +0 -0
  399. {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/licenses/LICENSE +0 -0
  400. {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  401. {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,405 @@
1
+ """Work queue management for MPM Commander.
2
+
3
+ This module provides WorkQueue for managing work items within a project,
4
+ including priority-based execution and dependency resolution.
5
+ """
6
+
7
+ import logging
8
+ import uuid
9
+ from typing import List, Optional
10
+
11
+ from ..models.work import WorkItem, WorkPriority, WorkState
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class WorkQueue:
17
+ """Manages work items for a project.
18
+
19
+ Provides operations for adding, retrieving, and updating work items
20
+ with support for priority-based execution and linear dependencies.
21
+
22
+ Attributes:
23
+ project_id: ID of the project this queue belongs to
24
+ _items: Internal storage of work items by ID
25
+
26
+ Example:
27
+ >>> queue = WorkQueue("proj-123")
28
+ >>> work = queue.add("Implement feature X", priority=WorkPriority.HIGH)
29
+ >>> next_work = queue.get_next()
30
+ >>> queue.start(next_work.id)
31
+ >>> queue.complete(next_work.id, "Feature implemented")
32
+ """
33
+
34
+ def __init__(self, project_id: str):
35
+ """Initialize work queue for a project.
36
+
37
+ Args:
38
+ project_id: Unique project identifier
39
+ """
40
+ self.project_id = project_id
41
+ self._items: dict[str, WorkItem] = {}
42
+ logger.debug(f"Initialized WorkQueue for project {project_id}")
43
+
44
+ def add(
45
+ self,
46
+ content: str,
47
+ priority: WorkPriority = WorkPriority.MEDIUM,
48
+ depends_on: Optional[List[str]] = None,
49
+ ) -> WorkItem:
50
+ """Add work item to queue.
51
+
52
+ Args:
53
+ content: The task/message to execute
54
+ priority: Execution priority (default: MEDIUM)
55
+ depends_on: List of work item IDs that must complete first
56
+
57
+ Returns:
58
+ The created WorkItem
59
+
60
+ Example:
61
+ >>> work = queue.add("Fix bug #123", WorkPriority.HIGH)
62
+ >>> work.state
63
+ <WorkState.QUEUED: 'queued'>
64
+ """
65
+ work_id = f"work-{uuid.uuid4().hex[:8]}"
66
+
67
+ work = WorkItem(
68
+ id=work_id,
69
+ project_id=self.project_id,
70
+ content=content,
71
+ state=WorkState.QUEUED,
72
+ priority=priority,
73
+ depends_on=depends_on or [],
74
+ )
75
+
76
+ self._items[work_id] = work
77
+ logger.info(
78
+ f"Added work item {work_id} to project {self.project_id} "
79
+ f"with priority {priority.name}"
80
+ )
81
+
82
+ return work
83
+
84
+ def get_next(self) -> Optional[WorkItem]:
85
+ """Get next ready work item (dependencies satisfied, highest priority).
86
+
87
+ Returns work items in this order:
88
+ 1. QUEUED items with satisfied dependencies
89
+ 2. Ordered by priority (CRITICAL > HIGH > MEDIUM > LOW)
90
+ 3. Within same priority, oldest first (FIFO)
91
+
92
+ Returns:
93
+ Next executable work item, or None if queue empty or all blocked
94
+
95
+ Example:
96
+ >>> work = queue.get_next()
97
+ >>> if work:
98
+ ... print(f"Next: {work.content}")
99
+ """
100
+ # Get all completed work IDs for dependency checking
101
+ completed = self.completed_ids
102
+
103
+ # Filter for QUEUED items with satisfied dependencies
104
+ ready_items = [
105
+ item
106
+ for item in self._items.values()
107
+ if item.state == WorkState.QUEUED and item.can_start(completed)
108
+ ]
109
+
110
+ if not ready_items:
111
+ return None
112
+
113
+ # Sort by priority (descending), then by created_at (ascending)
114
+ ready_items.sort(key=lambda x: (-x.priority.value, x.created_at))
115
+
116
+ next_item = ready_items[0]
117
+ logger.debug(
118
+ f"Next work item for {self.project_id}: {next_item.id} "
119
+ f"(priority={next_item.priority.name})"
120
+ )
121
+
122
+ return next_item
123
+
124
+ def start(self, work_id: str) -> bool:
125
+ """Mark work as in progress.
126
+
127
+ Args:
128
+ work_id: Work item ID to start
129
+
130
+ Returns:
131
+ True if state changed, False if not found or invalid state
132
+
133
+ Example:
134
+ >>> queue.start("work-123")
135
+ True
136
+ """
137
+ item = self._items.get(work_id)
138
+ if not item:
139
+ logger.warning(f"Work item {work_id} not found")
140
+ return False
141
+
142
+ if item.state != WorkState.QUEUED:
143
+ logger.warning(
144
+ f"Work item {work_id} not QUEUED (current: {item.state.value})"
145
+ )
146
+ return False
147
+
148
+ from datetime import datetime, timezone
149
+
150
+ item.state = WorkState.IN_PROGRESS
151
+ item.started_at = datetime.now(timezone.utc)
152
+
153
+ logger.info(f"Started work item {work_id}")
154
+ return True
155
+
156
+ def complete(self, work_id: str, result: Optional[str] = None) -> bool:
157
+ """Mark work as completed.
158
+
159
+ Args:
160
+ work_id: Work item ID to complete
161
+ result: Optional result message
162
+
163
+ Returns:
164
+ True if state changed, False if not found or invalid state
165
+
166
+ Example:
167
+ >>> queue.complete("work-123", "Successfully implemented feature")
168
+ True
169
+ """
170
+ item = self._items.get(work_id)
171
+ if not item:
172
+ logger.warning(f"Work item {work_id} not found")
173
+ return False
174
+
175
+ if item.state not in (WorkState.IN_PROGRESS, WorkState.BLOCKED):
176
+ logger.warning(
177
+ f"Work item {work_id} not IN_PROGRESS or BLOCKED "
178
+ f"(current: {item.state.value})"
179
+ )
180
+ return False
181
+
182
+ from datetime import datetime, timezone
183
+
184
+ item.state = WorkState.COMPLETED
185
+ item.completed_at = datetime.now(timezone.utc)
186
+ item.result = result
187
+
188
+ logger.info(f"Completed work item {work_id}")
189
+ return True
190
+
191
+ def fail(self, work_id: str, error: str) -> bool:
192
+ """Mark work as failed.
193
+
194
+ Args:
195
+ work_id: Work item ID to fail
196
+ error: Error message
197
+
198
+ Returns:
199
+ True if state changed, False if not found or invalid state
200
+
201
+ Example:
202
+ >>> queue.fail("work-123", "Execution timeout")
203
+ True
204
+ """
205
+ item = self._items.get(work_id)
206
+ if not item:
207
+ logger.warning(f"Work item {work_id} not found")
208
+ return False
209
+
210
+ if item.state not in (WorkState.IN_PROGRESS, WorkState.BLOCKED):
211
+ logger.warning(
212
+ f"Work item {work_id} not IN_PROGRESS or BLOCKED "
213
+ f"(current: {item.state.value})"
214
+ )
215
+ return False
216
+
217
+ from datetime import datetime, timezone
218
+
219
+ item.state = WorkState.FAILED
220
+ item.completed_at = datetime.now(timezone.utc)
221
+ item.error = error
222
+
223
+ logger.error(f"Failed work item {work_id}: {error}")
224
+ return True
225
+
226
+ def block(self, work_id: str, reason: str) -> bool:
227
+ """Mark work as blocked (e.g., waiting for event resolution).
228
+
229
+ Args:
230
+ work_id: Work item ID to block
231
+ reason: Reason for blocking
232
+
233
+ Returns:
234
+ True if state changed, False if not found or invalid state
235
+
236
+ Example:
237
+ >>> queue.block("work-123", "Waiting for user approval")
238
+ True
239
+ """
240
+ item = self._items.get(work_id)
241
+ if not item:
242
+ logger.warning(f"Work item {work_id} not found")
243
+ return False
244
+
245
+ if item.state != WorkState.IN_PROGRESS:
246
+ logger.warning(
247
+ f"Work item {work_id} not IN_PROGRESS (current: {item.state.value})"
248
+ )
249
+ return False
250
+
251
+ item.state = WorkState.BLOCKED
252
+ item.metadata["block_reason"] = reason
253
+
254
+ logger.info(f"Blocked work item {work_id}: {reason}")
255
+ return True
256
+
257
+ def unblock(self, work_id: str) -> bool:
258
+ """Unblock work item (resume execution).
259
+
260
+ Args:
261
+ work_id: Work item ID to unblock
262
+
263
+ Returns:
264
+ True if state changed, False if not found or invalid state
265
+
266
+ Example:
267
+ >>> queue.unblock("work-123")
268
+ True
269
+ """
270
+ item = self._items.get(work_id)
271
+ if not item:
272
+ logger.warning(f"Work item {work_id} not found")
273
+ return False
274
+
275
+ if item.state != WorkState.BLOCKED:
276
+ logger.warning(
277
+ f"Work item {work_id} not BLOCKED (current: {item.state.value})"
278
+ )
279
+ return False
280
+
281
+ item.state = WorkState.IN_PROGRESS
282
+ if "block_reason" in item.metadata:
283
+ del item.metadata["block_reason"]
284
+
285
+ logger.info(f"Unblocked work item {work_id}")
286
+ return True
287
+
288
+ def cancel(self, work_id: str) -> bool:
289
+ """Cancel pending work.
290
+
291
+ Args:
292
+ work_id: Work item ID to cancel
293
+
294
+ Returns:
295
+ True if state changed, False if not found or invalid state
296
+
297
+ Example:
298
+ >>> queue.cancel("work-123")
299
+ True
300
+ """
301
+ item = self._items.get(work_id)
302
+ if not item:
303
+ logger.warning(f"Work item {work_id} not found")
304
+ return False
305
+
306
+ if item.state not in (WorkState.PENDING, WorkState.QUEUED, WorkState.BLOCKED):
307
+ logger.warning(
308
+ f"Cannot cancel work item {work_id} in state {item.state.value}"
309
+ )
310
+ return False
311
+
312
+ from datetime import datetime, timezone
313
+
314
+ item.state = WorkState.CANCELLED
315
+ item.completed_at = datetime.now(timezone.utc)
316
+
317
+ logger.info(f"Cancelled work item {work_id}")
318
+ return True
319
+
320
+ def get(self, work_id: str) -> Optional[WorkItem]:
321
+ """Get work item by ID.
322
+
323
+ Args:
324
+ work_id: Work item ID to retrieve
325
+
326
+ Returns:
327
+ WorkItem if found, None otherwise
328
+
329
+ Example:
330
+ >>> work = queue.get("work-123")
331
+ >>> if work:
332
+ ... print(work.content)
333
+ """
334
+ return self._items.get(work_id)
335
+
336
+ def list(self, state: Optional[WorkState] = None) -> List[WorkItem]:
337
+ """List work items, optionally filtered by state.
338
+
339
+ Args:
340
+ state: Optional state filter
341
+
342
+ Returns:
343
+ List of work items matching criteria (may be empty)
344
+
345
+ Example:
346
+ >>> queued = queue.list(WorkState.QUEUED)
347
+ >>> all_items = queue.list()
348
+ """
349
+ if state is None:
350
+ return list(self._items.values())
351
+
352
+ return [item for item in self._items.values() if item.state == state]
353
+
354
+ @property
355
+ def pending_count(self) -> int:
356
+ """Get count of pending/queued work items.
357
+
358
+ Returns:
359
+ Number of items in PENDING or QUEUED state
360
+
361
+ Example:
362
+ >>> count = queue.pending_count
363
+ """
364
+ return sum(
365
+ 1
366
+ for item in self._items.values()
367
+ if item.state in (WorkState.PENDING, WorkState.QUEUED)
368
+ )
369
+
370
+ @property
371
+ def completed_ids(self) -> set[str]:
372
+ """Get IDs of completed work items (for dependency checking).
373
+
374
+ Returns:
375
+ Set of work item IDs in COMPLETED state
376
+
377
+ Example:
378
+ >>> completed = queue.completed_ids
379
+ """
380
+ return {
381
+ item.id
382
+ for item in self._items.values()
383
+ if item.state == WorkState.COMPLETED
384
+ }
385
+
386
+ def load_items(self, items: List[WorkItem]) -> None:
387
+ """Load work items from persistence.
388
+
389
+ Args:
390
+ items: List of WorkItem instances to load
391
+
392
+ Example:
393
+ >>> queue.load_items(persisted_items)
394
+ """
395
+ for item in items:
396
+ if item.project_id != self.project_id:
397
+ logger.warning(
398
+ f"Skipping work item {item.id} - wrong project "
399
+ f"(expected {self.project_id}, got {item.project_id})"
400
+ )
401
+ continue
402
+
403
+ self._items[item.id] = item
404
+
405
+ logger.info(f"Loaded {len(items)} work items for project {self.project_id}")
@@ -0,0 +1,27 @@
1
+ """Event resolution workflow for MPM Commander.
2
+
3
+ This package provides event handling and notification capabilities for
4
+ managing blocking events that require user input.
5
+
6
+ Modules:
7
+ event_handler: Handles blocking events and session pause/resume
8
+ notifier: Sends notifications for events and resolutions
9
+
10
+ Classes:
11
+ EventHandler: Main event resolution coordinator
12
+ Notifier: Notification delivery system
13
+ NotifierConfig: Configuration for notification channels
14
+
15
+ Example:
16
+ >>> from claude_mpm.commander.workflow import EventHandler, Notifier
17
+ >>> from claude_mpm.commander.workflow import NotifierConfig
18
+ >>>
19
+ >>> notifier = Notifier(NotifierConfig(log_level="INFO"))
20
+ >>> handler = EventHandler(inbox, sessions)
21
+ >>> await handler.process_event(event)
22
+ """
23
+
24
+ from .event_handler import EventHandler
25
+ from .notifier import Notifier, NotifierConfig
26
+
27
+ __all__ = ["EventHandler", "Notifier", "NotifierConfig"]
@@ -0,0 +1,219 @@
1
+ """Event handler for pause/resume workflow on blocking events.
2
+
3
+ This module provides EventHandler which manages blocking events that require
4
+ user input and coordinates session pause/resume.
5
+ """
6
+
7
+ import logging
8
+ from typing import Dict, List, Optional
9
+
10
+ from ..inbox import Inbox
11
+ from ..models.events import BLOCKING_EVENTS, Event, EventStatus
12
+ from ..project_session import ProjectSession
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class EventHandler:
18
+ """Handles events requiring user resolution and session pause/resume.
19
+
20
+ This class detects blocking events (permission requests, errors, confirmations),
21
+ pauses the associated project session, and resumes execution after the event
22
+ is resolved with a user response.
23
+
24
+ Attributes:
25
+ inbox: Inbox for event management
26
+ session_manager: Dict mapping project_id to ProjectSession
27
+
28
+ Example:
29
+ >>> handler = EventHandler(inbox, sessions)
30
+ >>> await handler.process_event(event) # Pauses if blocking
31
+ >>> success = await handler.resolve_event(event_id, "User response")
32
+ """
33
+
34
+ def __init__(
35
+ self, inbox: Inbox, session_manager: Dict[str, ProjectSession]
36
+ ) -> None:
37
+ """Initialize event handler.
38
+
39
+ Args:
40
+ inbox: Inbox instance for event access
41
+ session_manager: Dict mapping project_id -> ProjectSession
42
+
43
+ Raises:
44
+ ValueError: If inbox or session_manager is None
45
+ """
46
+ if inbox is None:
47
+ raise ValueError("Inbox cannot be None")
48
+ if session_manager is None:
49
+ raise ValueError("Session manager cannot be None")
50
+
51
+ self.inbox = inbox
52
+ self.session_manager = session_manager
53
+ self._event_manager = inbox.events
54
+
55
+ logger.debug("EventHandler initialized")
56
+
57
+ async def process_event(self, event: Event) -> None:
58
+ """Process an event - pause session if blocking.
59
+
60
+ If the event is blocking (requires user input), pauses the associated
61
+ project session until the event is resolved.
62
+
63
+ Args:
64
+ event: Event to process
65
+
66
+ Example:
67
+ >>> await handler.process_event(error_event)
68
+ # Session paused for project
69
+ """
70
+ if not self.is_blocking(event):
71
+ logger.debug(
72
+ "Event %s is non-blocking (%s), no pause needed",
73
+ event.id,
74
+ event.type.value,
75
+ )
76
+ return
77
+
78
+ logger.info(
79
+ "Processing blocking event %s for project %s: %s",
80
+ event.id,
81
+ event.project_id,
82
+ event.title,
83
+ )
84
+
85
+ # Get the project session
86
+ session = self.session_manager.get(event.project_id)
87
+ if not session:
88
+ logger.warning(
89
+ "No session found for project %s, cannot pause", event.project_id
90
+ )
91
+ return
92
+
93
+ # Pause the session
94
+ try:
95
+ await session.pause(f"Event {event.id}: {event.title}")
96
+ logger.info(
97
+ "Paused session for project %s due to event %s",
98
+ event.project_id,
99
+ event.id,
100
+ )
101
+ except Exception as e:
102
+ logger.error(
103
+ "Failed to pause session for project %s: %s", event.project_id, e
104
+ )
105
+
106
+ async def resolve_event(self, event_id: str, response: str) -> bool:
107
+ """Resolve an event with user response and resume session if applicable.
108
+
109
+ Marks the event as resolved, sends the response to the runtime, and
110
+ resumes the project session if it was paused for this event.
111
+
112
+ Args:
113
+ event_id: ID of event to resolve
114
+ response: User's response to the event
115
+
116
+ Returns:
117
+ True if resolution successful and session resumed, False otherwise
118
+
119
+ Raises:
120
+ KeyError: If event_id not found
121
+
122
+ Example:
123
+ >>> success = await handler.resolve_event("evt_123", "Use authlib")
124
+ >>> if success:
125
+ ... print("Event resolved and session resumed")
126
+ """
127
+ # Get the event
128
+ event = self._event_manager.get(event_id)
129
+ if not event:
130
+ raise KeyError(f"Event not found: {event_id}")
131
+
132
+ logger.info("Resolving event %s: %s", event_id, response[:50])
133
+
134
+ # Check if event WAS blocking BEFORE resolving
135
+ was_blocking = self.is_blocking(event)
136
+
137
+ # Mark event as resolved
138
+ self._event_manager.respond(event_id, response)
139
+
140
+ # If event was NOT blocking, no need to resume
141
+ if not was_blocking:
142
+ logger.debug("Event %s was non-blocking, no resume needed", event_id)
143
+ return True
144
+
145
+ # Get the project session
146
+ session = self.session_manager.get(event.project_id)
147
+ if not session:
148
+ logger.warning(
149
+ "No session found for project %s, cannot resume", event.project_id
150
+ )
151
+ return False
152
+
153
+ # Check if session was paused for this event
154
+ if (
155
+ session.pause_reason
156
+ and event_id in session.pause_reason
157
+ and session.state.value == "paused"
158
+ ):
159
+ try:
160
+ # Send response to the runtime
161
+ if session.active_pane and session.executor:
162
+ await session.executor.send_message(session.active_pane, response)
163
+ logger.debug("Sent response to pane %s", session.active_pane)
164
+
165
+ # Resume the session
166
+ await session.resume()
167
+ logger.info(
168
+ "Resumed session for project %s after resolving event %s",
169
+ event.project_id,
170
+ event_id,
171
+ )
172
+ return True
173
+
174
+ except Exception as e:
175
+ logger.error(
176
+ "Failed to resume session for project %s: %s", event.project_id, e
177
+ )
178
+ return False
179
+ else:
180
+ logger.debug("Session not paused for event %s, no resume needed", event_id)
181
+ return True
182
+
183
+ async def get_pending_events(self, project_id: Optional[str] = None) -> List[Event]:
184
+ """Get unresolved events, optionally filtered by project.
185
+
186
+ Args:
187
+ project_id: If provided, only return events for this project
188
+
189
+ Returns:
190
+ List of pending events sorted by priority and time
191
+
192
+ Example:
193
+ >>> all_pending = await handler.get_pending_events()
194
+ >>> project_pending = await handler.get_pending_events("proj_123")
195
+ """
196
+ return self._event_manager.get_pending(project_id)
197
+
198
+ def is_blocking(self, event: Event) -> bool:
199
+ """Check if event type requires pausing execution.
200
+
201
+ Blocking event types:
202
+ - permission_request: Requires user approval
203
+ - error: Critical error blocking progress
204
+ - confirmation_request: User confirmation needed
205
+ - decision_needed: User must choose option
206
+ - approval: Destructive action needs approval
207
+
208
+ Args:
209
+ event: Event to check
210
+
211
+ Returns:
212
+ True if event blocks progress, False otherwise
213
+
214
+ Example:
215
+ >>> if handler.is_blocking(event):
216
+ ... await handler.process_event(event)
217
+ """
218
+ # Check if event type is blocking and status is pending
219
+ return event.type in BLOCKING_EVENTS and event.status == EventStatus.PENDING