claude-mpm 5.4.48__py3-none-any.whl → 5.6.34__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 (467) 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 +119 -689
  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 +216 -0
  13. claude_mpm/cli/commands/configure.py +620 -21
  14. claude_mpm/cli/commands/configure_agent_display.py +3 -1
  15. claude_mpm/cli/commands/hook_errors.py +60 -60
  16. claude_mpm/cli/commands/monitor.py +2 -2
  17. claude_mpm/cli/commands/mpm_init/core.py +15 -8
  18. claude_mpm/cli/commands/profile.py +9 -10
  19. claude_mpm/cli/commands/run.py +35 -3
  20. claude_mpm/cli/commands/skill_source.py +51 -2
  21. claude_mpm/cli/commands/skills.py +171 -17
  22. claude_mpm/cli/executor.py +120 -16
  23. claude_mpm/cli/interactive/__init__.py +10 -0
  24. claude_mpm/cli/interactive/agent_wizard.py +30 -50
  25. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  26. claude_mpm/cli/interactive/skill_selector.py +481 -0
  27. claude_mpm/cli/parsers/base_parser.py +76 -1
  28. claude_mpm/cli/parsers/commander_parser.py +116 -0
  29. claude_mpm/cli/parsers/profile_parser.py +0 -1
  30. claude_mpm/cli/parsers/run_parser.py +10 -0
  31. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  32. claude_mpm/cli/parsers/skills_parser.py +5 -0
  33. claude_mpm/cli/startup.py +544 -511
  34. claude_mpm/cli/startup_display.py +74 -6
  35. claude_mpm/cli/startup_logging.py +2 -2
  36. claude_mpm/cli/utils.py +7 -3
  37. claude_mpm/commander/__init__.py +78 -0
  38. claude_mpm/commander/adapters/__init__.py +60 -0
  39. claude_mpm/commander/adapters/auggie.py +260 -0
  40. claude_mpm/commander/adapters/base.py +288 -0
  41. claude_mpm/commander/adapters/claude_code.py +392 -0
  42. claude_mpm/commander/adapters/codex.py +237 -0
  43. claude_mpm/commander/adapters/communication.py +366 -0
  44. claude_mpm/commander/adapters/example_usage.py +310 -0
  45. claude_mpm/commander/adapters/mpm.py +389 -0
  46. claude_mpm/commander/adapters/registry.py +204 -0
  47. claude_mpm/commander/api/__init__.py +16 -0
  48. claude_mpm/commander/api/app.py +121 -0
  49. claude_mpm/commander/api/errors.py +133 -0
  50. claude_mpm/commander/api/routes/__init__.py +8 -0
  51. claude_mpm/commander/api/routes/events.py +184 -0
  52. claude_mpm/commander/api/routes/inbox.py +171 -0
  53. claude_mpm/commander/api/routes/messages.py +148 -0
  54. claude_mpm/commander/api/routes/projects.py +271 -0
  55. claude_mpm/commander/api/routes/sessions.py +226 -0
  56. claude_mpm/commander/api/routes/work.py +296 -0
  57. claude_mpm/commander/api/schemas.py +186 -0
  58. claude_mpm/commander/chat/__init__.py +7 -0
  59. claude_mpm/commander/chat/cli.py +146 -0
  60. claude_mpm/commander/chat/commands.py +96 -0
  61. claude_mpm/commander/chat/repl.py +310 -0
  62. claude_mpm/commander/config.py +51 -0
  63. claude_mpm/commander/config_loader.py +115 -0
  64. claude_mpm/commander/core/__init__.py +10 -0
  65. claude_mpm/commander/core/block_manager.py +325 -0
  66. claude_mpm/commander/core/response_manager.py +323 -0
  67. claude_mpm/commander/daemon.py +603 -0
  68. claude_mpm/commander/env_loader.py +59 -0
  69. claude_mpm/commander/events/__init__.py +26 -0
  70. claude_mpm/commander/events/manager.py +332 -0
  71. claude_mpm/commander/frameworks/__init__.py +12 -0
  72. claude_mpm/commander/frameworks/base.py +146 -0
  73. claude_mpm/commander/frameworks/claude_code.py +58 -0
  74. claude_mpm/commander/frameworks/mpm.py +62 -0
  75. claude_mpm/commander/inbox/__init__.py +16 -0
  76. claude_mpm/commander/inbox/dedup.py +128 -0
  77. claude_mpm/commander/inbox/inbox.py +224 -0
  78. claude_mpm/commander/inbox/models.py +70 -0
  79. claude_mpm/commander/instance_manager.py +450 -0
  80. claude_mpm/commander/llm/__init__.py +6 -0
  81. claude_mpm/commander/llm/openrouter_client.py +167 -0
  82. claude_mpm/commander/llm/summarizer.py +70 -0
  83. claude_mpm/commander/memory/__init__.py +45 -0
  84. claude_mpm/commander/memory/compression.py +347 -0
  85. claude_mpm/commander/memory/embeddings.py +230 -0
  86. claude_mpm/commander/memory/entities.py +310 -0
  87. claude_mpm/commander/memory/example_usage.py +290 -0
  88. claude_mpm/commander/memory/integration.py +325 -0
  89. claude_mpm/commander/memory/search.py +381 -0
  90. claude_mpm/commander/memory/store.py +657 -0
  91. claude_mpm/commander/models/__init__.py +18 -0
  92. claude_mpm/commander/models/events.py +121 -0
  93. claude_mpm/commander/models/project.py +162 -0
  94. claude_mpm/commander/models/work.py +214 -0
  95. claude_mpm/commander/parsing/__init__.py +20 -0
  96. claude_mpm/commander/parsing/extractor.py +132 -0
  97. claude_mpm/commander/parsing/output_parser.py +270 -0
  98. claude_mpm/commander/parsing/patterns.py +100 -0
  99. claude_mpm/commander/persistence/__init__.py +11 -0
  100. claude_mpm/commander/persistence/event_store.py +274 -0
  101. claude_mpm/commander/persistence/state_store.py +309 -0
  102. claude_mpm/commander/persistence/work_store.py +164 -0
  103. claude_mpm/commander/polling/__init__.py +13 -0
  104. claude_mpm/commander/polling/event_detector.py +104 -0
  105. claude_mpm/commander/polling/output_buffer.py +49 -0
  106. claude_mpm/commander/polling/output_poller.py +153 -0
  107. claude_mpm/commander/project_session.py +268 -0
  108. claude_mpm/commander/proxy/__init__.py +12 -0
  109. claude_mpm/commander/proxy/formatter.py +89 -0
  110. claude_mpm/commander/proxy/output_handler.py +191 -0
  111. claude_mpm/commander/proxy/relay.py +155 -0
  112. claude_mpm/commander/registry.py +410 -0
  113. claude_mpm/commander/runtime/__init__.py +10 -0
  114. claude_mpm/commander/runtime/executor.py +191 -0
  115. claude_mpm/commander/runtime/monitor.py +346 -0
  116. claude_mpm/commander/session/__init__.py +6 -0
  117. claude_mpm/commander/session/context.py +81 -0
  118. claude_mpm/commander/session/manager.py +59 -0
  119. claude_mpm/commander/tmux_orchestrator.py +361 -0
  120. claude_mpm/commander/web/__init__.py +1 -0
  121. claude_mpm/commander/work/__init__.py +30 -0
  122. claude_mpm/commander/work/executor.py +207 -0
  123. claude_mpm/commander/work/queue.py +405 -0
  124. claude_mpm/commander/workflow/__init__.py +27 -0
  125. claude_mpm/commander/workflow/event_handler.py +241 -0
  126. claude_mpm/commander/workflow/notifier.py +146 -0
  127. claude_mpm/commands/mpm-config.md +8 -0
  128. claude_mpm/commands/mpm-doctor.md +8 -0
  129. claude_mpm/commands/mpm-help.md +8 -0
  130. claude_mpm/commands/mpm-init.md +8 -0
  131. claude_mpm/commands/mpm-monitor.md +8 -0
  132. claude_mpm/commands/mpm-organize.md +8 -0
  133. claude_mpm/commands/mpm-postmortem.md +8 -0
  134. claude_mpm/commands/mpm-session-resume.md +9 -1
  135. claude_mpm/commands/mpm-status.md +8 -0
  136. claude_mpm/commands/mpm-ticket-view.md +8 -0
  137. claude_mpm/commands/mpm-version.md +8 -0
  138. claude_mpm/commands/mpm.md +8 -0
  139. claude_mpm/config/agent_presets.py +8 -7
  140. claude_mpm/config/skill_sources.py +16 -0
  141. claude_mpm/constants.py +1 -0
  142. claude_mpm/core/claude_runner.py +154 -2
  143. claude_mpm/core/config.py +35 -22
  144. claude_mpm/core/config_constants.py +74 -9
  145. claude_mpm/core/constants.py +56 -12
  146. claude_mpm/core/hook_manager.py +51 -3
  147. claude_mpm/core/interactive_session.py +12 -11
  148. claude_mpm/core/logger.py +26 -9
  149. claude_mpm/core/logging_utils.py +39 -13
  150. claude_mpm/core/network_config.py +148 -0
  151. claude_mpm/core/oneshot_session.py +7 -6
  152. claude_mpm/core/optimized_startup.py +3 -1
  153. claude_mpm/core/output_style_manager.py +66 -18
  154. claude_mpm/core/shared/config_loader.py +3 -1
  155. claude_mpm/core/socketio_pool.py +47 -15
  156. claude_mpm/core/unified_config.py +54 -8
  157. claude_mpm/core/unified_paths.py +95 -90
  158. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  159. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  160. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
  161. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
  162. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
  163. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
  164. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
  165. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
  166. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
  167. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
  168. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  169. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
  170. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uj46x2Wr.js → BSNlmTZj.js} +1 -1
  171. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
  172. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
  173. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
  174. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
  175. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  176. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  177. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
  178. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
  179. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
  180. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
  181. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
  182. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
  183. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
  184. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
  185. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  186. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
  187. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
  188. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
  189. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  190. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
  191. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  192. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
  193. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
  194. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
  195. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
  196. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
  197. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{N4qtv3Hx.js → DR8nis88.js} +2 -2
  198. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
  199. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  200. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
  201. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
  202. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
  203. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
  204. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
  205. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
  206. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  207. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
  208. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  209. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
  210. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DjhvlsAc.js → NqQ1dWOy.js} +1 -1
  211. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
  212. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
  213. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  214. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
  215. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
  216. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
  217. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
  218. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  219. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.CAGBuiOw.js → 0.RgBboRvH.js} +1 -1
  220. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
  221. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  222. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
  223. claude_mpm/dashboard/static/svelte-build/index.html +11 -11
  224. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  225. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  226. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  227. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  228. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  229. claude_mpm/experimental/cli_enhancements.py +2 -1
  230. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  231. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  232. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  233. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  234. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  235. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  236. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  237. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
  238. claude_mpm/hooks/claude_hooks/event_handlers.py +527 -136
  239. claude_mpm/hooks/claude_hooks/hook_handler.py +170 -104
  240. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  241. claude_mpm/hooks/claude_hooks/installer.py +206 -36
  242. claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
  243. claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
  244. claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
  245. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  246. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  247. claude_mpm/hooks/claude_hooks/services/__pycache__/container.cpython-311.pyc +0 -0
  248. claude_mpm/hooks/claude_hooks/services/__pycache__/protocols.cpython-311.pyc +0 -0
  249. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  250. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  251. claude_mpm/hooks/claude_hooks/services/connection_manager.py +41 -26
  252. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
  253. claude_mpm/hooks/claude_hooks/services/container.py +310 -0
  254. claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
  255. claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
  256. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
  257. claude_mpm/hooks/session_resume_hook.py +89 -1
  258. claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
  259. claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
  260. claude_mpm/init.py +215 -2
  261. claude_mpm/scripts/claude-hook-handler.sh +46 -19
  262. claude_mpm/scripts/start_activity_logging.py +0 -0
  263. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  264. claude_mpm/services/agents/agent_selection_service.py +2 -2
  265. claude_mpm/services/agents/cache_git_manager.py +1 -1
  266. claude_mpm/services/agents/deployment/agent_discovery_service.py +3 -1
  267. claude_mpm/services/agents/deployment/agent_format_converter.py +8 -6
  268. claude_mpm/services/agents/deployment/agent_template_builder.py +14 -4
  269. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  270. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +4 -4
  271. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +4 -1
  272. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  273. claude_mpm/services/agents/git_source_manager.py +6 -2
  274. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  275. claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
  276. claude_mpm/services/agents/sources/git_source_sync_service.py +10 -5
  277. claude_mpm/services/agents/startup_sync.py +5 -2
  278. claude_mpm/services/cli/__init__.py +3 -0
  279. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  280. claude_mpm/services/cli/session_resume_helper.py +10 -2
  281. claude_mpm/services/command_deployment_service.py +44 -26
  282. claude_mpm/services/delegation_detector.py +175 -0
  283. claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
  284. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  285. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  286. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  287. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  288. claude_mpm/services/diagnostics/models.py +14 -1
  289. claude_mpm/services/event_log.py +325 -0
  290. claude_mpm/services/hook_installer_service.py +77 -8
  291. claude_mpm/services/infrastructure/__init__.py +4 -0
  292. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  293. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  294. claude_mpm/services/monitor/daemon_manager.py +15 -4
  295. claude_mpm/services/monitor/management/lifecycle.py +8 -3
  296. claude_mpm/services/monitor/server.py +106 -16
  297. claude_mpm/services/pm_skills_deployer.py +267 -94
  298. claude_mpm/services/profile_manager.py +10 -4
  299. claude_mpm/services/skills/git_skill_source_manager.py +192 -29
  300. claude_mpm/services/skills/selective_skill_deployer.py +211 -46
  301. claude_mpm/services/skills/skill_discovery_service.py +74 -4
  302. claude_mpm/services/skills_deployer.py +188 -67
  303. claude_mpm/services/socketio/handlers/hook.py +14 -7
  304. claude_mpm/services/socketio/server/main.py +12 -4
  305. claude_mpm/skills/__init__.py +2 -1
  306. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  307. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  308. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  309. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  310. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  311. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  312. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  313. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  314. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  315. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  316. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  317. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  318. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  319. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  320. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  321. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  322. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  323. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  324. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  325. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  326. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  327. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  328. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  329. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  330. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  331. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  332. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  333. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  334. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  335. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  336. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  337. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  338. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  339. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  340. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  341. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  342. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  343. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  344. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  345. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  346. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  347. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  348. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  349. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  350. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  351. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  352. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  353. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  354. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  355. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  356. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  357. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  358. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  359. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  360. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  361. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  362. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  363. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  364. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  365. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  366. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  367. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  368. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  369. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  370. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  371. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  372. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  373. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  374. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  375. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  376. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  377. claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
  378. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  379. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  380. claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
  381. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  382. claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
  383. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  384. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  385. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  386. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  387. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  388. claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
  389. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  390. claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
  391. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  392. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  393. claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
  394. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  395. claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
  396. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  397. claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
  398. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  399. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  400. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  401. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  402. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  403. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  404. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  405. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  406. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  407. claude_mpm/skills/bundled/security-scanning.md +112 -0
  408. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  409. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  410. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  411. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  412. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  413. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  414. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  415. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  416. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  417. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  418. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  419. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  420. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  421. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  422. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  423. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  424. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  425. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  426. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  427. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  428. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  429. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  430. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  431. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  432. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  433. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  434. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  435. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  436. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  437. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  438. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  439. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  440. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  441. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  442. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  443. claude_mpm/skills/registry.py +295 -90
  444. claude_mpm/skills/skill_manager.py +29 -23
  445. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  446. claude_mpm/utils/agent_dependency_loader.py +103 -4
  447. claude_mpm/utils/robust_installer.py +45 -24
  448. claude_mpm-5.6.34.dist-info/METADATA +393 -0
  449. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/RECORD +453 -151
  450. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +0 -1
  451. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +0 -1
  452. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +0 -1
  453. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +0 -1
  454. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +0 -1
  455. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +0 -2
  456. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +0 -2
  457. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +0 -1
  458. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +0 -1
  459. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +0 -10
  460. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  461. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  462. claude_mpm-5.4.48.dist-info/METADATA +0 -999
  463. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/WHEEL +0 -0
  464. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/entry_points.txt +0 -0
  465. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE +0 -0
  466. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  467. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,450 @@
1
+ """Manages running Claude Code/MPM instances."""
2
+
3
+ import logging
4
+ from pathlib import Path
5
+ from typing import Optional
6
+
7
+ from claude_mpm.commander.adapters import (
8
+ AdapterResponse,
9
+ ClaudeCodeAdapter,
10
+ ClaudeCodeCommunicationAdapter,
11
+ )
12
+ from claude_mpm.commander.frameworks.base import BaseFramework, InstanceInfo
13
+ from claude_mpm.commander.frameworks.claude_code import ClaudeCodeFramework
14
+ from claude_mpm.commander.frameworks.mpm import MPMFramework
15
+ from claude_mpm.commander.tmux_orchestrator import TmuxOrchestrator
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class InstanceNotFoundError(Exception):
21
+ """Raised when an instance is not found."""
22
+
23
+ def __init__(self, name: str):
24
+ super().__init__(f"Instance not found: {name}")
25
+ self.name = name
26
+
27
+
28
+ class FrameworkNotFoundError(Exception):
29
+ """Raised when a framework is not found or not available."""
30
+
31
+ def __init__(self, framework: str):
32
+ super().__init__(f"Framework not found or not available: {framework}")
33
+ self.framework = framework
34
+
35
+
36
+ class InstanceAlreadyExistsError(Exception):
37
+ """Raised when trying to start an instance that already exists."""
38
+
39
+ def __init__(self, name: str):
40
+ super().__init__(f"Instance already exists: {name}")
41
+ self.name = name
42
+
43
+
44
+ class InstanceManager:
45
+ """Manages lifecycle of Claude instances.
46
+
47
+ The InstanceManager coordinates framework selection, instance startup,
48
+ and tracking of running instances across the TmuxOrchestrator.
49
+
50
+ Attributes:
51
+ orchestrator: TmuxOrchestrator for managing tmux sessions/panes
52
+
53
+ Example:
54
+ >>> orchestrator = TmuxOrchestrator()
55
+ >>> manager = InstanceManager(orchestrator)
56
+ >>> frameworks = manager.list_frameworks()
57
+ >>> print(frameworks)
58
+ ['cc', 'mpm']
59
+ >>> instance = await manager.start_instance(
60
+ ... "myapp",
61
+ ... Path("/Users/user/myapp"),
62
+ ... framework="cc"
63
+ ... )
64
+ >>> print(instance.name, instance.framework)
65
+ myapp cc
66
+ """
67
+
68
+ def __init__(self, orchestrator: TmuxOrchestrator):
69
+ """Initialize the instance manager.
70
+
71
+ Args:
72
+ orchestrator: TmuxOrchestrator for managing tmux sessions/panes
73
+ """
74
+ self.orchestrator = orchestrator
75
+ self._instances: dict[str, InstanceInfo] = {}
76
+ self._frameworks = self._load_frameworks()
77
+ self._adapters: dict[str, ClaudeCodeCommunicationAdapter] = {}
78
+
79
+ def _load_frameworks(self) -> dict[str, BaseFramework]:
80
+ """Load available frameworks.
81
+
82
+ Returns:
83
+ Dict mapping framework name to framework instance
84
+
85
+ Example:
86
+ >>> manager = InstanceManager(orchestrator)
87
+ >>> frameworks = manager._load_frameworks()
88
+ >>> print(frameworks.keys())
89
+ dict_keys(['cc', 'mpm'])
90
+ """
91
+ frameworks = {}
92
+ for framework_class in [ClaudeCodeFramework, MPMFramework]:
93
+ framework = framework_class()
94
+ if framework.is_available():
95
+ frameworks[framework.name] = framework
96
+ logger.info(
97
+ f"Loaded framework: {framework.name} ({framework.display_name})"
98
+ )
99
+ else:
100
+ logger.warning(
101
+ f"Framework not available: {framework.name} ({framework.display_name})"
102
+ )
103
+
104
+ return frameworks
105
+
106
+ def list_frameworks(self) -> list[str]:
107
+ """List available framework names.
108
+
109
+ Returns:
110
+ List of framework names (e.g., ["cc", "mpm"])
111
+
112
+ Example:
113
+ >>> manager = InstanceManager(orchestrator)
114
+ >>> frameworks = manager.list_frameworks()
115
+ >>> print(frameworks)
116
+ ['cc', 'mpm']
117
+ """
118
+ return list(self._frameworks.keys())
119
+
120
+ async def start_instance(
121
+ self, name: str, project_path: Path, framework: str = "cc"
122
+ ) -> InstanceInfo:
123
+ """Start a new instance.
124
+
125
+ Args:
126
+ name: Instance name (e.g., "myapp")
127
+ project_path: Path to project directory
128
+ framework: Framework to use ("cc" or "mpm")
129
+
130
+ Returns:
131
+ InstanceInfo with tmux session details
132
+
133
+ Raises:
134
+ FrameworkNotFoundError: If framework is not available
135
+ InstanceAlreadyExistsError: If instance already exists
136
+
137
+ Example:
138
+ >>> manager = InstanceManager(orchestrator)
139
+ >>> instance = await manager.start_instance(
140
+ ... "myapp",
141
+ ... Path("/Users/user/myapp"),
142
+ ... framework="cc"
143
+ ... )
144
+ >>> print(instance.name, instance.framework)
145
+ myapp cc
146
+ """
147
+ # Check if instance already exists
148
+ if name in self._instances:
149
+ raise InstanceAlreadyExistsError(name)
150
+
151
+ # Get framework
152
+ if framework not in self._frameworks:
153
+ raise FrameworkNotFoundError(framework)
154
+
155
+ framework_obj = self._frameworks[framework]
156
+
157
+ # Get git info
158
+ git_branch, git_status = framework_obj.get_git_info(project_path)
159
+
160
+ # Ensure tmux session exists
161
+ self.orchestrator.create_session()
162
+
163
+ # Create pane
164
+ pane_target = self.orchestrator.create_pane(name, str(project_path))
165
+
166
+ # Start framework in pane
167
+ startup_cmd = framework_obj.get_startup_command(project_path)
168
+ self.orchestrator.send_keys(pane_target, startup_cmd)
169
+
170
+ # Create communication adapter for the instance (only for Claude Code for now)
171
+ # Do this BEFORE creating InstanceInfo so we can set connected=True
172
+ has_adapter = False
173
+ if framework == "cc":
174
+ runtime_adapter = ClaudeCodeAdapter()
175
+ comm_adapter = ClaudeCodeCommunicationAdapter(
176
+ orchestrator=self.orchestrator,
177
+ pane_target=pane_target,
178
+ runtime_adapter=runtime_adapter,
179
+ )
180
+ self._adapters[name] = comm_adapter
181
+ has_adapter = True
182
+ logger.debug(f"Created communication adapter for instance '{name}'")
183
+
184
+ # Create instance info
185
+ instance = InstanceInfo(
186
+ name=name,
187
+ project_path=project_path,
188
+ framework=framework,
189
+ tmux_session=self.orchestrator.session_name,
190
+ pane_target=pane_target,
191
+ git_branch=git_branch,
192
+ git_status=git_status,
193
+ connected=has_adapter,
194
+ )
195
+
196
+ # Track instance
197
+ self._instances[name] = instance
198
+
199
+ logger.info(
200
+ f"Started instance '{name}' with framework '{framework}' at {project_path}"
201
+ )
202
+
203
+ return instance
204
+
205
+ async def stop_instance(self, name: str) -> bool:
206
+ """Stop an instance.
207
+
208
+ Args:
209
+ name: Instance name
210
+
211
+ Returns:
212
+ True if instance was stopped
213
+
214
+ Raises:
215
+ InstanceNotFoundError: If instance not found
216
+
217
+ Example:
218
+ >>> manager = InstanceManager(orchestrator)
219
+ >>> await manager.stop_instance("myapp")
220
+ True
221
+ """
222
+ if name not in self._instances:
223
+ raise InstanceNotFoundError(name)
224
+
225
+ instance = self._instances[name]
226
+
227
+ # Kill tmux pane
228
+ self.orchestrator.kill_pane(instance.pane_target)
229
+
230
+ # Remove adapter if exists
231
+ if name in self._adapters:
232
+ del self._adapters[name]
233
+ instance.connected = False
234
+ logger.debug(f"Removed adapter for instance '{name}'")
235
+
236
+ # Remove from tracking
237
+ del self._instances[name]
238
+
239
+ logger.info(f"Stopped instance '{name}'")
240
+
241
+ return True
242
+
243
+ def get_instance(self, name: str) -> Optional[InstanceInfo]:
244
+ """Get instance by name.
245
+
246
+ Args:
247
+ name: Instance name
248
+
249
+ Returns:
250
+ InstanceInfo if found, None otherwise
251
+
252
+ Example:
253
+ >>> manager = InstanceManager(orchestrator)
254
+ >>> instance = manager.get_instance("myapp")
255
+ >>> if instance:
256
+ ... print(instance.name, instance.framework)
257
+ myapp cc
258
+ """
259
+ return self._instances.get(name)
260
+
261
+ def list_instances(self) -> list[InstanceInfo]:
262
+ """List all running instances.
263
+
264
+ Returns:
265
+ List of InstanceInfo for all running instances
266
+
267
+ Example:
268
+ >>> manager = InstanceManager(orchestrator)
269
+ >>> instances = manager.list_instances()
270
+ >>> for instance in instances:
271
+ ... print(instance.name, instance.framework)
272
+ myapp cc
273
+ otherapp mpm
274
+ """
275
+ return list(self._instances.values())
276
+
277
+ async def send_to_instance(
278
+ self, name: str, message: str, wait_for_response: bool = False
279
+ ) -> Optional[AdapterResponse]:
280
+ """Send a message/command to an instance.
281
+
282
+ Args:
283
+ name: Instance name
284
+ message: Message to send
285
+ wait_for_response: If True, wait for and return response
286
+
287
+ Returns:
288
+ AdapterResponse if wait_for_response=True, None otherwise
289
+
290
+ Raises:
291
+ InstanceNotFoundError: If instance not found
292
+
293
+ Example:
294
+ >>> manager = InstanceManager(orchestrator)
295
+ >>> # Send without waiting
296
+ >>> await manager.send_to_instance("myapp", "Fix the bug in main.py")
297
+ >>> # Send and wait for response
298
+ >>> response = await manager.send_to_instance(
299
+ ... "myapp", "Fix the bug", wait_for_response=True
300
+ ... )
301
+ >>> print(response.content)
302
+ """
303
+ if name not in self._instances:
304
+ raise InstanceNotFoundError(name)
305
+
306
+ instance = self._instances[name]
307
+
308
+ # Use adapter if available
309
+ if name in self._adapters:
310
+ adapter = self._adapters[name]
311
+ await adapter.send(message)
312
+ logger.info(
313
+ f"Sent message via adapter to instance '{name}': {message[:50]}..."
314
+ )
315
+
316
+ if wait_for_response:
317
+ return await adapter.receive()
318
+ return None
319
+
320
+ # Fallback to direct tmux if no adapter
321
+ self.orchestrator.send_keys(instance.pane_target, message)
322
+ logger.info(f"Sent message to instance '{name}': {message[:50]}...")
323
+ return None
324
+
325
+ def get_adapter(self, name: str) -> Optional[ClaudeCodeCommunicationAdapter]:
326
+ """Get communication adapter for an instance.
327
+
328
+ Args:
329
+ name: Instance name
330
+
331
+ Returns:
332
+ ClaudeCodeCommunicationAdapter if exists, None otherwise
333
+
334
+ Example:
335
+ >>> manager = InstanceManager(orchestrator)
336
+ >>> adapter = manager.get_adapter("myapp")
337
+ >>> if adapter:
338
+ ... await adapter.send("Create a new file")
339
+ ... async for chunk in adapter.stream_response():
340
+ ... print(chunk, end='')
341
+ """
342
+ return self._adapters.get(name)
343
+
344
+ async def rename_instance(self, old_name: str, new_name: str) -> bool:
345
+ """Rename an instance.
346
+
347
+ Args:
348
+ old_name: Current instance name
349
+ new_name: New instance name
350
+
351
+ Returns:
352
+ True if renamed successfully
353
+
354
+ Raises:
355
+ InstanceNotFoundError: If old_name doesn't exist
356
+ InstanceAlreadyExistsError: If new_name already exists
357
+
358
+ Example:
359
+ >>> manager = InstanceManager(orchestrator)
360
+ >>> await manager.rename_instance("myapp", "myapp-v2")
361
+ True
362
+ """
363
+ # Validate old_name exists
364
+ if old_name not in self._instances:
365
+ raise InstanceNotFoundError(old_name)
366
+
367
+ # Validate new_name doesn't exist
368
+ if new_name in self._instances:
369
+ raise InstanceAlreadyExistsError(new_name)
370
+
371
+ # Get instance and update name
372
+ instance = self._instances[old_name]
373
+ instance.name = new_name
374
+
375
+ # Update _instances dict (remove old key, add new)
376
+ del self._instances[old_name]
377
+ self._instances[new_name] = instance
378
+
379
+ # Update _adapters dict if exists
380
+ if old_name in self._adapters:
381
+ adapter = self._adapters[old_name]
382
+ del self._adapters[old_name]
383
+ self._adapters[new_name] = adapter
384
+ logger.debug(f"Moved adapter from '{old_name}' to '{new_name}'")
385
+
386
+ logger.info(f"Renamed instance from '{old_name}' to '{new_name}'")
387
+
388
+ return True
389
+
390
+ async def close_instance(self, name: str) -> bool:
391
+ """Close and remove an instance.
392
+
393
+ Alias for stop_instance that provides clearer semantics for closing.
394
+
395
+ Args:
396
+ name: Instance name to close
397
+
398
+ Returns:
399
+ True if closed successfully
400
+
401
+ Raises:
402
+ InstanceNotFoundError: If instance not found
403
+
404
+ Example:
405
+ >>> manager = InstanceManager(orchestrator)
406
+ >>> await manager.close_instance("myapp")
407
+ True
408
+ """
409
+ return await self.stop_instance(name)
410
+
411
+ async def disconnect_instance(self, name: str) -> bool:
412
+ """Disconnect from an instance without closing it.
413
+
414
+ The instance keeps running but we stop communication.
415
+ Removes the adapter while keeping the instance tracked.
416
+
417
+ Args:
418
+ name: Instance name to disconnect from
419
+
420
+ Returns:
421
+ True if disconnected successfully
422
+
423
+ Raises:
424
+ InstanceNotFoundError: If instance not found
425
+
426
+ Example:
427
+ >>> manager = InstanceManager(orchestrator)
428
+ >>> await manager.disconnect_instance("myapp")
429
+ True
430
+ >>> # Instance still running, but no adapter connection
431
+ >>> adapter = manager.get_adapter("myapp")
432
+ >>> print(adapter)
433
+ None
434
+ """
435
+ # Validate instance exists
436
+ if name not in self._instances:
437
+ raise InstanceNotFoundError(name)
438
+
439
+ instance = self._instances[name]
440
+
441
+ # Remove adapter if exists (but keep instance)
442
+ if name in self._adapters:
443
+ # Could add cleanup here if adapter has resources to close
444
+ del self._adapters[name]
445
+ instance.connected = False
446
+ logger.info(f"Disconnected from instance '{name}' (instance still running)")
447
+ else:
448
+ logger.debug(f"No adapter to disconnect for instance '{name}'")
449
+
450
+ return True
@@ -0,0 +1,6 @@
1
+ """LLM integration for Commander chat interface and summarization."""
2
+
3
+ from .openrouter_client import OpenRouterClient, OpenRouterConfig
4
+ from .summarizer import OutputSummarizer
5
+
6
+ __all__ = ["OpenRouterClient", "OpenRouterConfig", "OutputSummarizer"]
@@ -0,0 +1,167 @@
1
+ """OpenRouter LLM client for Commander chat interface."""
2
+
3
+ import os
4
+ from dataclasses import dataclass
5
+ from typing import AsyncIterator
6
+
7
+ import httpx
8
+
9
+
10
+ @dataclass
11
+ class OpenRouterConfig:
12
+ """Configuration for OpenRouter API client."""
13
+
14
+ api_key: str | None = None # Falls back to OPENROUTER_API_KEY env
15
+ model: str = "anthropic/claude-3.5-sonnet"
16
+ base_url: str = "https://openrouter.ai/api/v1"
17
+ max_tokens: int = 4096
18
+ temperature: float = 0.7
19
+
20
+
21
+ class OpenRouterClient:
22
+ """Async client for OpenRouter API."""
23
+
24
+ def __init__(self, config: OpenRouterConfig | None = None):
25
+ """Initialize client with config.
26
+
27
+ Args:
28
+ config: OpenRouter configuration. Defaults to OpenRouterConfig().
29
+
30
+ Raises:
31
+ ValueError: If OPENROUTER_API_KEY is not set.
32
+ """
33
+ self.config = config or OpenRouterConfig()
34
+ self._api_key = self.config.api_key or os.getenv("OPENROUTER_API_KEY")
35
+ if not self._api_key:
36
+ raise ValueError("OPENROUTER_API_KEY not set")
37
+
38
+ async def chat(self, messages: list[dict], system: str | None = None) -> str:
39
+ """Send chat completion request, return response content.
40
+
41
+ Args:
42
+ messages: List of message dicts with 'role' and 'content' keys.
43
+ system: Optional system prompt.
44
+
45
+ Returns:
46
+ Response content from the model.
47
+
48
+ Raises:
49
+ httpx.HTTPStatusError: If API request fails.
50
+ """
51
+ async with httpx.AsyncClient() as client:
52
+ # Build request payload
53
+ payload = {
54
+ "model": self.config.model,
55
+ "messages": messages,
56
+ "max_tokens": self.config.max_tokens,
57
+ "temperature": self.config.temperature,
58
+ }
59
+
60
+ if system:
61
+ payload["system"] = system
62
+
63
+ # Send request
64
+ response = await client.post(
65
+ f"{self.config.base_url}/chat/completions",
66
+ headers={
67
+ "Authorization": f"Bearer {self._api_key}",
68
+ "Content-Type": "application/json",
69
+ },
70
+ json=payload,
71
+ timeout=30.0,
72
+ )
73
+ response.raise_for_status()
74
+
75
+ # Extract content from response
76
+ data = response.json()
77
+ return data["choices"][0]["message"]["content"]
78
+
79
+ async def chat_stream(
80
+ self, messages: list[dict], system: str | None = None
81
+ ) -> AsyncIterator[str]:
82
+ """Stream chat completion, yield chunks.
83
+
84
+ Args:
85
+ messages: List of message dicts with 'role' and 'content' keys.
86
+ system: Optional system prompt.
87
+
88
+ Yields:
89
+ Content chunks from the streaming response.
90
+
91
+ Raises:
92
+ httpx.HTTPStatusError: If API request fails.
93
+ """
94
+ async with httpx.AsyncClient() as client:
95
+ # Build request payload
96
+ payload = {
97
+ "model": self.config.model,
98
+ "messages": messages,
99
+ "max_tokens": self.config.max_tokens,
100
+ "temperature": self.config.temperature,
101
+ "stream": True,
102
+ }
103
+
104
+ if system:
105
+ payload["system"] = system
106
+
107
+ # Send streaming request
108
+ async with client.stream(
109
+ "POST",
110
+ f"{self.config.base_url}/chat/completions",
111
+ headers={
112
+ "Authorization": f"Bearer {self._api_key}",
113
+ "Content-Type": "application/json",
114
+ },
115
+ json=payload,
116
+ timeout=30.0,
117
+ ) as response:
118
+ response.raise_for_status()
119
+
120
+ # Parse SSE stream
121
+ async for line in response.aiter_lines():
122
+ if not line.strip():
123
+ continue
124
+
125
+ # SSE format: "data: {json}"
126
+ if line.startswith("data: "):
127
+ data_str = line[6:] # Remove "data: " prefix
128
+
129
+ # Check for stream end
130
+ if data_str == "[DONE]":
131
+ break
132
+
133
+ # Parse JSON chunk
134
+ import json
135
+
136
+ try:
137
+ data = json.loads(data_str)
138
+ delta = data["choices"][0].get("delta", {})
139
+ if "content" in delta:
140
+ yield delta["content"]
141
+ except (json.JSONDecodeError, KeyError, IndexError):
142
+ # Skip malformed chunks
143
+ continue
144
+
145
+ async def summarize(self, text: str, max_length: int = 500) -> str:
146
+ """Summarize text to max_length characters.
147
+
148
+ Args:
149
+ text: Text to summarize.
150
+ max_length: Maximum length of summary in characters.
151
+
152
+ Returns:
153
+ Summarized text.
154
+ """
155
+ messages = [
156
+ {
157
+ "role": "user",
158
+ "content": f"Summarize the following text in approximately {max_length} characters or less:\n\n{text}",
159
+ }
160
+ ]
161
+
162
+ system = (
163
+ "You are a concise summarization assistant. "
164
+ "Provide clear, accurate summaries that capture the key points."
165
+ )
166
+
167
+ return await self.chat(messages, system=system)
@@ -0,0 +1,70 @@
1
+ """Summarizes Claude Code output for user display."""
2
+
3
+ from .openrouter_client import OpenRouterClient
4
+
5
+
6
+ class OutputSummarizer:
7
+ """Summarizes long output from Claude Code instances."""
8
+
9
+ def __init__(self, client: OpenRouterClient):
10
+ """Initialize with OpenRouter client.
11
+
12
+ Args:
13
+ client: OpenRouterClient instance for LLM requests.
14
+ """
15
+ self.client = client
16
+
17
+ async def summarize(self, output: str, context: str | None = None) -> str:
18
+ """Summarize Claude Code output.
19
+
20
+ Args:
21
+ output: Raw output from Claude Code.
22
+ context: Optional context about what was requested.
23
+
24
+ Returns:
25
+ Concise summary of the output.
26
+ """
27
+ # Build summarization prompt
28
+ if context:
29
+ prompt = f"""Summarize the following Claude Code output.
30
+
31
+ Context: {context}
32
+
33
+ Output:
34
+ {output}
35
+
36
+ Provide a concise summary (2-3 sentences) that captures:
37
+ 1. What action was taken
38
+ 2. The key result or outcome
39
+ 3. Any important warnings or next steps
40
+
41
+ Summary:"""
42
+ else:
43
+ prompt = f"""Summarize the following Claude Code output in 2-3 sentences.
44
+
45
+ Output:
46
+ {output}
47
+
48
+ Summary:"""
49
+
50
+ messages = [{"role": "user", "content": prompt}]
51
+
52
+ system = (
53
+ "You are a technical summarization assistant. "
54
+ "Provide clear, concise summaries of command output and code execution results. "
55
+ "Focus on actionable information and key outcomes."
56
+ )
57
+
58
+ return await self.client.chat(messages, system=system)
59
+
60
+ def needs_summarization(self, output: str, threshold: int = 500) -> bool:
61
+ """Check if output is long enough to warrant summarization.
62
+
63
+ Args:
64
+ output: Output text to check.
65
+ threshold: Character count threshold for summarization.
66
+
67
+ Returns:
68
+ True if output exceeds threshold, False otherwise.
69
+ """
70
+ return len(output) > threshold