claude-mpm 5.4.41__py3-none-any.whl → 5.6.23__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 (460) 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/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 +182 -32
  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 +2 -3
  33. claude_mpm/cli/startup.py +527 -506
  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 +35 -11
  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 +63 -18
  154. claude_mpm/core/shared/config_loader.py +3 -1
  155. claude_mpm/core/socketio_pool.py +13 -5
  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 +305 -87
  239. claude_mpm/hooks/claude_hooks/hook_handler.py +106 -89
  240. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  241. claude_mpm/hooks/claude_hooks/installer.py +116 -8
  242. claude_mpm/hooks/claude_hooks/memory_integration.py +51 -31
  243. claude_mpm/hooks/claude_hooks/response_tracking.py +42 -59
  244. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  245. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  246. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  247. claude_mpm/hooks/claude_hooks/services/connection_manager.py +39 -24
  248. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +36 -103
  249. claude_mpm/hooks/claude_hooks/services/state_manager.py +23 -36
  250. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +73 -75
  251. claude_mpm/hooks/kuzu_memory_hook.py +5 -5
  252. claude_mpm/hooks/session_resume_hook.py +89 -1
  253. claude_mpm/hooks/templates/pre_tool_use_template.py +10 -2
  254. claude_mpm/init.py +215 -2
  255. claude_mpm/scripts/claude-hook-handler.sh +43 -16
  256. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  257. claude_mpm/services/agents/agent_selection_service.py +2 -2
  258. claude_mpm/services/agents/cache_git_manager.py +1 -1
  259. claude_mpm/services/agents/deployment/agent_discovery_service.py +3 -1
  260. claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
  261. claude_mpm/services/agents/deployment/agent_template_builder.py +37 -17
  262. claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
  263. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  264. claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
  265. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +36 -8
  266. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +50 -26
  267. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  268. claude_mpm/services/agents/git_source_manager.py +21 -2
  269. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  270. claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
  271. claude_mpm/services/agents/sources/git_source_sync_service.py +116 -5
  272. claude_mpm/services/agents/startup_sync.py +5 -2
  273. claude_mpm/services/cli/__init__.py +3 -0
  274. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  275. claude_mpm/services/cli/session_resume_helper.py +10 -2
  276. claude_mpm/services/delegation_detector.py +175 -0
  277. claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
  278. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  279. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  280. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  281. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  282. claude_mpm/services/diagnostics/models.py +14 -1
  283. claude_mpm/services/event_log.py +325 -0
  284. claude_mpm/services/infrastructure/__init__.py +4 -0
  285. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  286. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  287. claude_mpm/services/monitor/daemon_manager.py +15 -4
  288. claude_mpm/services/monitor/management/lifecycle.py +8 -3
  289. claude_mpm/services/monitor/server.py +106 -16
  290. claude_mpm/services/pm_skills_deployer.py +302 -94
  291. claude_mpm/services/profile_manager.py +10 -4
  292. claude_mpm/services/skills/git_skill_source_manager.py +192 -29
  293. claude_mpm/services/skills/selective_skill_deployer.py +211 -46
  294. claude_mpm/services/skills/skill_discovery_service.py +74 -4
  295. claude_mpm/services/skills_deployer.py +192 -70
  296. claude_mpm/services/socketio/handlers/hook.py +14 -7
  297. claude_mpm/services/socketio/server/main.py +12 -4
  298. claude_mpm/skills/__init__.py +2 -1
  299. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  300. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  301. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  302. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  303. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  304. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  305. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  306. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  307. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  308. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  309. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  310. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  311. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  312. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  313. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  314. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  315. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  316. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  317. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  318. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  319. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  320. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  321. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  322. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  323. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  324. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  325. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  326. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  327. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  328. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  329. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  330. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  331. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  332. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  333. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  334. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  335. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  336. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  337. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  338. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  339. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  340. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  341. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  342. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  343. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  344. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  345. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  346. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  347. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  348. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  349. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  350. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  351. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  352. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  353. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  354. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  355. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  356. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  357. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  358. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  359. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  360. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  361. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  362. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  363. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  364. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  365. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  366. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  367. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  368. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  369. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  370. claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
  371. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  372. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  373. claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
  374. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  375. claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
  376. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  377. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  378. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  379. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  380. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  381. claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
  382. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  383. claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
  384. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  385. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  386. claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
  387. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  388. claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
  389. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  390. claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
  391. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  392. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  393. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  394. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  395. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  396. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  397. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  398. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  399. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  400. claude_mpm/skills/bundled/security-scanning.md +112 -0
  401. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  402. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  403. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  404. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  405. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  406. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  407. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  408. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  409. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  410. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  411. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  412. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  413. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  414. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  415. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  416. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  417. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  418. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  419. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  420. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  421. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  422. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  423. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  424. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  425. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  426. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  427. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  428. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  429. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  430. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  431. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  432. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  433. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  434. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  435. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  436. claude_mpm/skills/registry.py +295 -90
  437. claude_mpm/skills/skill_manager.py +29 -23
  438. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  439. claude_mpm/utils/agent_dependency_loader.py +103 -4
  440. claude_mpm/utils/robust_installer.py +45 -24
  441. claude_mpm-5.6.23.dist-info/METADATA +393 -0
  442. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.23.dist-info}/RECORD +447 -149
  443. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +0 -1
  444. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +0 -1
  445. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +0 -1
  446. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +0 -1
  447. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +0 -1
  448. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +0 -2
  449. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +0 -2
  450. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +0 -1
  451. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +0 -1
  452. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +0 -10
  453. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  454. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  455. claude_mpm-5.4.41.dist-info/METADATA +0 -998
  456. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.23.dist-info}/WHEEL +0 -0
  457. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.23.dist-info}/entry_points.txt +0 -0
  458. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.23.dist-info}/licenses/LICENSE +0 -0
  459. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.23.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  460. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.23.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,237 @@
1
+ """Codex CLI runtime adapter.
2
+
3
+ This module implements the RuntimeAdapter interface for Codex,
4
+ an AI coding assistant (limited support currently).
5
+ """
6
+
7
+ import logging
8
+ import re
9
+ import shlex
10
+ from typing import List, Optional, Set
11
+
12
+ from .base import (
13
+ Capability,
14
+ ParsedResponse,
15
+ RuntimeAdapter,
16
+ RuntimeCapability,
17
+ RuntimeInfo,
18
+ )
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ class CodexAdapter(RuntimeAdapter):
24
+ """Adapter for Codex CLI.
25
+
26
+ Codex is an AI coding assistant. This adapter provides basic support,
27
+ with limited capabilities compared to Claude Code or MPM.
28
+
29
+ Note:
30
+ Agent delegation and advanced features not yet supported.
31
+
32
+ Example:
33
+ >>> adapter = CodexAdapter()
34
+ >>> cmd = adapter.build_launch_command("/home/user/project")
35
+ >>> print(cmd)
36
+ cd '/home/user/project' && codex
37
+ """
38
+
39
+ # Idle detection patterns
40
+ IDLE_PATTERNS = [
41
+ r"^>\s*$", # Simple prompt
42
+ r"codex>\s*$", # Named prompt
43
+ r"Ready",
44
+ r"Waiting for input",
45
+ ]
46
+
47
+ # Error patterns
48
+ ERROR_PATTERNS = [
49
+ r"Error:",
50
+ r"Failed:",
51
+ r"Exception:",
52
+ r"Permission denied",
53
+ r"not found",
54
+ r"Traceback",
55
+ r"FATAL:",
56
+ ]
57
+
58
+ # Question patterns
59
+ QUESTION_PATTERNS = [
60
+ r"Which option",
61
+ r"Should I proceed",
62
+ r"Please choose",
63
+ r"\(y/n\)\?",
64
+ r"Are you sure",
65
+ r"\[Y/n\]",
66
+ ]
67
+
68
+ # ANSI escape code pattern
69
+ ANSI_ESCAPE = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
70
+
71
+ @property
72
+ def name(self) -> str:
73
+ """Return the runtime identifier."""
74
+ return "codex"
75
+
76
+ @property
77
+ def capabilities(self) -> Set[Capability]:
78
+ """Return the set of capabilities supported by Codex."""
79
+ return {
80
+ Capability.TOOL_USE,
81
+ Capability.FILE_EDIT,
82
+ Capability.FILE_CREATE,
83
+ Capability.SHELL_COMMANDS,
84
+ Capability.COMPLEX_REASONING,
85
+ }
86
+
87
+ @property
88
+ def runtime_info(self) -> RuntimeInfo:
89
+ """Return detailed runtime information."""
90
+ return RuntimeInfo(
91
+ name="codex",
92
+ version=None, # Version detection could be added
93
+ capabilities={
94
+ RuntimeCapability.FILE_READ,
95
+ RuntimeCapability.FILE_EDIT,
96
+ RuntimeCapability.FILE_CREATE,
97
+ RuntimeCapability.BASH_EXECUTION,
98
+ RuntimeCapability.TOOL_USE,
99
+ RuntimeCapability.COMPLEX_REASONING,
100
+ },
101
+ command="codex",
102
+ supports_agents=False, # No agent support
103
+ instruction_file=None, # No custom instructions support
104
+ )
105
+
106
+ def build_launch_command(
107
+ self, project_path: str, agent_prompt: Optional[str] = None
108
+ ) -> str:
109
+ """Generate shell command to start Codex.
110
+
111
+ Args:
112
+ project_path: Absolute path to the project directory
113
+ agent_prompt: Optional system prompt (may not be supported)
114
+
115
+ Returns:
116
+ Shell command string ready to execute
117
+
118
+ Example:
119
+ >>> adapter = CodexAdapter()
120
+ >>> adapter.build_launch_command("/home/user/project")
121
+ "cd '/home/user/project' && codex"
122
+ """
123
+ quoted_path = shlex.quote(project_path)
124
+ cmd = f"cd {quoted_path} && codex"
125
+
126
+ # Note: Codex may not support custom prompts
127
+ # Adjust based on actual Codex CLI capabilities
128
+ if agent_prompt:
129
+ logger.warning("Codex may not support custom prompts")
130
+
131
+ logger.debug(f"Built Codex launch command: {cmd}")
132
+ return cmd
133
+
134
+ def format_input(self, message: str) -> str:
135
+ """Prepare message for Codex's input format."""
136
+ formatted = message.strip()
137
+ logger.debug(f"Formatted input: {formatted[:100]}...")
138
+ return formatted
139
+
140
+ def strip_ansi(self, text: str) -> str:
141
+ """Remove ANSI escape codes from text."""
142
+ return self.ANSI_ESCAPE.sub("", text)
143
+
144
+ def detect_idle(self, output: str) -> bool:
145
+ """Recognize when Codex is waiting for input."""
146
+ if not output:
147
+ return False
148
+
149
+ clean = self.strip_ansi(output)
150
+ lines = clean.strip().split("\n")
151
+
152
+ if not lines:
153
+ return False
154
+
155
+ last_line = lines[-1].strip()
156
+
157
+ for pattern in self.IDLE_PATTERNS:
158
+ if re.search(pattern, last_line):
159
+ logger.debug(f"Detected idle state with pattern: {pattern}")
160
+ return True
161
+
162
+ return False
163
+
164
+ def detect_error(self, output: str) -> Optional[str]:
165
+ """Recognize error states and extract error message."""
166
+ clean = self.strip_ansi(output)
167
+
168
+ for pattern in self.ERROR_PATTERNS:
169
+ match = re.search(pattern, clean, re.IGNORECASE)
170
+ if match:
171
+ for line in clean.split("\n"):
172
+ if re.search(pattern, line, re.IGNORECASE):
173
+ error_msg = line.strip()
174
+ logger.warning(f"Detected error: {error_msg}")
175
+ return error_msg
176
+
177
+ return None
178
+
179
+ def detect_question(
180
+ self, output: str
181
+ ) -> tuple[bool, Optional[str], Optional[List[str]]]:
182
+ """Detect if Codex is asking a question."""
183
+ clean = self.strip_ansi(output)
184
+
185
+ for pattern in self.QUESTION_PATTERNS:
186
+ if re.search(pattern, clean, re.IGNORECASE):
187
+ lines = clean.strip().split("\n")
188
+ question = None
189
+ options = []
190
+
191
+ for line in lines:
192
+ if re.search(pattern, line, re.IGNORECASE):
193
+ question = line.strip()
194
+
195
+ # Look for numbered options
196
+ opt_match = re.match(r"^\s*(\d+)[.):]\s*(.+)$", line)
197
+ if opt_match:
198
+ options.append(opt_match.group(2).strip())
199
+
200
+ logger.debug(
201
+ f"Detected question: {question}, options: {options if options else 'none'}"
202
+ )
203
+ return True, question, options if options else None
204
+
205
+ return False, None, None
206
+
207
+ def parse_response(self, output: str) -> ParsedResponse:
208
+ """Extract meaningful content from Codex output."""
209
+ if not output:
210
+ return ParsedResponse(
211
+ content="",
212
+ is_complete=False,
213
+ is_error=False,
214
+ is_question=False,
215
+ )
216
+
217
+ clean = self.strip_ansi(output)
218
+ error_msg = self.detect_error(output)
219
+ is_question, question_text, options = self.detect_question(output)
220
+ is_complete = self.detect_idle(output)
221
+
222
+ response = ParsedResponse(
223
+ content=clean,
224
+ is_complete=is_complete,
225
+ is_error=error_msg is not None,
226
+ error_message=error_msg,
227
+ is_question=is_question,
228
+ question_text=question_text,
229
+ options=options,
230
+ )
231
+
232
+ logger.debug(
233
+ f"Parsed response: complete={is_complete}, error={error_msg is not None}, "
234
+ f"question={is_question}"
235
+ )
236
+
237
+ return response
@@ -0,0 +1,366 @@
1
+ """Communication adapters for managing async I/O with AI coding assistants.
2
+
3
+ This module provides the async communication layer that sits between
4
+ InstanceManager and TmuxOrchestrator, using RuntimeAdapter for parsing.
5
+ """
6
+
7
+ import asyncio
8
+ import logging
9
+ from abc import ABC, abstractmethod
10
+ from dataclasses import dataclass
11
+ from enum import Enum
12
+ from typing import TYPE_CHECKING, AsyncIterator, Optional
13
+
14
+ from claude_mpm.commander.tmux_orchestrator import TmuxOrchestrator
15
+
16
+ from .base import RuntimeAdapter
17
+
18
+ if TYPE_CHECKING:
19
+ from .base import ParsedResponse
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ class AdapterState(Enum):
25
+ """States that a communication adapter can be in."""
26
+
27
+ IDLE = "idle" # Ready for input
28
+ PROCESSING = "processing" # Working on request
29
+ WAITING = "waiting" # Waiting for user input (e.g., permission)
30
+ ERROR = "error" # Error state
31
+
32
+
33
+ @dataclass
34
+ class AdapterResponse:
35
+ """Response from a communication adapter.
36
+
37
+ Attributes:
38
+ content: The response content
39
+ state: Current adapter state
40
+ tool_uses: List of tools used in response
41
+ files_modified: List of files edited
42
+ is_complete: True if response is complete (prompt returned)
43
+
44
+ Example:
45
+ >>> response = AdapterResponse(
46
+ ... content="File created: test.py",
47
+ ... state=AdapterState.IDLE,
48
+ ... tool_uses=["Write"],
49
+ ... files_modified=["test.py"],
50
+ ... is_complete=True
51
+ ... )
52
+ """
53
+
54
+ content: str
55
+ state: AdapterState
56
+ tool_uses: Optional[list[str]] = None
57
+ files_modified: Optional[list[str]] = None
58
+ is_complete: bool = False
59
+
60
+
61
+ class BaseCommunicationAdapter(ABC):
62
+ """Abstract base class for communication adapters.
63
+
64
+ A communication adapter manages the async I/O with an AI coding assistant
65
+ via TmuxOrchestrator, maintaining state and handling streaming responses.
66
+
67
+ Example:
68
+ >>> orchestrator = TmuxOrchestrator()
69
+ >>> adapter = ClaudeCodeCommunicationAdapter(orchestrator, "%0")
70
+ >>> await adapter.send("Fix the bug in main.py")
71
+ >>> response = await adapter.receive()
72
+ >>> print(response.content)
73
+ """
74
+
75
+ @abstractmethod
76
+ async def send(self, message: str) -> None:
77
+ """Send a message to the assistant.
78
+
79
+ Args:
80
+ message: The message to send
81
+
82
+ Example:
83
+ >>> await adapter.send("Fix the bug in main.py")
84
+ """
85
+
86
+ @abstractmethod
87
+ async def receive(self, timeout: float = 30.0) -> AdapterResponse:
88
+ """Wait for and return response.
89
+
90
+ Args:
91
+ timeout: Maximum time to wait for response
92
+
93
+ Returns:
94
+ AdapterResponse with parsed content and state
95
+
96
+ Example:
97
+ >>> response = await adapter.receive(timeout=60.0)
98
+ >>> print(response.content)
99
+ """
100
+
101
+ @abstractmethod
102
+ async def interrupt(self) -> bool:
103
+ """Send interrupt signal (Ctrl+C).
104
+
105
+ Returns:
106
+ True if interrupt was successful
107
+
108
+ Example:
109
+ >>> success = await adapter.interrupt()
110
+ """
111
+
112
+ @abstractmethod
113
+ def is_ready(self) -> bool:
114
+ """Check if adapter is ready for input.
115
+
116
+ Returns:
117
+ True if adapter is in IDLE state
118
+
119
+ Example:
120
+ >>> if adapter.is_ready():
121
+ ... await adapter.send("Next task")
122
+ """
123
+
124
+ @abstractmethod
125
+ async def stream_response(self) -> AsyncIterator[str]:
126
+ """Stream response chunks as they arrive.
127
+
128
+ Yields:
129
+ Response chunks as they become available
130
+
131
+ Example:
132
+ >>> async for chunk in adapter.stream_response():
133
+ ... print(chunk, end='')
134
+ """
135
+
136
+
137
+ class ClaudeCodeCommunicationAdapter(BaseCommunicationAdapter):
138
+ """Communication adapter for Claude Code CLI.
139
+
140
+ This adapter manages async I/O with Claude Code via TmuxOrchestrator,
141
+ using ClaudeCodeAdapter (RuntimeAdapter) for output parsing.
142
+
143
+ Attributes:
144
+ orchestrator: TmuxOrchestrator for tmux operations
145
+ pane_target: Tmux pane target (e.g., "%0")
146
+ poll_interval: Polling interval for output capture (seconds)
147
+
148
+ Example:
149
+ >>> orchestrator = TmuxOrchestrator()
150
+ >>> adapter = ClaudeCodeCommunicationAdapter(orchestrator, "%0")
151
+ >>> await adapter.send("Create a new Python file")
152
+ >>> response = await adapter.receive()
153
+ >>> print(response.files_modified)
154
+ ['new_file.py']
155
+ """
156
+
157
+ def __init__(
158
+ self,
159
+ orchestrator: TmuxOrchestrator,
160
+ pane_target: str,
161
+ runtime_adapter: RuntimeAdapter,
162
+ poll_interval: float = 0.2,
163
+ ):
164
+ """Initialize the communication adapter.
165
+
166
+ Args:
167
+ orchestrator: TmuxOrchestrator for tmux operations
168
+ pane_target: Tmux pane target (e.g., "%0")
169
+ runtime_adapter: RuntimeAdapter for parsing output
170
+ poll_interval: Polling interval for output capture (seconds)
171
+ """
172
+ self.orchestrator = orchestrator
173
+ self.pane_target = pane_target
174
+ self.runtime_adapter = runtime_adapter
175
+ self.poll_interval = poll_interval
176
+ self._state = AdapterState.IDLE
177
+ self._last_output = ""
178
+ self._output_buffer = ""
179
+
180
+ async def send(self, message: str) -> None:
181
+ """Send message to Claude Code.
182
+
183
+ Args:
184
+ message: The message to send
185
+
186
+ Example:
187
+ >>> await adapter.send("Fix the bug in main.py")
188
+ """
189
+ logger.debug(f"Sending message to {self.pane_target}: {message[:50]}...")
190
+ self._state = AdapterState.PROCESSING
191
+ self._output_buffer = ""
192
+
193
+ # Format message using RuntimeAdapter
194
+ formatted = self.runtime_adapter.format_input(message)
195
+
196
+ # Send via tmux
197
+ self.orchestrator.send_keys(self.pane_target, formatted, enter=True)
198
+
199
+ async def receive(self, timeout: float = 30.0) -> AdapterResponse:
200
+ """Wait for complete response from Claude Code.
201
+
202
+ Args:
203
+ timeout: Maximum time to wait for response
204
+
205
+ Returns:
206
+ AdapterResponse with parsed content and state
207
+
208
+ Example:
209
+ >>> response = await adapter.receive(timeout=60.0)
210
+ >>> if response.is_complete:
211
+ ... print("Task complete!")
212
+ """
213
+ start = asyncio.get_event_loop().time()
214
+
215
+ while asyncio.get_event_loop().time() - start < timeout:
216
+ # Capture output from tmux pane
217
+ output = self.orchestrator.capture_output(self.pane_target, lines=100)
218
+
219
+ # Get only new output
220
+ new_output = self._get_new_output(output)
221
+ if new_output:
222
+ self._output_buffer += new_output
223
+
224
+ # Parse response using RuntimeAdapter
225
+ parsed = self.runtime_adapter.parse_response(output)
226
+
227
+ # Check if error occurred (prioritize error state)
228
+ if parsed.is_error:
229
+ self._state = AdapterState.ERROR
230
+ logger.warning(f"Error detected: {parsed.error_message}")
231
+ return self._build_response(parsed, is_complete=True)
232
+
233
+ # Check if waiting for user input (question)
234
+ if parsed.is_question:
235
+ self._state = AdapterState.WAITING
236
+ logger.debug(f"Question detected: {parsed.question_text}")
237
+ return self._build_response(parsed, is_complete=False)
238
+
239
+ # Check if response is complete (idle state)
240
+ if parsed.is_complete:
241
+ self._state = AdapterState.IDLE
242
+ logger.debug("Response complete (idle detected)")
243
+ return self._build_response(parsed, is_complete=True)
244
+
245
+ # Continue polling
246
+ await asyncio.sleep(self.poll_interval)
247
+
248
+ # Timeout - return partial response
249
+ logger.warning(f"Timeout after {timeout}s")
250
+ parsed = self.runtime_adapter.parse_response(self._output_buffer)
251
+ return self._build_response(parsed, is_complete=False)
252
+
253
+ async def interrupt(self) -> bool:
254
+ """Send Ctrl+C to interrupt Claude Code.
255
+
256
+ Returns:
257
+ True if interrupt was successful
258
+
259
+ Example:
260
+ >>> success = await adapter.interrupt()
261
+ >>> if success:
262
+ ... print("Interrupted successfully")
263
+ """
264
+ try:
265
+ logger.info(f"Sending interrupt to {self.pane_target}")
266
+ self.orchestrator.send_keys(self.pane_target, "C-c", enter=False)
267
+ self._state = AdapterState.IDLE
268
+ return True
269
+ except Exception as e:
270
+ logger.error(f"Failed to interrupt: {e}")
271
+ return False
272
+
273
+ def is_ready(self) -> bool:
274
+ """Check if adapter is ready for input.
275
+
276
+ Returns:
277
+ True if adapter is in IDLE state
278
+
279
+ Example:
280
+ >>> if adapter.is_ready():
281
+ ... await adapter.send("Next task")
282
+ """
283
+ return self._state == AdapterState.IDLE
284
+
285
+ async def stream_response(self) -> AsyncIterator[str]:
286
+ """Stream response chunks from Claude Code.
287
+
288
+ Yields:
289
+ Response chunks as they become available
290
+
291
+ Example:
292
+ >>> async for chunk in adapter.stream_response():
293
+ ... print(chunk, end='', flush=True)
294
+ """
295
+ last_len = 0
296
+
297
+ while self._state == AdapterState.PROCESSING:
298
+ # Capture current output
299
+ output = self.orchestrator.capture_output(self.pane_target, lines=100)
300
+
301
+ # Get new output since last check and add to buffer
302
+ new_output = self._get_new_output(output)
303
+ if new_output:
304
+ self._output_buffer += new_output
305
+
306
+ # Yield new chunk if buffer grew
307
+ if len(self._output_buffer) > last_len:
308
+ chunk = self._output_buffer[last_len:]
309
+ last_len = len(self._output_buffer)
310
+ yield chunk
311
+
312
+ # Check if complete using RuntimeAdapter
313
+ parsed = self.runtime_adapter.parse_response(output)
314
+ if parsed.is_complete:
315
+ self._state = AdapterState.IDLE
316
+ logger.debug("Streaming complete (idle detected)")
317
+ break
318
+
319
+ await asyncio.sleep(self.poll_interval)
320
+
321
+ def _get_new_output(self, current: str) -> str:
322
+ """Get only new output since last capture.
323
+
324
+ Args:
325
+ current: Current output from tmux pane
326
+
327
+ Returns:
328
+ New output that hasn't been seen before
329
+ """
330
+ if current == self._last_output:
331
+ return ""
332
+
333
+ # Find where new content starts
334
+ if self._last_output and current.startswith(self._last_output):
335
+ new = current[len(self._last_output) :]
336
+ else:
337
+ new = current
338
+
339
+ self._last_output = current
340
+ return new
341
+
342
+ def _build_response(
343
+ self,
344
+ parsed: "ParsedResponse",
345
+ is_complete: bool,
346
+ ) -> AdapterResponse:
347
+ """Build AdapterResponse from ParsedResponse.
348
+
349
+ Args:
350
+ parsed: ParsedResponse from RuntimeAdapter
351
+ is_complete: Whether response is complete
352
+
353
+ Returns:
354
+ AdapterResponse with metadata
355
+ """
356
+ # TODO: Extract tool uses and files modified from content
357
+ # This would require additional parsing patterns in RuntimeAdapter
358
+ # For now, return basic response
359
+
360
+ return AdapterResponse(
361
+ content=parsed.content,
362
+ state=self._state,
363
+ tool_uses=None, # Future: extract from content
364
+ files_modified=None, # Future: extract from content
365
+ is_complete=is_complete,
366
+ )