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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +8 -5
  3. claude_mpm/agents/{CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md → CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md} +14 -6
  4. claude_mpm/agents/PM_INSTRUCTIONS.md +109 -706
  5. claude_mpm/agents/WORKFLOW.md +2 -0
  6. claude_mpm/agents/templates/circuit-breakers.md +26 -17
  7. claude_mpm/auth/__init__.py +35 -0
  8. claude_mpm/auth/callback_server.py +328 -0
  9. claude_mpm/auth/models.py +104 -0
  10. claude_mpm/auth/oauth_manager.py +266 -0
  11. claude_mpm/auth/providers/__init__.py +12 -0
  12. claude_mpm/auth/providers/base.py +165 -0
  13. claude_mpm/auth/providers/google.py +261 -0
  14. claude_mpm/auth/token_storage.py +252 -0
  15. claude_mpm/cli/commands/autotodos.py +566 -0
  16. claude_mpm/cli/commands/commander.py +216 -0
  17. claude_mpm/cli/commands/hook_errors.py +60 -60
  18. claude_mpm/cli/commands/mcp.py +29 -17
  19. claude_mpm/cli/commands/mcp_command_router.py +39 -0
  20. claude_mpm/cli/commands/mcp_service_commands.py +304 -0
  21. claude_mpm/cli/commands/monitor.py +2 -2
  22. claude_mpm/cli/commands/mpm_init/core.py +2 -2
  23. claude_mpm/cli/commands/oauth.py +481 -0
  24. claude_mpm/cli/commands/run.py +35 -3
  25. claude_mpm/cli/commands/skill_source.py +51 -2
  26. claude_mpm/cli/commands/skills.py +5 -3
  27. claude_mpm/cli/executor.py +128 -16
  28. claude_mpm/cli/helpers.py +1 -1
  29. claude_mpm/cli/parsers/base_parser.py +84 -1
  30. claude_mpm/cli/parsers/commander_parser.py +116 -0
  31. claude_mpm/cli/parsers/mcp_parser.py +79 -0
  32. claude_mpm/cli/parsers/oauth_parser.py +165 -0
  33. claude_mpm/cli/parsers/run_parser.py +10 -0
  34. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  35. claude_mpm/cli/parsers/skills_parser.py +5 -0
  36. claude_mpm/cli/startup.py +345 -40
  37. claude_mpm/cli/startup_display.py +76 -7
  38. claude_mpm/cli/startup_logging.py +2 -2
  39. claude_mpm/cli/startup_migrations.py +236 -0
  40. claude_mpm/cli/utils.py +7 -3
  41. claude_mpm/commander/__init__.py +78 -0
  42. claude_mpm/commander/adapters/__init__.py +60 -0
  43. claude_mpm/commander/adapters/auggie.py +260 -0
  44. claude_mpm/commander/adapters/base.py +288 -0
  45. claude_mpm/commander/adapters/claude_code.py +392 -0
  46. claude_mpm/commander/adapters/codex.py +237 -0
  47. claude_mpm/commander/adapters/communication.py +366 -0
  48. claude_mpm/commander/adapters/example_usage.py +310 -0
  49. claude_mpm/commander/adapters/mpm.py +389 -0
  50. claude_mpm/commander/adapters/registry.py +204 -0
  51. claude_mpm/commander/api/__init__.py +16 -0
  52. claude_mpm/commander/api/app.py +121 -0
  53. claude_mpm/commander/api/errors.py +133 -0
  54. claude_mpm/commander/api/routes/__init__.py +8 -0
  55. claude_mpm/commander/api/routes/events.py +184 -0
  56. claude_mpm/commander/api/routes/inbox.py +171 -0
  57. claude_mpm/commander/api/routes/messages.py +148 -0
  58. claude_mpm/commander/api/routes/projects.py +271 -0
  59. claude_mpm/commander/api/routes/sessions.py +226 -0
  60. claude_mpm/commander/api/routes/work.py +296 -0
  61. claude_mpm/commander/api/schemas.py +186 -0
  62. claude_mpm/commander/chat/__init__.py +7 -0
  63. claude_mpm/commander/chat/cli.py +149 -0
  64. claude_mpm/commander/chat/commands.py +124 -0
  65. claude_mpm/commander/chat/repl.py +1957 -0
  66. claude_mpm/commander/config.py +51 -0
  67. claude_mpm/commander/config_loader.py +115 -0
  68. claude_mpm/commander/core/__init__.py +10 -0
  69. claude_mpm/commander/core/block_manager.py +325 -0
  70. claude_mpm/commander/core/response_manager.py +323 -0
  71. claude_mpm/commander/daemon.py +603 -0
  72. claude_mpm/commander/env_loader.py +59 -0
  73. claude_mpm/commander/events/__init__.py +26 -0
  74. claude_mpm/commander/events/manager.py +392 -0
  75. claude_mpm/commander/frameworks/__init__.py +12 -0
  76. claude_mpm/commander/frameworks/base.py +233 -0
  77. claude_mpm/commander/frameworks/claude_code.py +58 -0
  78. claude_mpm/commander/frameworks/mpm.py +57 -0
  79. claude_mpm/commander/git/__init__.py +5 -0
  80. claude_mpm/commander/git/worktree_manager.py +212 -0
  81. claude_mpm/commander/inbox/__init__.py +16 -0
  82. claude_mpm/commander/inbox/dedup.py +128 -0
  83. claude_mpm/commander/inbox/inbox.py +224 -0
  84. claude_mpm/commander/inbox/models.py +70 -0
  85. claude_mpm/commander/instance_manager.py +868 -0
  86. claude_mpm/commander/llm/__init__.py +6 -0
  87. claude_mpm/commander/llm/openrouter_client.py +167 -0
  88. claude_mpm/commander/llm/summarizer.py +70 -0
  89. claude_mpm/commander/memory/__init__.py +45 -0
  90. claude_mpm/commander/memory/compression.py +347 -0
  91. claude_mpm/commander/memory/embeddings.py +230 -0
  92. claude_mpm/commander/memory/entities.py +310 -0
  93. claude_mpm/commander/memory/example_usage.py +290 -0
  94. claude_mpm/commander/memory/integration.py +325 -0
  95. claude_mpm/commander/memory/search.py +381 -0
  96. claude_mpm/commander/memory/store.py +657 -0
  97. claude_mpm/commander/models/__init__.py +18 -0
  98. claude_mpm/commander/models/events.py +127 -0
  99. claude_mpm/commander/models/project.py +162 -0
  100. claude_mpm/commander/models/work.py +214 -0
  101. claude_mpm/commander/parsing/__init__.py +20 -0
  102. claude_mpm/commander/parsing/extractor.py +132 -0
  103. claude_mpm/commander/parsing/output_parser.py +270 -0
  104. claude_mpm/commander/parsing/patterns.py +100 -0
  105. claude_mpm/commander/persistence/__init__.py +11 -0
  106. claude_mpm/commander/persistence/event_store.py +274 -0
  107. claude_mpm/commander/persistence/state_store.py +403 -0
  108. claude_mpm/commander/persistence/work_store.py +164 -0
  109. claude_mpm/commander/polling/__init__.py +13 -0
  110. claude_mpm/commander/polling/event_detector.py +104 -0
  111. claude_mpm/commander/polling/output_buffer.py +49 -0
  112. claude_mpm/commander/polling/output_poller.py +153 -0
  113. claude_mpm/commander/project_session.py +268 -0
  114. claude_mpm/commander/proxy/__init__.py +12 -0
  115. claude_mpm/commander/proxy/formatter.py +89 -0
  116. claude_mpm/commander/proxy/output_handler.py +191 -0
  117. claude_mpm/commander/proxy/relay.py +155 -0
  118. claude_mpm/commander/registry.py +410 -0
  119. claude_mpm/commander/runtime/__init__.py +10 -0
  120. claude_mpm/commander/runtime/executor.py +191 -0
  121. claude_mpm/commander/runtime/monitor.py +346 -0
  122. claude_mpm/commander/session/__init__.py +6 -0
  123. claude_mpm/commander/session/context.py +81 -0
  124. claude_mpm/commander/session/manager.py +59 -0
  125. claude_mpm/commander/tmux_orchestrator.py +362 -0
  126. claude_mpm/commander/web/__init__.py +1 -0
  127. claude_mpm/commander/work/__init__.py +30 -0
  128. claude_mpm/commander/work/executor.py +207 -0
  129. claude_mpm/commander/work/queue.py +405 -0
  130. claude_mpm/commander/workflow/__init__.py +27 -0
  131. claude_mpm/commander/workflow/event_handler.py +241 -0
  132. claude_mpm/commander/workflow/notifier.py +146 -0
  133. claude_mpm/commands/mpm-config.md +8 -0
  134. claude_mpm/commands/mpm-doctor.md +8 -0
  135. claude_mpm/commands/mpm-help.md +8 -0
  136. claude_mpm/commands/mpm-init.md +8 -0
  137. claude_mpm/commands/mpm-monitor.md +8 -0
  138. claude_mpm/commands/mpm-organize.md +8 -0
  139. claude_mpm/commands/mpm-postmortem.md +8 -0
  140. claude_mpm/commands/mpm-session-resume.md +9 -1
  141. claude_mpm/commands/mpm-status.md +8 -0
  142. claude_mpm/commands/mpm-ticket-view.md +8 -0
  143. claude_mpm/commands/mpm-version.md +8 -0
  144. claude_mpm/commands/mpm.md +8 -0
  145. claude_mpm/config/agent_presets.py +8 -7
  146. claude_mpm/config/skill_sources.py +16 -0
  147. claude_mpm/constants.py +5 -0
  148. claude_mpm/core/claude_runner.py +152 -0
  149. claude_mpm/core/config.py +35 -22
  150. claude_mpm/core/config_constants.py +74 -9
  151. claude_mpm/core/constants.py +56 -12
  152. claude_mpm/core/hook_manager.py +53 -4
  153. claude_mpm/core/interactive_session.py +5 -4
  154. claude_mpm/core/logger.py +26 -9
  155. claude_mpm/core/logging_utils.py +39 -13
  156. claude_mpm/core/network_config.py +148 -0
  157. claude_mpm/core/oneshot_session.py +7 -6
  158. claude_mpm/core/output_style_manager.py +52 -12
  159. claude_mpm/core/socketio_pool.py +47 -15
  160. claude_mpm/core/unified_config.py +10 -6
  161. claude_mpm/core/unified_paths.py +68 -80
  162. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  163. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  164. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cs_tUR18.js → 1WZnGYqX.js} +1 -1
  165. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CDuw-vjf.js → 67pF3qNn.js} +1 -1
  166. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bTOqqlTd.js → 6RxdMKe4.js} +1 -1
  167. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DwBR2MJi.js → 8cZrfX0h.js} +1 -1
  168. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{ZGh7QtNv.js → 9a6T2nm-.js} +1 -1
  169. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D9lljYKQ.js → B443AUzu.js} +1 -1
  170. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{RJiighC3.js → B8AwtY2H.js} +1 -1
  171. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uuIeMWc-.js → BF15LAsF.js} +1 -1
  172. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D3k0OPJN.js → BRcwIQNr.js} +1 -1
  173. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CyWMqx4W.js → BV6nKitt.js} +1 -1
  174. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CiIAseT4.js → BViJ8lZt.js} +5 -5
  175. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CBBdVcY8.js → BcQ-Q0FE.js} +1 -1
  176. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BovzEFCE.js → Bpyvgze_.js} +1 -1
  177. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  178. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  179. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{eNVUfhuA.js → C3rbW_a-.js} +1 -1
  180. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{GYwsonyD.js → C8WYN38h.js} +1 -1
  181. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BIF9m_hv.js → C9I8FlXH.js} +1 -1
  182. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B0uc0UOD.js → CIQcWgO2.js} +3 -3
  183. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Be7GpZd6.js → CIctN7YN.js} +1 -1
  184. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Bh0LDWpI.js → CKrS_JZW.js} +2 -2
  185. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DUrLdbGD.js → CR6P9C4A.js} +1 -1
  186. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7xVLGWV.js → CRRR9MD_.js} +1 -1
  187. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  188. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dhb8PKl3.js → CSXtMOf0.js} +1 -1
  189. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BPYeabCQ.js → CT-sbxSk.js} +1 -1
  190. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{sQeU3Y1z.js → CWm6DJsp.js} +1 -1
  191. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CnA0NrzZ.js → CpqQ1Kzn.js} +1 -1
  192. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4B-KCzX.js → D2nGpDRe.js} +1 -1
  193. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DGkLK5U1.js → D9iCMida.js} +1 -1
  194. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BofRWZRR.js → D9ykgMoY.js} +1 -1
  195. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DmxopI1J.js → DL2Ldur1.js} +1 -1
  196. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C30mlcqg.js → DPfltzjH.js} +1 -1
  197. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Vzk33B_K.js → DR8nis88.js} +2 -2
  198. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DI7hHRFL.js → DUliQN2b.js} +1 -1
  199. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4JcI4KD.js → DXlhR01x.js} +1 -1
  200. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bT1r9zLR.js → D_lyTybS.js} +1 -1
  201. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DZX00Y4g.js → DngoTTgh.js} +1 -1
  202. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzZX-COe.js → DqkmHtDC.js} +1 -1
  203. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7RN905-.js → DsDh8EYs.js} +1 -1
  204. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DLVjFsZ3.js → DypDmXgd.js} +1 -1
  205. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{iEWssX7S.js → IPYC-LnN.js} +1 -1
  206. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  207. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DaimHw_p.js → JpevfAFt.js} +1 -1
  208. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DY1XQ8fi.js → R8CEIRAd.js} +1 -1
  209. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dle-35c7.js → Zxy7qc-l.js} +2 -2
  210. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  211. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C_Usid8X.js → qtd3IeO4.js} +2 -2
  212. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzeYkLYB.js → ulBFON_C.js} +2 -2
  213. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cfqx1Qun.js → wQVh1CoA.js} +1 -1
  214. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/{app.D6-I5TpK.js → app.Dr7t0z2J.js} +2 -2
  215. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  216. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.m1gL8KXf.js → 0.RgBboRvH.js} +1 -1
  217. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{1.CgNOuw-d.js → 1.DG-KkbDf.js} +1 -1
  218. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  219. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
  220. claude_mpm/dashboard/static/svelte-build/index.html +9 -9
  221. claude_mpm/experimental/cli_enhancements.py +2 -1
  222. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  223. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  224. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
  225. claude_mpm/hooks/claude_hooks/event_handlers.py +466 -136
  226. claude_mpm/hooks/claude_hooks/hook_handler.py +204 -104
  227. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  228. claude_mpm/hooks/claude_hooks/installer.py +291 -59
  229. claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
  230. claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
  231. claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
  232. claude_mpm/hooks/claude_hooks/services/connection_manager.py +41 -26
  233. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
  234. claude_mpm/hooks/claude_hooks/services/container.py +326 -0
  235. claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
  236. claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
  237. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
  238. claude_mpm/hooks/session_resume_hook.py +89 -1
  239. claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
  240. claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
  241. claude_mpm/init.py +22 -15
  242. claude_mpm/mcp/__init__.py +9 -0
  243. claude_mpm/mcp/google_workspace_server.py +610 -0
  244. claude_mpm/scripts/claude-hook-handler.sh +46 -19
  245. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  246. claude_mpm/services/agents/agent_selection_service.py +2 -2
  247. claude_mpm/services/agents/cache_git_manager.py +1 -1
  248. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +3 -0
  249. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  250. claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
  251. claude_mpm/services/cli/__init__.py +3 -0
  252. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  253. claude_mpm/services/cli/session_resume_helper.py +10 -2
  254. claude_mpm/services/command_deployment_service.py +44 -26
  255. claude_mpm/services/delegation_detector.py +175 -0
  256. claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
  257. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  258. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  259. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  260. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  261. claude_mpm/services/diagnostics/models.py +14 -1
  262. claude_mpm/services/event_log.py +325 -0
  263. claude_mpm/services/hook_installer_service.py +77 -8
  264. claude_mpm/services/infrastructure/__init__.py +4 -0
  265. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  266. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  267. claude_mpm/services/mcp_config_manager.py +99 -19
  268. claude_mpm/services/mcp_service_registry.py +294 -0
  269. claude_mpm/services/monitor/daemon_manager.py +15 -4
  270. claude_mpm/services/monitor/management/lifecycle.py +8 -2
  271. claude_mpm/services/monitor/server.py +111 -16
  272. claude_mpm/services/pm_skills_deployer.py +261 -87
  273. claude_mpm/services/skills/git_skill_source_manager.py +130 -10
  274. claude_mpm/services/skills/selective_skill_deployer.py +142 -16
  275. claude_mpm/services/skills/skill_discovery_service.py +74 -4
  276. claude_mpm/services/skills_deployer.py +31 -5
  277. claude_mpm/services/socketio/handlers/hook.py +14 -7
  278. claude_mpm/services/socketio/server/main.py +12 -4
  279. claude_mpm/skills/__init__.py +2 -1
  280. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  281. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  282. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  283. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  284. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  285. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  286. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  287. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  288. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  289. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  290. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  291. claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
  292. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  293. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  294. claude_mpm/skills/bundled/pm/{pm-teaching-mode → mpm-teaching-mode}/SKILL.md +2 -2
  295. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  296. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  297. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  298. claude_mpm/skills/registry.py +295 -90
  299. claude_mpm/skills/skill_manager.py +4 -4
  300. claude_mpm-5.6.76.dist-info/METADATA +416 -0
  301. {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/RECORD +312 -175
  302. {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/WHEEL +1 -1
  303. {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/entry_points.txt +2 -0
  304. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +0 -1
  305. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +0 -1
  306. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +0 -1
  307. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +0 -24
  308. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +0 -1
  309. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +0 -1
  310. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +0 -323
  311. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +0 -1
  312. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +0 -1
  313. claude_mpm-5.4.85.dist-info/METADATA +0 -1023
  314. /claude_mpm/skills/bundled/pm/{pm-bug-reporting/pm-bug-reporting.md → mpm-bug-reporting/SKILL.md} +0 -0
  315. /claude_mpm/skills/bundled/pm/{pm-delegation-patterns → mpm-delegation-patterns}/SKILL.md +0 -0
  316. /claude_mpm/skills/bundled/pm/{pm-git-file-tracking → mpm-git-file-tracking}/SKILL.md +0 -0
  317. /claude_mpm/skills/bundled/pm/{pm-pr-workflow → mpm-pr-workflow}/SKILL.md +0 -0
  318. /claude_mpm/skills/bundled/pm/{pm-ticketing-integration → mpm-ticketing-integration}/SKILL.md +0 -0
  319. /claude_mpm/skills/bundled/pm/{pm-verification-protocols → mpm-verification-protocols}/SKILL.md +0 -0
  320. {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/licenses/LICENSE +0 -0
  321. {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  322. {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,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
+ )
@@ -0,0 +1,310 @@
1
+ """Example usage of multi-runtime adapter architecture.
2
+
3
+ This module demonstrates how to use the adapter registry and
4
+ individual adapters for different AI coding runtimes.
5
+ """
6
+
7
+ import logging
8
+ from typing import Optional
9
+
10
+ from claude_mpm.commander.adapters import (
11
+ AdapterRegistry,
12
+ AuggieAdapter,
13
+ ClaudeCodeAdapter,
14
+ CodexAdapter,
15
+ MPMAdapter,
16
+ RuntimeAdapter,
17
+ RuntimeCapability,
18
+ )
19
+
20
+ # Configure logging
21
+ logging.basicConfig(
22
+ level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
23
+ )
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ def example_registry_usage() -> None:
28
+ """Demonstrate adapter registry usage."""
29
+ print("\n" + "=" * 60)
30
+ print("ADAPTER REGISTRY USAGE")
31
+ print("=" * 60 + "\n")
32
+
33
+ # List all registered adapters
34
+ registered = AdapterRegistry.list_registered()
35
+ print(f"Registered adapters: {registered}")
36
+
37
+ # Detect available runtimes on system
38
+ available = AdapterRegistry.detect_available()
39
+ print(f"Available runtimes: {available}")
40
+
41
+ # Get default adapter (best available)
42
+ default_adapter = AdapterRegistry.get_default()
43
+ if default_adapter:
44
+ print(f"\nDefault adapter: {default_adapter.name}")
45
+ print(f"Capabilities: {default_adapter.capabilities}")
46
+ else:
47
+ print("\nNo adapters available on this system")
48
+
49
+ # Get specific adapter
50
+ mpm_adapter = AdapterRegistry.get("mpm")
51
+ if mpm_adapter:
52
+ print(f"\nMPM adapter available: {mpm_adapter.name}")
53
+ else:
54
+ print("\nMPM adapter not available")
55
+
56
+ # Check if specific runtime is available
57
+ if AdapterRegistry.is_available("claude-code"):
58
+ print("\nClaude Code is available")
59
+ else:
60
+ print("\nClaude Code is NOT available")
61
+
62
+
63
+ def example_adapter_capabilities() -> None:
64
+ """Demonstrate checking adapter capabilities."""
65
+ print("\n" + "=" * 60)
66
+ print("ADAPTER CAPABILITIES")
67
+ print("=" * 60 + "\n")
68
+
69
+ adapters = [
70
+ ClaudeCodeAdapter(),
71
+ AuggieAdapter(),
72
+ CodexAdapter(),
73
+ MPMAdapter(),
74
+ ]
75
+
76
+ for adapter in adapters:
77
+ print(f"\n{adapter.name.upper()} Adapter:")
78
+ print(
79
+ f" Command: {adapter.runtime_info.command if adapter.runtime_info else 'N/A'}"
80
+ )
81
+
82
+ # Check for specific capabilities
83
+ info = adapter.runtime_info
84
+ if info:
85
+ print(f" Supports agents: {info.supports_agents}")
86
+ print(f" Instruction file: {info.instruction_file or 'None'}")
87
+
88
+ # Check for advanced features
89
+ if RuntimeCapability.AGENT_DELEGATION in info.capabilities:
90
+ print(" ✓ Agent delegation supported")
91
+ else:
92
+ print(" ✗ Agent delegation NOT supported")
93
+
94
+ if RuntimeCapability.HOOKS in info.capabilities:
95
+ print(" ✓ Lifecycle hooks supported")
96
+ else:
97
+ print(" ✗ Lifecycle hooks NOT supported")
98
+
99
+ if RuntimeCapability.MCP_TOOLS in info.capabilities:
100
+ print(" ✓ MCP tools supported")
101
+ else:
102
+ print(" ✗ MCP tools NOT supported")
103
+
104
+ if RuntimeCapability.SKILLS in info.capabilities:
105
+ print(" ✓ Skills supported")
106
+ else:
107
+ print(" ✗ Skills NOT supported")
108
+
109
+ if RuntimeCapability.MONITOR in info.capabilities:
110
+ print(" ✓ Real-time monitoring supported")
111
+ else:
112
+ print(" ✗ Real-time monitoring NOT supported")
113
+
114
+
115
+ def example_build_commands() -> None:
116
+ """Demonstrate building launch commands."""
117
+ print("\n" + "=" * 60)
118
+ print("BUILD LAUNCH COMMANDS")
119
+ print("=" * 60 + "\n")
120
+
121
+ project_path = "/home/user/my-project"
122
+ agent_prompt = "You are a Python expert specializing in FastAPI and async code."
123
+
124
+ adapters = [
125
+ ClaudeCodeAdapter(),
126
+ AuggieAdapter(),
127
+ CodexAdapter(),
128
+ MPMAdapter(),
129
+ ]
130
+
131
+ for adapter in adapters:
132
+ print(f"\n{adapter.name.upper()}:")
133
+
134
+ # Basic launch command
135
+ cmd = adapter.build_launch_command(project_path)
136
+ print(f" Basic: {cmd}")
137
+
138
+ # With agent prompt
139
+ cmd_with_prompt = adapter.build_launch_command(project_path, agent_prompt)
140
+ print(f" With prompt: {cmd_with_prompt}")
141
+
142
+
143
+ def example_inject_instructions() -> None:
144
+ """Demonstrate injecting custom instructions."""
145
+ print("\n" + "=" * 60)
146
+ print("INJECT CUSTOM INSTRUCTIONS")
147
+ print("=" * 60 + "\n")
148
+
149
+ instructions = """You are a senior Python engineer.
150
+ Follow PEP 8 strictly.
151
+ Write comprehensive tests for all code.
152
+ Use type hints everywhere."""
153
+
154
+ adapters = [
155
+ ClaudeCodeAdapter(),
156
+ AuggieAdapter(),
157
+ CodexAdapter(),
158
+ MPMAdapter(),
159
+ ]
160
+
161
+ for adapter in adapters:
162
+ print(f"\n{adapter.name.upper()}:")
163
+
164
+ cmd = adapter.inject_instructions(instructions)
165
+ if cmd:
166
+ print(f" Command: {cmd}")
167
+ else:
168
+ print(" Not supported")
169
+
170
+
171
+ def example_inject_agent_context() -> None:
172
+ """Demonstrate injecting agent context."""
173
+ print("\n" + "=" * 60)
174
+ print("INJECT AGENT CONTEXT")
175
+ print("=" * 60 + "\n")
176
+
177
+ agent_id = "eng-001"
178
+ context = {
179
+ "role": "Engineer",
180
+ "specialty": "Backend Python",
181
+ "task": "Implement API endpoints",
182
+ }
183
+
184
+ adapters = [
185
+ ClaudeCodeAdapter(),
186
+ AuggieAdapter(),
187
+ CodexAdapter(),
188
+ MPMAdapter(),
189
+ ]
190
+
191
+ for adapter in adapters:
192
+ print(f"\n{adapter.name.upper()}:")
193
+
194
+ cmd = adapter.inject_agent_context(agent_id, context)
195
+ if cmd:
196
+ print(f" Command: {cmd[:100]}...")
197
+ else:
198
+ print(" Not supported")
199
+
200
+
201
+ def example_parse_response() -> None:
202
+ """Demonstrate parsing runtime output."""
203
+ print("\n" + "=" * 60)
204
+ print("PARSE RUNTIME OUTPUT")
205
+ print("=" * 60 + "\n")
206
+
207
+ # Simulate different output scenarios
208
+ outputs = {
209
+ "idle": "File created successfully.\n> ",
210
+ "error": "Error: File not found: config.py\n> ",
211
+ "question": "Should I proceed with the changes? (y/n)?",
212
+ "processing": "Processing your request...",
213
+ }
214
+
215
+ adapter = ClaudeCodeAdapter()
216
+
217
+ for scenario, output in outputs.items():
218
+ print(f"\n{scenario.upper()}:")
219
+ parsed = adapter.parse_response(output)
220
+ print(f" Content: {parsed.content[:50]}...")
221
+ print(f" Is complete: {parsed.is_complete}")
222
+ print(f" Is error: {parsed.is_error}")
223
+ print(f" Is question: {parsed.is_question}")
224
+ if parsed.error_message:
225
+ print(f" Error message: {parsed.error_message}")
226
+ if parsed.question_text:
227
+ print(f" Question: {parsed.question_text}")
228
+
229
+
230
+ def example_runtime_selection() -> None:
231
+ """Demonstrate selecting runtime based on requirements."""
232
+ print("\n" + "=" * 60)
233
+ print("RUNTIME SELECTION LOGIC")
234
+ print("=" * 60 + "\n")
235
+
236
+ def select_runtime(
237
+ needs_agents: bool = False, needs_mcp: bool = False
238
+ ) -> Optional[RuntimeAdapter]:
239
+ """Select appropriate runtime based on requirements."""
240
+ # Get all available adapters
241
+ available = AdapterRegistry.detect_available()
242
+
243
+ # Filter by requirements
244
+ for name in available:
245
+ adapter = AdapterRegistry.get(name)
246
+ if not adapter or not adapter.runtime_info:
247
+ continue
248
+
249
+ info = adapter.runtime_info
250
+
251
+ # Check agent requirement
252
+ if needs_agents and not info.supports_agents:
253
+ continue
254
+
255
+ # Check MCP requirement
256
+ if needs_mcp and RuntimeCapability.MCP_TOOLS not in info.capabilities:
257
+ continue
258
+
259
+ # Found suitable runtime
260
+ return adapter
261
+
262
+ return None
263
+
264
+ # Example 1: Need agent delegation
265
+ print("Requirement: Agent delegation")
266
+ adapter = select_runtime(needs_agents=True)
267
+ if adapter:
268
+ print(f" Selected: {adapter.name}")
269
+ else:
270
+ print(" No suitable runtime found")
271
+
272
+ # Example 2: Need MCP tools
273
+ print("\nRequirement: MCP tools")
274
+ adapter = select_runtime(needs_mcp=True)
275
+ if adapter:
276
+ print(f" Selected: {adapter.name}")
277
+ else:
278
+ print(" No suitable runtime found")
279
+
280
+ # Example 3: Need both
281
+ print("\nRequirement: Agent delegation + MCP tools")
282
+ adapter = select_runtime(needs_agents=True, needs_mcp=True)
283
+ if adapter:
284
+ print(f" Selected: {adapter.name}")
285
+ else:
286
+ print(" No suitable runtime found")
287
+
288
+
289
+ def main() -> None:
290
+ """Run all examples."""
291
+ print("\n" + "#" * 60)
292
+ print("# MULTI-RUNTIME ADAPTER ARCHITECTURE EXAMPLES")
293
+ print("#" * 60)
294
+
295
+ # Run all examples
296
+ example_registry_usage()
297
+ example_adapter_capabilities()
298
+ example_build_commands()
299
+ example_inject_instructions()
300
+ example_inject_agent_context()
301
+ example_parse_response()
302
+ example_runtime_selection()
303
+
304
+ print("\n" + "#" * 60)
305
+ print("# EXAMPLES COMPLETE")
306
+ print("#" * 60 + "\n")
307
+
308
+
309
+ if __name__ == "__main__":
310
+ main()