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,865 @@
1
+ """Manages running Claude Code/MPM instances."""
2
+
3
+ import asyncio
4
+ import logging
5
+ import re
6
+ from datetime import datetime, timezone
7
+ from pathlib import Path
8
+ from typing import TYPE_CHECKING, Optional
9
+
10
+ from claude_mpm.commander.adapters import (
11
+ AdapterResponse,
12
+ ClaudeCodeAdapter,
13
+ ClaudeCodeCommunicationAdapter,
14
+ )
15
+ from claude_mpm.commander.frameworks.base import (
16
+ BaseFramework,
17
+ InstanceInfo,
18
+ RegisteredInstance,
19
+ )
20
+ from claude_mpm.commander.frameworks.claude_code import ClaudeCodeFramework
21
+ from claude_mpm.commander.frameworks.mpm import MPMFramework
22
+ from claude_mpm.commander.git.worktree_manager import WorktreeManager
23
+ from claude_mpm.commander.models.events import EventType
24
+ from claude_mpm.commander.tmux_orchestrator import TmuxOrchestrator
25
+
26
+ if TYPE_CHECKING:
27
+ from claude_mpm.commander.events.manager import EventManager
28
+ from claude_mpm.commander.persistence.state_store import StateStore
29
+
30
+ logger = logging.getLogger(__name__)
31
+
32
+
33
+ class InstanceNotFoundError(Exception):
34
+ """Raised when an instance is not found."""
35
+
36
+ def __init__(self, name: str):
37
+ super().__init__(f"Instance not found: {name}")
38
+ self.name = name
39
+
40
+
41
+ class FrameworkNotFoundError(Exception):
42
+ """Raised when a framework is not found or not available."""
43
+
44
+ def __init__(self, framework: str):
45
+ super().__init__(f"Framework not found or not available: {framework}")
46
+ self.framework = framework
47
+
48
+
49
+ class InstanceAlreadyExistsError(Exception):
50
+ """Raised when trying to start an instance that already exists."""
51
+
52
+ def __init__(self, name: str):
53
+ super().__init__(f"Instance already exists: {name}")
54
+ self.name = name
55
+
56
+
57
+ class InstanceManager:
58
+ """Manages lifecycle of Claude instances.
59
+
60
+ The InstanceManager coordinates framework selection, instance startup,
61
+ and tracking of running instances across the TmuxOrchestrator.
62
+
63
+ Attributes:
64
+ orchestrator: TmuxOrchestrator for managing tmux sessions/panes
65
+
66
+ Example:
67
+ >>> orchestrator = TmuxOrchestrator()
68
+ >>> manager = InstanceManager(orchestrator)
69
+ >>> frameworks = manager.list_frameworks()
70
+ >>> print(frameworks)
71
+ ['cc', 'mpm']
72
+ >>> instance = await manager.start_instance(
73
+ ... "myapp",
74
+ ... Path("/Users/user/myapp"),
75
+ ... framework="cc"
76
+ ... )
77
+ >>> print(instance.name, instance.framework)
78
+ myapp cc
79
+ """
80
+
81
+ def __init__(self, orchestrator: TmuxOrchestrator):
82
+ """Initialize the instance manager.
83
+
84
+ Args:
85
+ orchestrator: TmuxOrchestrator for managing tmux sessions/panes
86
+ """
87
+ self.orchestrator = orchestrator
88
+ self._instances: dict[str, InstanceInfo] = {}
89
+ self._frameworks = self._load_frameworks()
90
+ self._adapters: dict[str, ClaudeCodeCommunicationAdapter] = {}
91
+ self._event_manager: Optional[EventManager] = None
92
+ self._state_store: Optional[StateStore] = None
93
+
94
+ def set_event_manager(self, event_manager: "EventManager") -> None:
95
+ """Set the event manager for emitting instance events.
96
+
97
+ Args:
98
+ event_manager: EventManager instance for event emission
99
+
100
+ Example:
101
+ >>> manager = InstanceManager(orchestrator)
102
+ >>> manager.set_event_manager(event_manager)
103
+ """
104
+ self._event_manager = event_manager
105
+
106
+ def set_state_store(self, state_store: "StateStore") -> None:
107
+ """Set state store for persistence.
108
+
109
+ Args:
110
+ state_store: StateStore instance for persisting registered instances
111
+
112
+ Example:
113
+ >>> manager = InstanceManager(orchestrator)
114
+ >>> manager.set_state_store(state_store)
115
+ """
116
+ self._state_store = state_store
117
+
118
+ def _load_frameworks(self) -> dict[str, BaseFramework]:
119
+ """Load available frameworks.
120
+
121
+ Returns:
122
+ Dict mapping framework name to framework instance
123
+
124
+ Example:
125
+ >>> manager = InstanceManager(orchestrator)
126
+ >>> frameworks = manager._load_frameworks()
127
+ >>> print(frameworks.keys())
128
+ dict_keys(['cc', 'mpm'])
129
+ """
130
+ frameworks = {}
131
+ for framework_class in [ClaudeCodeFramework, MPMFramework]:
132
+ framework = framework_class()
133
+ if framework.is_available():
134
+ frameworks[framework.name] = framework
135
+ logger.info(
136
+ f"Loaded framework: {framework.name} ({framework.display_name})"
137
+ )
138
+ else:
139
+ logger.warning(
140
+ f"Framework not available: {framework.name} ({framework.display_name})"
141
+ )
142
+
143
+ return frameworks
144
+
145
+ def list_frameworks(self) -> list[str]:
146
+ """List available framework names.
147
+
148
+ Returns:
149
+ List of framework names (e.g., ["cc", "mpm"])
150
+
151
+ Example:
152
+ >>> manager = InstanceManager(orchestrator)
153
+ >>> frameworks = manager.list_frameworks()
154
+ >>> print(frameworks)
155
+ ['cc', 'mpm']
156
+ """
157
+ return list(self._frameworks.keys())
158
+
159
+ async def start_instance(
160
+ self, name: str, project_path: Path, framework: str = "cc"
161
+ ) -> InstanceInfo:
162
+ """Start a new instance.
163
+
164
+ Args:
165
+ name: Instance name (e.g., "myapp")
166
+ project_path: Path to project directory
167
+ framework: Framework to use ("cc" or "mpm")
168
+
169
+ Returns:
170
+ InstanceInfo with tmux session details
171
+
172
+ Raises:
173
+ FrameworkNotFoundError: If framework is not available
174
+ InstanceAlreadyExistsError: If instance already exists
175
+
176
+ Example:
177
+ >>> manager = InstanceManager(orchestrator)
178
+ >>> instance = await manager.start_instance(
179
+ ... "myapp",
180
+ ... Path("/Users/user/myapp"),
181
+ ... framework="cc"
182
+ ... )
183
+ >>> print(instance.name, instance.framework)
184
+ myapp cc
185
+ """
186
+ # Check if instance already exists
187
+ if name in self._instances:
188
+ raise InstanceAlreadyExistsError(name)
189
+
190
+ # Get framework
191
+ if framework not in self._frameworks:
192
+ raise FrameworkNotFoundError(framework)
193
+
194
+ framework_obj = self._frameworks[framework]
195
+
196
+ # Get git info
197
+ git_branch, git_status = framework_obj.get_git_info(project_path)
198
+
199
+ # Ensure tmux session exists
200
+ self.orchestrator.create_session()
201
+
202
+ # Create pane
203
+ pane_target = self.orchestrator.create_pane(name, str(project_path))
204
+
205
+ # Start framework in pane
206
+ startup_cmd = framework_obj.get_startup_command(project_path)
207
+ self.orchestrator.send_keys(pane_target, startup_cmd)
208
+
209
+ # Create communication adapter for the instance (only for Claude Code for now)
210
+ # Do this BEFORE creating InstanceInfo so we can set connected=True
211
+ has_adapter = False
212
+ if framework == "cc":
213
+ runtime_adapter = ClaudeCodeAdapter()
214
+ comm_adapter = ClaudeCodeCommunicationAdapter(
215
+ orchestrator=self.orchestrator,
216
+ pane_target=pane_target,
217
+ runtime_adapter=runtime_adapter,
218
+ )
219
+ self._adapters[name] = comm_adapter
220
+ has_adapter = True
221
+ logger.debug(f"Created communication adapter for instance '{name}'")
222
+
223
+ # Create instance info
224
+ instance = InstanceInfo(
225
+ name=name,
226
+ project_path=project_path,
227
+ framework=framework,
228
+ tmux_session=self.orchestrator.session_name,
229
+ pane_target=pane_target,
230
+ git_branch=git_branch,
231
+ git_status=git_status,
232
+ connected=has_adapter,
233
+ )
234
+
235
+ # Track instance
236
+ self._instances[name] = instance
237
+
238
+ logger.info(
239
+ f"Started instance '{name}' with framework '{framework}' at {project_path}"
240
+ )
241
+
242
+ # Emit starting event and start background ready detection
243
+ if self._event_manager:
244
+ event = self._event_manager.create(
245
+ project_id=name,
246
+ event_type=EventType.INSTANCE_STARTING,
247
+ title=f"Starting instance '{name}'",
248
+ content=f"Instance {name} is starting at {project_path}",
249
+ context={"instance_name": name, "working_dir": str(project_path)},
250
+ )
251
+ await self._event_manager.emit(event)
252
+
253
+ # Start background ready detection (always, not just with event_manager)
254
+ asyncio.create_task(self._detect_ready(name, instance))
255
+
256
+ return instance
257
+
258
+ async def _detect_ready(
259
+ self, name: str, instance_info: InstanceInfo, timeout: int = 30
260
+ ) -> None:
261
+ """Background task to detect when instance is ready.
262
+
263
+ Monitors the pane output for patterns indicating the instance
264
+ is ready to accept commands.
265
+
266
+ Args:
267
+ name: Instance name
268
+ instance_info: InstanceInfo with pane details
269
+ timeout: Maximum seconds to wait for ready state
270
+
271
+ Example:
272
+ >>> # Called internally by start_instance
273
+ >>> asyncio.create_task(self._detect_ready(name, instance))
274
+ """
275
+ # TIER 1: Startup markers (most reliable, appear at T+0-2s)
276
+ startup_patterns = [
277
+ r"Claude Code v[\d.]+", # Version marker
278
+ r"Claude Code", # Product identification
279
+ r"Opus 4\.5", # Model identifier
280
+ r"Claude Max|Claude Pro", # Tier indicator
281
+ ]
282
+
283
+ # TIER 2: Ready state indicators (appear at T+5-10s)
284
+ ready_patterns = [
285
+ r">\s*$", # CLI prompt (end of line)
286
+ r"^>\s*", # CLI prompt (start of line)
287
+ r"What can I.*help", # Specific greeting
288
+ r"How can I.*assist", # Specific greeting
289
+ r"(Human|User):\s*$", # Anthropic format
290
+ ]
291
+
292
+ # TIER 3: Secondary indicators (confirmation)
293
+ secondary_patterns = [
294
+ r"Ready for input", # Explicit ready
295
+ r"Tips for getting", # Claude CLI tips
296
+ r"Use /help", # Help hint
297
+ r"claudeMd", # CLAUDE.md loaded
298
+ r"Agent Memory", # Agent initialized
299
+ r"PM_INSTRUCTIONS", # MPM initialized
300
+ ]
301
+
302
+ # Combine all patterns (TIER 1 most reliable)
303
+ all_patterns = startup_patterns + ready_patterns + secondary_patterns
304
+
305
+ start_time = asyncio.get_event_loop().time()
306
+ check_count = 0
307
+
308
+ while asyncio.get_event_loop().time() - start_time < timeout:
309
+ elapsed = asyncio.get_event_loop().time() - start_time
310
+ check_count += 1
311
+
312
+ # Progress logging at key milestones
313
+ if elapsed > 10 and check_count == 11:
314
+ logger.info(
315
+ f"Ready detection for '{name}' still waiting after 10s... "
316
+ f"(Claude Code startup may be slow)"
317
+ )
318
+ elif elapsed > 20 and check_count == 21:
319
+ logger.info(
320
+ f"Ready detection for '{name}' still waiting after 20s... "
321
+ f"(system may be overloaded)"
322
+ )
323
+
324
+ await asyncio.sleep(1)
325
+ try:
326
+ # IMPROVED: Increased buffer from 50 to 100 lines
327
+ output = self.orchestrator.capture_output(
328
+ instance_info.pane_target, lines=100
329
+ )
330
+
331
+ if output:
332
+ # Check all patterns (added re.IGNORECASE flag)
333
+ # IMPROVED: Use MULTILINE | IGNORECASE flags
334
+ for pattern in all_patterns:
335
+ if re.search(pattern, output, re.MULTILINE | re.IGNORECASE):
336
+ # Instance is ready!
337
+ if name in self._instances:
338
+ self._instances[name].ready = True
339
+
340
+ # Emit ready event
341
+ if self._event_manager:
342
+ event = self._event_manager.create(
343
+ project_id=name,
344
+ event_type=EventType.INSTANCE_READY,
345
+ title=f"Instance '{name}' ready",
346
+ content=(
347
+ f"Instance {name} is ready for commands "
348
+ f"(detected in {elapsed:.1f}s)"
349
+ ),
350
+ context={
351
+ "instance_name": name,
352
+ "detection_time": elapsed,
353
+ "pattern_matched": pattern,
354
+ },
355
+ )
356
+ await self._event_manager.emit(event)
357
+
358
+ logger.info(
359
+ f"Instance '{name}' is ready "
360
+ f"(detected in {elapsed:.1f}s via pattern: {pattern})"
361
+ )
362
+ return
363
+
364
+ except Exception as e:
365
+ logger.debug(
366
+ f"Error checking ready state for '{name}': {e}. "
367
+ f"Elapsed: {elapsed:.1f}s"
368
+ )
369
+
370
+ # Timeout - mark as ready anyway since instance might still work
371
+ logger.warning(
372
+ f"Instance '{name}' ready detection timed out after {timeout}s. "
373
+ f"Instance may still be functional. Check logs for issues."
374
+ )
375
+
376
+ if name in self._instances:
377
+ self._instances[name].ready = True
378
+
379
+ if self._event_manager:
380
+ event = self._event_manager.create(
381
+ project_id=name,
382
+ event_type=EventType.INSTANCE_READY,
383
+ title=f"Instance '{name}' started",
384
+ content=(
385
+ f"Instance {name} startup timeout. "
386
+ f"May be ready, or startup may be slow/blocked. "
387
+ f"Check instance manually if issues occur."
388
+ ),
389
+ context={
390
+ "instance_name": name,
391
+ "timeout": True,
392
+ "timeout_seconds": timeout,
393
+ },
394
+ )
395
+ await self._event_manager.emit(event)
396
+
397
+ async def wait_for_ready(self, name: str, timeout: int = 30) -> bool:
398
+ """Wait for an instance to be ready.
399
+
400
+ Polls the instance's ready flag until it becomes True or timeout.
401
+
402
+ Args:
403
+ name: Instance name
404
+ timeout: Maximum seconds to wait
405
+
406
+ Returns:
407
+ True if instance is ready, False if timeout
408
+
409
+ Example:
410
+ >>> manager = InstanceManager(orchestrator)
411
+ >>> await manager.start_instance("myapp", "/path/to/app", "mpm")
412
+ >>> if await manager.wait_for_ready("myapp", timeout=30):
413
+ ... print("Ready!")
414
+ """
415
+ start_time = asyncio.get_event_loop().time()
416
+ while asyncio.get_event_loop().time() - start_time < timeout:
417
+ inst = self._instances.get(name)
418
+ if inst and inst.ready:
419
+ return True
420
+ await asyncio.sleep(0.5)
421
+ return False
422
+
423
+ async def stop_instance(self, name: str) -> bool:
424
+ """Stop an instance.
425
+
426
+ Args:
427
+ name: Instance name
428
+
429
+ Returns:
430
+ True if instance was stopped
431
+
432
+ Raises:
433
+ InstanceNotFoundError: If instance not found
434
+
435
+ Example:
436
+ >>> manager = InstanceManager(orchestrator)
437
+ >>> await manager.stop_instance("myapp")
438
+ True
439
+ """
440
+ if name not in self._instances:
441
+ raise InstanceNotFoundError(name)
442
+
443
+ instance = self._instances[name]
444
+
445
+ # Kill tmux pane
446
+ self.orchestrator.kill_pane(instance.pane_target)
447
+
448
+ # Remove adapter if exists
449
+ if name in self._adapters:
450
+ del self._adapters[name]
451
+ instance.connected = False
452
+ logger.debug(f"Removed adapter for instance '{name}'")
453
+
454
+ # Remove from tracking
455
+ del self._instances[name]
456
+
457
+ logger.info(f"Stopped instance '{name}'")
458
+
459
+ return True
460
+
461
+ def get_instance(self, name: str) -> Optional[InstanceInfo]:
462
+ """Get instance by name.
463
+
464
+ Args:
465
+ name: Instance name
466
+
467
+ Returns:
468
+ InstanceInfo if found, None otherwise
469
+
470
+ Example:
471
+ >>> manager = InstanceManager(orchestrator)
472
+ >>> instance = manager.get_instance("myapp")
473
+ >>> if instance:
474
+ ... print(instance.name, instance.framework)
475
+ myapp cc
476
+ """
477
+ return self._instances.get(name)
478
+
479
+ def list_instances(self) -> list[InstanceInfo]:
480
+ """List all running instances.
481
+
482
+ Returns:
483
+ List of InstanceInfo for all running instances
484
+
485
+ Example:
486
+ >>> manager = InstanceManager(orchestrator)
487
+ >>> instances = manager.list_instances()
488
+ >>> for instance in instances:
489
+ ... print(instance.name, instance.framework)
490
+ myapp cc
491
+ otherapp mpm
492
+ """
493
+ return list(self._instances.values())
494
+
495
+ async def send_to_instance(
496
+ self, name: str, message: str, wait_for_response: bool = False
497
+ ) -> Optional[AdapterResponse]:
498
+ """Send a message/command to an instance.
499
+
500
+ Args:
501
+ name: Instance name
502
+ message: Message to send
503
+ wait_for_response: If True, wait for and return response
504
+
505
+ Returns:
506
+ AdapterResponse if wait_for_response=True, None otherwise
507
+
508
+ Raises:
509
+ InstanceNotFoundError: If instance not found
510
+
511
+ Example:
512
+ >>> manager = InstanceManager(orchestrator)
513
+ >>> # Send without waiting
514
+ >>> await manager.send_to_instance("myapp", "Fix the bug in main.py")
515
+ >>> # Send and wait for response
516
+ >>> response = await manager.send_to_instance(
517
+ ... "myapp", "Fix the bug", wait_for_response=True
518
+ ... )
519
+ >>> print(response.content)
520
+ """
521
+ if name not in self._instances:
522
+ raise InstanceNotFoundError(name)
523
+
524
+ instance = self._instances[name]
525
+
526
+ # Use adapter if available
527
+ if name in self._adapters:
528
+ adapter = self._adapters[name]
529
+ await adapter.send(message)
530
+ logger.info(
531
+ f"Sent message via adapter to instance '{name}': {message[:50]}..."
532
+ )
533
+
534
+ if wait_for_response:
535
+ return await adapter.receive()
536
+ return None
537
+
538
+ # Fallback to direct tmux if no adapter
539
+ self.orchestrator.send_keys(instance.pane_target, message)
540
+ logger.info(f"Sent message to instance '{name}': {message[:50]}...")
541
+ return None
542
+
543
+ def get_adapter(self, name: str) -> Optional[ClaudeCodeCommunicationAdapter]:
544
+ """Get communication adapter for an instance.
545
+
546
+ Args:
547
+ name: Instance name
548
+
549
+ Returns:
550
+ ClaudeCodeCommunicationAdapter if exists, None otherwise
551
+
552
+ Example:
553
+ >>> manager = InstanceManager(orchestrator)
554
+ >>> adapter = manager.get_adapter("myapp")
555
+ >>> if adapter:
556
+ ... await adapter.send("Create a new file")
557
+ ... async for chunk in adapter.stream_response():
558
+ ... print(chunk, end='')
559
+ """
560
+ return self._adapters.get(name)
561
+
562
+ async def rename_instance(self, old_name: str, new_name: str) -> bool:
563
+ """Rename an instance.
564
+
565
+ Args:
566
+ old_name: Current instance name
567
+ new_name: New instance name
568
+
569
+ Returns:
570
+ True if renamed successfully
571
+
572
+ Raises:
573
+ InstanceNotFoundError: If old_name doesn't exist
574
+ InstanceAlreadyExistsError: If new_name already exists
575
+
576
+ Example:
577
+ >>> manager = InstanceManager(orchestrator)
578
+ >>> await manager.rename_instance("myapp", "myapp-v2")
579
+ True
580
+ """
581
+ # Validate old_name exists
582
+ if old_name not in self._instances:
583
+ raise InstanceNotFoundError(old_name)
584
+
585
+ # Validate new_name doesn't exist
586
+ if new_name in self._instances:
587
+ raise InstanceAlreadyExistsError(new_name)
588
+
589
+ # Get instance and update name
590
+ instance = self._instances[old_name]
591
+ instance.name = new_name
592
+
593
+ # Update _instances dict (remove old key, add new)
594
+ del self._instances[old_name]
595
+ self._instances[new_name] = instance
596
+
597
+ # Update _adapters dict if exists
598
+ if old_name in self._adapters:
599
+ adapter = self._adapters[old_name]
600
+ del self._adapters[old_name]
601
+ self._adapters[new_name] = adapter
602
+ logger.debug(f"Moved adapter from '{old_name}' to '{new_name}'")
603
+
604
+ logger.info(f"Renamed instance from '{old_name}' to '{new_name}'")
605
+
606
+ return True
607
+
608
+ async def close_instance(self, name: str, merge: bool = True) -> tuple[bool, str]:
609
+ """Close instance: stop tmux, optionally merge worktree, cleanup.
610
+
611
+ Args:
612
+ name: Instance name to close
613
+ merge: Whether to merge worktree to main (default True)
614
+
615
+ Returns:
616
+ Tuple of (success, message)
617
+
618
+ Example:
619
+ >>> manager = InstanceManager(orchestrator)
620
+ >>> success, msg = await manager.close_instance("myapp")
621
+ >>> print(success, msg)
622
+ True Closed 'myapp'
623
+ """
624
+ registered = (
625
+ self._state_store.get_registered_instance(name)
626
+ if self._state_store
627
+ else None
628
+ )
629
+
630
+ # Stop the tmux session
631
+ try:
632
+ await self.stop_instance(name)
633
+ except InstanceNotFoundError:
634
+ # Instance not running, but may still have worktree to clean up
635
+ pass
636
+
637
+ # Merge and cleanup worktree if enabled
638
+ if registered and registered.use_worktree and registered.worktree_path:
639
+ wt_manager = WorktreeManager(Path(registered.path))
640
+ if merge:
641
+ success, msg = wt_manager.merge_to_main(name, delete_after=True)
642
+ if not success:
643
+ return False, msg
644
+ else:
645
+ wt_manager.remove(name, force=True)
646
+
647
+ # Remove from registry
648
+ if self._state_store:
649
+ self._state_store.unregister_instance(name)
650
+
651
+ return True, f"Closed '{name}'"
652
+
653
+ async def disconnect_instance(self, name: str) -> bool:
654
+ """Disconnect from an instance without closing it.
655
+
656
+ The instance keeps running but we stop communication.
657
+ Removes the adapter while keeping the instance tracked.
658
+
659
+ Args:
660
+ name: Instance name to disconnect from
661
+
662
+ Returns:
663
+ True if disconnected successfully
664
+
665
+ Raises:
666
+ InstanceNotFoundError: If instance not found
667
+
668
+ Example:
669
+ >>> manager = InstanceManager(orchestrator)
670
+ >>> await manager.disconnect_instance("myapp")
671
+ True
672
+ >>> # Instance still running, but no adapter connection
673
+ >>> adapter = manager.get_adapter("myapp")
674
+ >>> print(adapter)
675
+ None
676
+ """
677
+ # Validate instance exists
678
+ if name not in self._instances:
679
+ raise InstanceNotFoundError(name)
680
+
681
+ instance = self._instances[name]
682
+
683
+ # Remove adapter if exists (but keep instance)
684
+ if name in self._adapters:
685
+ # Could add cleanup here if adapter has resources to close
686
+ del self._adapters[name]
687
+ instance.connected = False
688
+ logger.info(f"Disconnected from instance '{name}' (instance still running)")
689
+ else:
690
+ logger.debug(f"No adapter to disconnect for instance '{name}'")
691
+
692
+ return True
693
+
694
+ async def register_instance(
695
+ self,
696
+ path: str,
697
+ framework: str,
698
+ name: str,
699
+ use_worktree: bool = True,
700
+ branch: Optional[str] = None,
701
+ ) -> InstanceInfo:
702
+ """Register an instance and start it.
703
+
704
+ Registers the instance in persistent storage so it can be started
705
+ by name in future sessions, then starts the instance.
706
+
707
+ Args:
708
+ path: Project directory path
709
+ framework: Framework to use ("cc" or "mpm")
710
+ name: Instance name (also worktree name if enabled)
711
+ use_worktree: Create isolated git worktree (default True)
712
+ branch: Branch for worktree (default: session-{name})
713
+
714
+ Returns:
715
+ InstanceInfo with tmux session details
716
+
717
+ Raises:
718
+ FrameworkNotFoundError: If framework is not available
719
+ InstanceAlreadyExistsError: If instance already exists
720
+
721
+ Example:
722
+ >>> manager = InstanceManager(orchestrator)
723
+ >>> manager.set_state_store(state_store)
724
+ >>> instance = await manager.register_instance(
725
+ ... "/Users/user/myapp", "cc", "myapp"
726
+ ... )
727
+ >>> print(instance.name, instance.framework)
728
+ myapp cc
729
+ """
730
+ project_path = Path(path).expanduser().resolve()
731
+
732
+ worktree_path = None
733
+ worktree_branch = None
734
+ working_path = project_path
735
+
736
+ # Create worktree if enabled and it's a git repo
737
+ if use_worktree and (project_path / ".git").exists():
738
+ try:
739
+ wt_manager = WorktreeManager(project_path)
740
+ wt_info = wt_manager.create(name, branch)
741
+ worktree_path = str(wt_info.path)
742
+ worktree_branch = wt_info.branch
743
+ working_path = wt_info.path
744
+ logger.info(
745
+ f"Created worktree for '{name}' at {worktree_path} "
746
+ f"on branch {worktree_branch}"
747
+ )
748
+ except Exception as e:
749
+ logger.warning(f"Could not create worktree: {e}. Using original path.")
750
+
751
+ # Create registered instance with worktree info
752
+ registered = RegisteredInstance(
753
+ name=name,
754
+ path=str(project_path),
755
+ framework=framework,
756
+ registered_at=datetime.now(timezone.utc).isoformat(),
757
+ worktree_path=worktree_path,
758
+ worktree_branch=worktree_branch,
759
+ use_worktree=use_worktree and worktree_path is not None,
760
+ )
761
+
762
+ # Save to persistent storage
763
+ if self._state_store:
764
+ self._state_store.register_instance(registered)
765
+
766
+ # Start the instance in worktree path
767
+ return await self.start_instance(name, working_path, framework)
768
+
769
+ async def start_by_name(self, name: str) -> Optional[InstanceInfo]:
770
+ """Start a previously registered instance by name.
771
+
772
+ Looks up the instance registration and starts it with the
773
+ stored path and framework. Uses the worktree path if configured.
774
+
775
+ Args:
776
+ name: Instance name (must have been previously registered)
777
+
778
+ Returns:
779
+ InstanceInfo if instance was found and started, None if not registered
780
+
781
+ Example:
782
+ >>> manager = InstanceManager(orchestrator)
783
+ >>> manager.set_state_store(state_store)
784
+ >>> # After previous registration
785
+ >>> instance = await manager.start_by_name("myapp")
786
+ >>> if instance:
787
+ ... print(instance.name, instance.project_path)
788
+ myapp /Users/user/myapp
789
+ """
790
+ if not self._state_store:
791
+ return None
792
+
793
+ registered = self._state_store.get_registered_instance(name)
794
+ if not registered:
795
+ return None
796
+
797
+ # Use working_path which respects worktree setting
798
+ return await self.start_instance(
799
+ registered.name,
800
+ Path(registered.working_path),
801
+ registered.framework,
802
+ )
803
+
804
+ def list_registered(self) -> dict[str, RegisteredInstance]:
805
+ """List all registered instances.
806
+
807
+ Returns:
808
+ Dict mapping instance name to RegisteredInstance
809
+
810
+ Example:
811
+ >>> manager = InstanceManager(orchestrator)
812
+ >>> manager.set_state_store(state_store)
813
+ >>> registered = manager.list_registered()
814
+ >>> for name, instance in registered.items():
815
+ ... print(f"{name}: {instance.path} ({instance.framework})")
816
+ myapp: /Users/user/myapp (cc)
817
+ """
818
+ if not self._state_store:
819
+ return {}
820
+ return self._state_store.load_instances()
821
+
822
+ def unregister(self, name: str) -> bool:
823
+ """Unregister an instance.
824
+
825
+ Removes the instance from persistent storage. Does not stop
826
+ any running instance with this name.
827
+
828
+ Args:
829
+ name: Instance name to unregister
830
+
831
+ Returns:
832
+ True if instance was found and unregistered, False if not found
833
+
834
+ Example:
835
+ >>> manager = InstanceManager(orchestrator)
836
+ >>> manager.set_state_store(state_store)
837
+ >>> success = manager.unregister("myapp")
838
+ >>> print(success)
839
+ True
840
+ """
841
+ if not self._state_store:
842
+ return False
843
+ return self._state_store.unregister_instance(name)
844
+
845
+ def list_worktrees(self, path: str) -> list:
846
+ """List worktrees for a project.
847
+
848
+ Args:
849
+ path: Project directory path
850
+
851
+ Returns:
852
+ List of WorktreeInfo for all worktrees associated with the project
853
+
854
+ Example:
855
+ >>> manager = InstanceManager(orchestrator)
856
+ >>> worktrees = manager.list_worktrees("/Users/user/myapp")
857
+ >>> for wt in worktrees:
858
+ ... print(f"{wt.name}: {wt.path} ({wt.branch})")
859
+ myapp: /Users/user/.worktrees-myapp/myapp (session-myapp)
860
+ """
861
+ try:
862
+ wt_manager = WorktreeManager(Path(path))
863
+ return wt_manager.list()
864
+ except Exception:
865
+ return []