claude-mpm 5.4.41__py3-none-any.whl → 5.6.72__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (490) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
  3. claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
  4. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +109 -1925
  5. claude_mpm/agents/PM_INSTRUCTIONS.md +161 -298
  6. claude_mpm/agents/WORKFLOW.md +2 -0
  7. claude_mpm/agents/templates/circuit-breakers.md +26 -17
  8. claude_mpm/auth/__init__.py +35 -0
  9. claude_mpm/auth/callback_server.py +328 -0
  10. claude_mpm/auth/models.py +104 -0
  11. claude_mpm/auth/oauth_manager.py +266 -0
  12. claude_mpm/auth/providers/__init__.py +12 -0
  13. claude_mpm/auth/providers/base.py +165 -0
  14. claude_mpm/auth/providers/google.py +261 -0
  15. claude_mpm/auth/token_storage.py +252 -0
  16. claude_mpm/cli/__init__.py +5 -1
  17. claude_mpm/cli/commands/agents.py +2 -4
  18. claude_mpm/cli/commands/agents_reconcile.py +197 -0
  19. claude_mpm/cli/commands/autotodos.py +566 -0
  20. claude_mpm/cli/commands/commander.py +216 -0
  21. claude_mpm/cli/commands/configure.py +620 -21
  22. claude_mpm/cli/commands/configure_agent_display.py +3 -1
  23. claude_mpm/cli/commands/hook_errors.py +60 -60
  24. claude_mpm/cli/commands/mcp.py +29 -17
  25. claude_mpm/cli/commands/mcp_command_router.py +39 -0
  26. claude_mpm/cli/commands/mcp_service_commands.py +304 -0
  27. claude_mpm/cli/commands/monitor.py +2 -2
  28. claude_mpm/cli/commands/mpm_init/core.py +15 -8
  29. claude_mpm/cli/commands/oauth.py +481 -0
  30. claude_mpm/cli/commands/profile.py +9 -10
  31. claude_mpm/cli/commands/run.py +35 -3
  32. claude_mpm/cli/commands/skill_source.py +51 -2
  33. claude_mpm/cli/commands/skills.py +182 -32
  34. claude_mpm/cli/executor.py +129 -16
  35. claude_mpm/cli/helpers.py +1 -1
  36. claude_mpm/cli/interactive/__init__.py +10 -0
  37. claude_mpm/cli/interactive/agent_wizard.py +30 -50
  38. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  39. claude_mpm/cli/interactive/skill_selector.py +481 -0
  40. claude_mpm/cli/parsers/base_parser.py +89 -1
  41. claude_mpm/cli/parsers/commander_parser.py +116 -0
  42. claude_mpm/cli/parsers/mcp_parser.py +79 -0
  43. claude_mpm/cli/parsers/oauth_parser.py +165 -0
  44. claude_mpm/cli/parsers/profile_parser.py +0 -1
  45. claude_mpm/cli/parsers/run_parser.py +10 -0
  46. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  47. claude_mpm/cli/parsers/skills_parser.py +2 -3
  48. claude_mpm/cli/startup.py +662 -524
  49. claude_mpm/cli/startup_display.py +76 -7
  50. claude_mpm/cli/startup_logging.py +2 -2
  51. claude_mpm/cli/utils.py +7 -3
  52. claude_mpm/commander/__init__.py +78 -0
  53. claude_mpm/commander/adapters/__init__.py +60 -0
  54. claude_mpm/commander/adapters/auggie.py +260 -0
  55. claude_mpm/commander/adapters/base.py +288 -0
  56. claude_mpm/commander/adapters/claude_code.py +392 -0
  57. claude_mpm/commander/adapters/codex.py +237 -0
  58. claude_mpm/commander/adapters/communication.py +366 -0
  59. claude_mpm/commander/adapters/example_usage.py +310 -0
  60. claude_mpm/commander/adapters/mpm.py +389 -0
  61. claude_mpm/commander/adapters/registry.py +204 -0
  62. claude_mpm/commander/api/__init__.py +16 -0
  63. claude_mpm/commander/api/app.py +121 -0
  64. claude_mpm/commander/api/errors.py +133 -0
  65. claude_mpm/commander/api/routes/__init__.py +8 -0
  66. claude_mpm/commander/api/routes/events.py +184 -0
  67. claude_mpm/commander/api/routes/inbox.py +171 -0
  68. claude_mpm/commander/api/routes/messages.py +148 -0
  69. claude_mpm/commander/api/routes/projects.py +271 -0
  70. claude_mpm/commander/api/routes/sessions.py +226 -0
  71. claude_mpm/commander/api/routes/work.py +296 -0
  72. claude_mpm/commander/api/schemas.py +186 -0
  73. claude_mpm/commander/chat/__init__.py +7 -0
  74. claude_mpm/commander/chat/cli.py +149 -0
  75. claude_mpm/commander/chat/commands.py +122 -0
  76. claude_mpm/commander/chat/repl.py +1821 -0
  77. claude_mpm/commander/config.py +51 -0
  78. claude_mpm/commander/config_loader.py +115 -0
  79. claude_mpm/commander/core/__init__.py +10 -0
  80. claude_mpm/commander/core/block_manager.py +325 -0
  81. claude_mpm/commander/core/response_manager.py +323 -0
  82. claude_mpm/commander/daemon.py +603 -0
  83. claude_mpm/commander/env_loader.py +59 -0
  84. claude_mpm/commander/events/__init__.py +26 -0
  85. claude_mpm/commander/events/manager.py +392 -0
  86. claude_mpm/commander/frameworks/__init__.py +12 -0
  87. claude_mpm/commander/frameworks/base.py +233 -0
  88. claude_mpm/commander/frameworks/claude_code.py +58 -0
  89. claude_mpm/commander/frameworks/mpm.py +57 -0
  90. claude_mpm/commander/git/__init__.py +5 -0
  91. claude_mpm/commander/git/worktree_manager.py +212 -0
  92. claude_mpm/commander/inbox/__init__.py +16 -0
  93. claude_mpm/commander/inbox/dedup.py +128 -0
  94. claude_mpm/commander/inbox/inbox.py +224 -0
  95. claude_mpm/commander/inbox/models.py +70 -0
  96. claude_mpm/commander/instance_manager.py +865 -0
  97. claude_mpm/commander/llm/__init__.py +6 -0
  98. claude_mpm/commander/llm/openrouter_client.py +167 -0
  99. claude_mpm/commander/llm/summarizer.py +70 -0
  100. claude_mpm/commander/memory/__init__.py +45 -0
  101. claude_mpm/commander/memory/compression.py +347 -0
  102. claude_mpm/commander/memory/embeddings.py +230 -0
  103. claude_mpm/commander/memory/entities.py +310 -0
  104. claude_mpm/commander/memory/example_usage.py +290 -0
  105. claude_mpm/commander/memory/integration.py +325 -0
  106. claude_mpm/commander/memory/search.py +381 -0
  107. claude_mpm/commander/memory/store.py +657 -0
  108. claude_mpm/commander/models/__init__.py +18 -0
  109. claude_mpm/commander/models/events.py +127 -0
  110. claude_mpm/commander/models/project.py +162 -0
  111. claude_mpm/commander/models/work.py +214 -0
  112. claude_mpm/commander/parsing/__init__.py +20 -0
  113. claude_mpm/commander/parsing/extractor.py +132 -0
  114. claude_mpm/commander/parsing/output_parser.py +270 -0
  115. claude_mpm/commander/parsing/patterns.py +100 -0
  116. claude_mpm/commander/persistence/__init__.py +11 -0
  117. claude_mpm/commander/persistence/event_store.py +274 -0
  118. claude_mpm/commander/persistence/state_store.py +403 -0
  119. claude_mpm/commander/persistence/work_store.py +164 -0
  120. claude_mpm/commander/polling/__init__.py +13 -0
  121. claude_mpm/commander/polling/event_detector.py +104 -0
  122. claude_mpm/commander/polling/output_buffer.py +49 -0
  123. claude_mpm/commander/polling/output_poller.py +153 -0
  124. claude_mpm/commander/project_session.py +268 -0
  125. claude_mpm/commander/proxy/__init__.py +12 -0
  126. claude_mpm/commander/proxy/formatter.py +89 -0
  127. claude_mpm/commander/proxy/output_handler.py +191 -0
  128. claude_mpm/commander/proxy/relay.py +155 -0
  129. claude_mpm/commander/registry.py +410 -0
  130. claude_mpm/commander/runtime/__init__.py +10 -0
  131. claude_mpm/commander/runtime/executor.py +191 -0
  132. claude_mpm/commander/runtime/monitor.py +346 -0
  133. claude_mpm/commander/session/__init__.py +6 -0
  134. claude_mpm/commander/session/context.py +81 -0
  135. claude_mpm/commander/session/manager.py +59 -0
  136. claude_mpm/commander/tmux_orchestrator.py +362 -0
  137. claude_mpm/commander/web/__init__.py +1 -0
  138. claude_mpm/commander/work/__init__.py +30 -0
  139. claude_mpm/commander/work/executor.py +207 -0
  140. claude_mpm/commander/work/queue.py +405 -0
  141. claude_mpm/commander/workflow/__init__.py +27 -0
  142. claude_mpm/commander/workflow/event_handler.py +241 -0
  143. claude_mpm/commander/workflow/notifier.py +146 -0
  144. claude_mpm/commands/mpm-config.md +8 -0
  145. claude_mpm/commands/mpm-doctor.md +8 -0
  146. claude_mpm/commands/mpm-help.md +8 -0
  147. claude_mpm/commands/mpm-init.md +8 -0
  148. claude_mpm/commands/mpm-monitor.md +8 -0
  149. claude_mpm/commands/mpm-organize.md +8 -0
  150. claude_mpm/commands/mpm-postmortem.md +8 -0
  151. claude_mpm/commands/mpm-session-resume.md +9 -1
  152. claude_mpm/commands/mpm-status.md +8 -0
  153. claude_mpm/commands/mpm-ticket-view.md +8 -0
  154. claude_mpm/commands/mpm-version.md +8 -0
  155. claude_mpm/commands/mpm.md +8 -0
  156. claude_mpm/config/agent_presets.py +8 -7
  157. claude_mpm/config/skill_sources.py +16 -0
  158. claude_mpm/constants.py +6 -0
  159. claude_mpm/core/claude_runner.py +154 -2
  160. claude_mpm/core/config.py +35 -22
  161. claude_mpm/core/config_constants.py +74 -9
  162. claude_mpm/core/constants.py +56 -12
  163. claude_mpm/core/hook_manager.py +53 -4
  164. claude_mpm/core/interactive_session.py +12 -11
  165. claude_mpm/core/logger.py +26 -9
  166. claude_mpm/core/logging_utils.py +39 -13
  167. claude_mpm/core/network_config.py +148 -0
  168. claude_mpm/core/oneshot_session.py +7 -6
  169. claude_mpm/core/optimized_startup.py +3 -1
  170. claude_mpm/core/output_style_manager.py +66 -18
  171. claude_mpm/core/shared/config_loader.py +3 -1
  172. claude_mpm/core/socketio_pool.py +47 -15
  173. claude_mpm/core/unified_config.py +54 -8
  174. claude_mpm/core/unified_paths.py +95 -90
  175. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  176. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  177. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
  178. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
  179. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
  180. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
  181. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
  182. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
  183. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
  184. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
  185. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  186. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
  187. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uj46x2Wr.js → BSNlmTZj.js} +1 -1
  188. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
  189. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
  190. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
  191. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
  192. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  193. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  194. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
  195. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
  196. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
  197. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
  198. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
  199. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
  200. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
  201. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
  202. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  203. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
  204. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
  205. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
  206. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  207. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
  208. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  209. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
  210. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
  211. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
  212. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
  213. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
  214. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{N4qtv3Hx.js → DR8nis88.js} +2 -2
  215. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
  216. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  217. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
  218. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
  219. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
  220. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
  221. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
  222. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
  223. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  224. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
  225. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  226. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
  227. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DjhvlsAc.js → NqQ1dWOy.js} +1 -1
  228. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
  229. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
  230. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  231. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
  232. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
  233. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
  234. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
  235. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  236. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.CAGBuiOw.js → 0.RgBboRvH.js} +1 -1
  237. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
  238. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  239. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
  240. claude_mpm/dashboard/static/svelte-build/index.html +11 -11
  241. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  242. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  243. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  244. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  245. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  246. claude_mpm/experimental/cli_enhancements.py +2 -1
  247. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  248. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  249. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  250. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  251. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  252. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  253. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  254. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
  255. claude_mpm/hooks/claude_hooks/event_handlers.py +466 -136
  256. claude_mpm/hooks/claude_hooks/hook_handler.py +204 -104
  257. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  258. claude_mpm/hooks/claude_hooks/installer.py +291 -59
  259. claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
  260. claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
  261. claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
  262. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  263. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  264. claude_mpm/hooks/claude_hooks/services/__pycache__/container.cpython-311.pyc +0 -0
  265. claude_mpm/hooks/claude_hooks/services/__pycache__/protocols.cpython-311.pyc +0 -0
  266. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  267. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  268. claude_mpm/hooks/claude_hooks/services/connection_manager.py +41 -26
  269. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
  270. claude_mpm/hooks/claude_hooks/services/container.py +326 -0
  271. claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
  272. claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
  273. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
  274. claude_mpm/hooks/kuzu_memory_hook.py +5 -5
  275. claude_mpm/hooks/session_resume_hook.py +89 -1
  276. claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
  277. claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
  278. claude_mpm/init.py +224 -4
  279. claude_mpm/mcp/__init__.py +9 -0
  280. claude_mpm/mcp/google_workspace_server.py +610 -0
  281. claude_mpm/scripts/claude-hook-handler.sh +46 -19
  282. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  283. claude_mpm/services/agents/agent_selection_service.py +2 -2
  284. claude_mpm/services/agents/cache_git_manager.py +1 -1
  285. claude_mpm/services/agents/deployment/agent_discovery_service.py +3 -1
  286. claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
  287. claude_mpm/services/agents/deployment/agent_template_builder.py +37 -17
  288. claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
  289. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  290. claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
  291. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +36 -8
  292. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +50 -26
  293. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  294. claude_mpm/services/agents/git_source_manager.py +21 -2
  295. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  296. claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
  297. claude_mpm/services/agents/sources/git_source_sync_service.py +116 -5
  298. claude_mpm/services/agents/startup_sync.py +5 -2
  299. claude_mpm/services/cli/__init__.py +3 -0
  300. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  301. claude_mpm/services/cli/session_resume_helper.py +10 -2
  302. claude_mpm/services/command_deployment_service.py +44 -26
  303. claude_mpm/services/delegation_detector.py +175 -0
  304. claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
  305. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  306. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  307. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  308. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  309. claude_mpm/services/diagnostics/models.py +14 -1
  310. claude_mpm/services/event_log.py +325 -0
  311. claude_mpm/services/hook_installer_service.py +77 -8
  312. claude_mpm/services/infrastructure/__init__.py +4 -0
  313. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  314. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  315. claude_mpm/services/mcp_config_manager.py +99 -19
  316. claude_mpm/services/mcp_service_registry.py +294 -0
  317. claude_mpm/services/monitor/daemon_manager.py +15 -4
  318. claude_mpm/services/monitor/management/lifecycle.py +8 -3
  319. claude_mpm/services/monitor/server.py +111 -16
  320. claude_mpm/services/pm_skills_deployer.py +302 -94
  321. claude_mpm/services/profile_manager.py +10 -4
  322. claude_mpm/services/skills/git_skill_source_manager.py +192 -29
  323. claude_mpm/services/skills/selective_skill_deployer.py +211 -46
  324. claude_mpm/services/skills/skill_discovery_service.py +74 -4
  325. claude_mpm/services/skills_deployer.py +192 -70
  326. claude_mpm/services/socketio/handlers/hook.py +14 -7
  327. claude_mpm/services/socketio/server/main.py +12 -4
  328. claude_mpm/skills/__init__.py +2 -1
  329. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  330. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  331. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  332. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  333. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  334. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  335. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  336. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  337. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  338. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  339. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  340. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  341. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  342. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  343. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  344. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  345. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  346. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  347. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  348. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  349. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  350. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  351. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  352. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  353. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  354. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  355. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  356. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  357. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  358. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  359. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  360. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  361. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  362. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  363. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  364. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  365. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  366. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  367. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  368. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  369. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  370. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  371. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  372. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  373. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  374. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  375. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  376. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  377. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  378. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  379. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  380. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  381. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  382. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  383. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  384. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  385. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  386. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  387. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  388. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  389. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  390. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  391. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  392. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  393. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  394. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  395. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  396. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  397. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  398. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  399. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  400. claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
  401. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  402. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  403. claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
  404. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  405. claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
  406. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  407. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  408. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  409. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  410. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  411. claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
  412. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  413. claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
  414. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  415. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  416. claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
  417. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  418. claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
  419. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  420. claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
  421. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  422. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  423. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  424. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  425. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  426. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  427. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  428. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  429. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  430. claude_mpm/skills/bundled/security-scanning.md +112 -0
  431. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  432. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  433. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  434. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  435. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  436. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  437. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  438. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  439. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  440. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  441. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  442. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  443. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  444. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  445. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  446. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  447. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  448. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  449. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  450. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  451. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  452. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  453. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  454. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  455. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  456. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  457. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  458. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  459. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  460. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  461. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  462. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  463. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  464. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  465. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  466. claude_mpm/skills/registry.py +295 -90
  467. claude_mpm/skills/skill_manager.py +29 -23
  468. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  469. claude_mpm/utils/agent_dependency_loader.py +103 -4
  470. claude_mpm/utils/robust_installer.py +45 -24
  471. claude_mpm-5.6.72.dist-info/METADATA +416 -0
  472. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/RECORD +477 -159
  473. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/WHEEL +1 -1
  474. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/entry_points.txt +2 -0
  475. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +0 -1
  476. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +0 -1
  477. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +0 -1
  478. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +0 -1
  479. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +0 -1
  480. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +0 -2
  481. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +0 -2
  482. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +0 -1
  483. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +0 -1
  484. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +0 -10
  485. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  486. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  487. claude_mpm-5.4.41.dist-info/METADATA +0 -998
  488. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/licenses/LICENSE +0 -0
  489. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  490. {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/top_level.txt +0 -0
@@ -688,13 +688,18 @@ class MPMInitCommand:
688
688
  return len(text) // 4
689
689
 
690
690
  def _deploy_pm_skills(self) -> None:
691
- """Deploy PM skills templates to project .claude-mpm directory.
691
+ """Deploy PM skills templates to project .claude directory.
692
692
 
693
- Copies PM skills from bundled templates to .claude-mpm/skills/pm/
693
+ Copies PM skills from bundled templates to .claude/skills/
694
694
  with version tracking and checksum validation.
695
695
  """
696
696
  try:
697
- from rich.progress import BarColumn, Progress, TaskProgressColumn, TextColumn
697
+ from rich.progress import (
698
+ BarColumn,
699
+ Progress,
700
+ TaskProgressColumn,
701
+ TextColumn,
702
+ )
698
703
 
699
704
  from claude_mpm.services.pm_skills_deployer import PMSkillsDeployerService
700
705
 
@@ -711,7 +716,9 @@ class MPMInitCommand:
711
716
  task = progress.add_task("", total=None) # Unknown total initially
712
717
 
713
718
  def update_progress(skill_name: str, current: int, total: int) -> None:
714
- progress.update(task, total=total, completed=current, description=skill_name)
719
+ progress.update(
720
+ task, total=total, completed=current, description=skill_name
721
+ )
715
722
 
716
723
  result = deployer.deploy_pm_skills(
717
724
  self.project_path, progress_callback=update_progress
@@ -729,7 +736,9 @@ class MPMInitCommand:
729
736
  )
730
737
 
731
738
  if result.errors:
732
- self.console.print(f"[yellow]⚠️ {len(result.errors)} errors:[/yellow]")
739
+ self.console.print(
740
+ f"[yellow]⚠️ {len(result.errors)} errors:[/yellow]"
741
+ )
733
742
  for error in result.errors[:3]: # Show first 3 errors
734
743
  self.console.print(f" • {error['skill']}: {error['error']}")
735
744
  else:
@@ -744,9 +753,7 @@ class MPMInitCommand:
744
753
  )
745
754
  except Exception as e:
746
755
  logger.error(f"Failed to deploy PM skills: {e}")
747
- self.console.print(
748
- f"[yellow]⚠️ PM skills deployment failed: {e}[/yellow]"
749
- )
756
+ self.console.print(f"[yellow]⚠️ PM skills deployment failed: {e}[/yellow]")
750
757
 
751
758
 
752
759
  __all__ = ["MPMInitCommand"]
@@ -0,0 +1,481 @@
1
+ """
2
+ OAuth management commands for claude-mpm CLI.
3
+
4
+ WHY: Users need a way to manage OAuth authentication for MCP services
5
+ that require OAuth2 flows (e.g., Google Workspace) directly from the terminal.
6
+
7
+ DESIGN DECISIONS:
8
+ - Use BaseCommand for consistent CLI patterns
9
+ - Reuse OAuth logic from commander/chat/repl.py
10
+ - Support multiple credential sources: .env.local, .env, environment variables
11
+ - Provide clear feedback during OAuth flow
12
+ """
13
+
14
+ import asyncio
15
+ import json
16
+ import os
17
+ from pathlib import Path
18
+ from typing import Any
19
+
20
+ from rich.console import Console
21
+ from rich.panel import Panel
22
+ from rich.table import Table
23
+
24
+ from ..shared import BaseCommand, CommandResult
25
+
26
+ console = Console()
27
+
28
+
29
+ def _load_oauth_credentials_from_env_files() -> tuple[str | None, str | None]:
30
+ """Load OAuth credentials from .env files.
31
+
32
+ Checks .env.local first (user overrides), then .env.
33
+ Returns tuple of (client_id, client_secret), either may be None.
34
+ """
35
+ client_id = None
36
+ client_secret = None
37
+
38
+ # Priority order: .env.local first (user overrides), then .env
39
+ env_files = [".env.local", ".env"]
40
+
41
+ for env_file in env_files:
42
+ env_path = Path.cwd() / env_file
43
+ if env_path.exists():
44
+ try:
45
+ with open(env_path) as f:
46
+ for line in f:
47
+ line = line.strip()
48
+ # Skip empty lines and comments
49
+ if not line or line.startswith("#"):
50
+ continue
51
+ if "=" in line:
52
+ key, _, value = line.partition("=")
53
+ key = key.strip()
54
+ value = value.strip().strip('"').strip("'")
55
+
56
+ if key == "GOOGLE_OAUTH_CLIENT_ID" and not client_id:
57
+ client_id = value
58
+ elif (
59
+ key == "GOOGLE_OAUTH_CLIENT_SECRET"
60
+ and not client_secret
61
+ ):
62
+ client_secret = value
63
+
64
+ # If we found both, no need to check more files
65
+ if client_id and client_secret:
66
+ break
67
+ except Exception: # nosec B110 - intentionally ignore .env file read errors
68
+ pass
69
+
70
+ return client_id, client_secret
71
+
72
+
73
+ class OAuthCommand(BaseCommand):
74
+ """OAuth management command for MCP services."""
75
+
76
+ def __init__(self):
77
+ super().__init__("oauth")
78
+
79
+ def validate_args(self, args) -> str | None:
80
+ """Validate command arguments."""
81
+ # If no oauth_command specified, default to 'list'
82
+ if not hasattr(args, "oauth_command") or not args.oauth_command:
83
+ args.oauth_command = None # Will show help
84
+ return None
85
+
86
+ valid_commands = ["list", "setup", "status", "revoke", "refresh"]
87
+ if args.oauth_command not in valid_commands:
88
+ return f"Unknown oauth command: {args.oauth_command}. Valid commands: {', '.join(valid_commands)}"
89
+
90
+ # Validate service_name for commands that require it
91
+ if args.oauth_command in ["setup", "status", "revoke", "refresh"]:
92
+ if not hasattr(args, "service_name") or not args.service_name:
93
+ return f"oauth {args.oauth_command} requires a service name"
94
+
95
+ return None
96
+
97
+ def run(self, args) -> CommandResult:
98
+ """Execute the OAuth command."""
99
+ # If no subcommand, show help
100
+ if not hasattr(args, "oauth_command") or not args.oauth_command:
101
+ self._show_help()
102
+ return CommandResult.success_result("Help displayed")
103
+
104
+ if args.oauth_command == "list":
105
+ return self._list_services(args)
106
+ if args.oauth_command == "setup":
107
+ return self._setup_oauth(args)
108
+ if args.oauth_command == "status":
109
+ return self._show_status(args)
110
+ if args.oauth_command == "revoke":
111
+ return self._revoke_tokens(args)
112
+ if args.oauth_command == "refresh":
113
+ return self._refresh_tokens(args)
114
+
115
+ return CommandResult.error_result(
116
+ f"Unknown oauth command: {args.oauth_command}"
117
+ )
118
+
119
+ def _show_help(self) -> None:
120
+ """Display OAuth command help."""
121
+ help_text = """
122
+ [bold]OAuth Commands:[/bold]
123
+ oauth list List OAuth-capable MCP services
124
+ oauth setup <service> Set up OAuth authentication for a service
125
+ oauth status <service> Show OAuth token status for a service
126
+ oauth revoke <service> Revoke OAuth tokens for a service
127
+ oauth refresh <service> Refresh OAuth tokens for a service
128
+
129
+ [bold]Examples:[/bold]
130
+ claude-mpm oauth list
131
+ claude-mpm oauth setup workspace-mcp
132
+ claude-mpm oauth status workspace-mcp
133
+ """
134
+ console.print(help_text)
135
+
136
+ def _list_services(self, args) -> CommandResult:
137
+ """List OAuth-capable MCP services."""
138
+ try:
139
+ from claude_mpm.services.mcp_service_registry import MCPServiceRegistry
140
+
141
+ services = MCPServiceRegistry.list_all()
142
+ oauth_services = [s for s in services if s.oauth_provider]
143
+
144
+ if not oauth_services:
145
+ console.print("[yellow]No OAuth-capable services found.[/yellow]")
146
+ return CommandResult.success_result("No OAuth services found")
147
+
148
+ # Check output format
149
+ output_format = getattr(args, "format", "table")
150
+
151
+ if output_format == "json":
152
+ data = [
153
+ {
154
+ "name": s.name,
155
+ "description": s.description,
156
+ "oauth_provider": s.oauth_provider,
157
+ "oauth_scopes": s.oauth_scopes,
158
+ "required_env": s.required_env,
159
+ }
160
+ for s in oauth_services
161
+ ]
162
+ console.print(json.dumps(data, indent=2))
163
+ return CommandResult.success_result(
164
+ "Services listed", data={"services": data}
165
+ )
166
+
167
+ # Table format
168
+ table = Table(title="OAuth-Capable MCP Services")
169
+ table.add_column("Service", style="cyan")
170
+ table.add_column("Provider", style="green")
171
+ table.add_column("Description", style="white")
172
+
173
+ for service in oauth_services:
174
+ table.add_row(
175
+ service.name,
176
+ service.oauth_provider or "",
177
+ service.description,
178
+ )
179
+
180
+ console.print(table)
181
+ return CommandResult.success_result(
182
+ f"Found {len(oauth_services)} OAuth-capable service(s)"
183
+ )
184
+
185
+ except ImportError:
186
+ return CommandResult.error_result("MCP Service Registry not available")
187
+ except Exception as e:
188
+ return CommandResult.error_result(f"Error listing services: {e}")
189
+
190
+ def _setup_oauth(self, args) -> CommandResult:
191
+ """Set up OAuth for a service."""
192
+ service_name = args.service_name
193
+
194
+ # Get service info from registry to get provider and scopes
195
+ try:
196
+ from claude_mpm.services.mcp_service_registry import MCPServiceRegistry
197
+
198
+ service = MCPServiceRegistry.get(service_name)
199
+ if not service:
200
+ return CommandResult.error_result(f"Service '{service_name}' not found")
201
+
202
+ provider_name = service.oauth_provider
203
+ if not provider_name:
204
+ return CommandResult.error_result(
205
+ f"Service '{service_name}' does not use OAuth"
206
+ )
207
+
208
+ scopes = service.oauth_scopes or None
209
+ except ImportError:
210
+ return CommandResult.error_result("MCP Service Registry not available")
211
+
212
+ # Priority: 1) .env files, 2) environment variables, 3) interactive prompt
213
+ client_id, client_secret = _load_oauth_credentials_from_env_files()
214
+
215
+ # Fall back to environment variables if not found in .env files
216
+ if not client_id:
217
+ client_id = os.environ.get("GOOGLE_OAUTH_CLIENT_ID")
218
+ if not client_secret:
219
+ client_secret = os.environ.get("GOOGLE_OAUTH_CLIENT_SECRET")
220
+
221
+ # Set credentials in environment so OAuth provider can access them
222
+ if client_id and client_secret:
223
+ os.environ["GOOGLE_OAUTH_CLIENT_ID"] = client_id
224
+ os.environ["GOOGLE_OAUTH_CLIENT_SECRET"] = client_secret
225
+
226
+ # If credentials missing, prompt for them interactively
227
+ if not client_id or not client_secret:
228
+ console.print("\n[yellow]Google OAuth credentials not found.[/yellow]")
229
+ console.print("Checked: .env.local, .env, and environment variables.\n")
230
+ console.print(
231
+ "Get credentials from: https://console.cloud.google.com/apis/credentials\n"
232
+ )
233
+ console.print("[dim]Tip: Add to .env.local for automatic loading:[/dim]")
234
+ console.print('[dim] GOOGLE_OAUTH_CLIENT_ID="your-client-id"[/dim]')
235
+ console.print(
236
+ '[dim] GOOGLE_OAUTH_CLIENT_SECRET="your-client-secret"[/dim]\n' # pragma: allowlist secret
237
+ )
238
+
239
+ try:
240
+ from prompt_toolkit import prompt as pt_prompt
241
+
242
+ client_id = pt_prompt("Enter GOOGLE_OAUTH_CLIENT_ID: ")
243
+ if not client_id.strip():
244
+ return CommandResult.error_result("Client ID is required")
245
+
246
+ client_secret = pt_prompt(
247
+ "Enter GOOGLE_OAUTH_CLIENT_SECRET: ", is_password=True
248
+ )
249
+ if not client_secret.strip():
250
+ return CommandResult.error_result("Client Secret is required")
251
+
252
+ # Set in environment for this session
253
+ os.environ["GOOGLE_OAUTH_CLIENT_ID"] = client_id.strip()
254
+ os.environ["GOOGLE_OAUTH_CLIENT_SECRET"] = client_secret.strip()
255
+ console.print("\n[green]Credentials set for this session.[/green]")
256
+
257
+ except (EOFError, KeyboardInterrupt):
258
+ return CommandResult.error_result("Credential entry cancelled")
259
+ except ImportError:
260
+ return CommandResult.error_result(
261
+ "prompt_toolkit not available for interactive input. "
262
+ "Please set GOOGLE_OAUTH_CLIENT_ID and GOOGLE_OAUTH_CLIENT_SECRET environment variables."
263
+ )
264
+
265
+ # Run OAuth flow
266
+ try:
267
+ from claude_mpm.auth import OAuthManager
268
+ from claude_mpm.auth.callback_server import DEFAULT_PORT
269
+ from claude_mpm.auth.providers.google import OAuthError
270
+
271
+ manager = OAuthManager()
272
+
273
+ # Get the actual callback port from the server
274
+ callback_port = DEFAULT_PORT
275
+ no_browser = getattr(args, "no_browser", False)
276
+
277
+ console.print(f"\n[cyan]Setting up OAuth for '{service_name}'...[/cyan]")
278
+ console.print(
279
+ f"Callback server listening on http://localhost:{callback_port}/callback"
280
+ )
281
+
282
+ if not no_browser:
283
+ console.print("Opening browser for authentication...")
284
+ else:
285
+ console.print(
286
+ "[yellow]Browser auto-open disabled. Please open the URL manually.[/yellow]"
287
+ )
288
+
289
+ # Run async OAuth flow - authenticate returns OAuthToken directly
290
+ # and raises OAuthError on failure
291
+ token = asyncio.run(
292
+ manager.authenticate(
293
+ service_name=service_name,
294
+ provider_name=provider_name,
295
+ scopes=scopes,
296
+ open_browser=not no_browser,
297
+ )
298
+ )
299
+
300
+ # Success - token was returned
301
+ console.print(f"\n[green]OAuth setup complete for '{service_name}'[/green]")
302
+ if token.expires_at:
303
+ console.print(f" Token expires: {token.expires_at}")
304
+ return CommandResult.success_result(
305
+ f"OAuth setup complete for '{service_name}'"
306
+ )
307
+
308
+ except OAuthError as e:
309
+ return CommandResult.error_result(f"OAuth setup failed: {e}")
310
+ except ImportError as e:
311
+ return CommandResult.error_result(f"OAuth module not available: {e}")
312
+ except Exception as e:
313
+ return CommandResult.error_result(f"Error during OAuth setup: {e}")
314
+
315
+ def _show_status(self, args) -> CommandResult:
316
+ """Show OAuth token status for a service."""
317
+ service_name = args.service_name
318
+
319
+ try:
320
+ from claude_mpm.auth import OAuthManager
321
+ from claude_mpm.auth.models import TokenStatus
322
+
323
+ manager = OAuthManager()
324
+ # get_status is synchronous and returns (TokenStatus, StoredToken | None)
325
+ token_status, stored_token = manager.get_status(service_name)
326
+
327
+ if token_status == TokenStatus.MISSING or stored_token is None:
328
+ console.print(
329
+ f"[yellow]No OAuth tokens found for '{service_name}'[/yellow]"
330
+ )
331
+ return CommandResult.success_result(
332
+ f"No tokens found for '{service_name}'"
333
+ )
334
+
335
+ # Build status dict for display
336
+ is_valid = token_status == TokenStatus.VALID
337
+ status_data = {
338
+ "valid": is_valid,
339
+ "status": token_status.name,
340
+ "expires_at": stored_token.token.expires_at,
341
+ "scopes": stored_token.token.scopes,
342
+ }
343
+
344
+ # Check output format
345
+ output_format = getattr(args, "format", "table")
346
+
347
+ if output_format == "json":
348
+ console.print(json.dumps(status_data, indent=2, default=str))
349
+ return CommandResult.success_result(
350
+ "Status displayed", data=status_data
351
+ )
352
+
353
+ # Table format
354
+ self._print_token_status(service_name, status_data)
355
+ return CommandResult.success_result("Status displayed")
356
+
357
+ except ImportError:
358
+ return CommandResult.error_result("OAuth module not available")
359
+ except Exception as e:
360
+ return CommandResult.error_result(f"Error checking status: {e}")
361
+
362
+ def _print_token_status(self, name: str, status: dict[str, Any]) -> None:
363
+ """Print token status information."""
364
+ panel_content = []
365
+ panel_content.append(f"[bold]Service:[/bold] {name}")
366
+ panel_content.append("[bold]Stored:[/bold] Yes")
367
+
368
+ if status.get("valid"):
369
+ panel_content.append("[bold]Status:[/bold] [green]Valid[/green]")
370
+ else:
371
+ panel_content.append("[bold]Status:[/bold] [red]Invalid/Expired[/red]")
372
+
373
+ if status.get("expires_at"):
374
+ panel_content.append(f"[bold]Expires:[/bold] {status['expires_at']}")
375
+
376
+ if status.get("scopes"):
377
+ scopes = ", ".join(status["scopes"])
378
+ panel_content.append(f"[bold]Scopes:[/bold] {scopes}")
379
+
380
+ panel = Panel(
381
+ "\n".join(panel_content),
382
+ title="OAuth Token Status",
383
+ border_style="green" if status.get("valid") else "red",
384
+ )
385
+ console.print(panel)
386
+
387
+ def _revoke_tokens(self, args) -> CommandResult:
388
+ """Revoke OAuth tokens for a service."""
389
+ service_name = args.service_name
390
+
391
+ # Confirm unless -y flag
392
+ if not getattr(args, "yes", False):
393
+ console.print(
394
+ f"[yellow]This will revoke OAuth tokens for '{service_name}'.[/yellow]"
395
+ )
396
+ try:
397
+ from prompt_toolkit import prompt as pt_prompt
398
+
399
+ confirm = pt_prompt("Are you sure? (y/N): ")
400
+ if confirm.lower() not in ("y", "yes"):
401
+ return CommandResult.success_result("Revocation cancelled")
402
+ except (EOFError, KeyboardInterrupt):
403
+ return CommandResult.success_result("Revocation cancelled")
404
+ except ImportError:
405
+ # No prompt_toolkit, proceed without confirmation
406
+ pass
407
+
408
+ try:
409
+ from claude_mpm.auth import OAuthManager
410
+
411
+ manager = OAuthManager()
412
+
413
+ console.print(f"[cyan]Revoking OAuth tokens for '{service_name}'...[/cyan]")
414
+ # revoke() returns bool directly
415
+ revoked = asyncio.run(manager.revoke(service_name))
416
+
417
+ if revoked:
418
+ console.print(
419
+ f"[green]OAuth tokens revoked for '{service_name}'[/green]"
420
+ )
421
+ return CommandResult.success_result(
422
+ f"Tokens revoked for '{service_name}'"
423
+ )
424
+ return CommandResult.error_result(
425
+ f"Failed to revoke tokens for '{service_name}'"
426
+ )
427
+
428
+ except ImportError:
429
+ return CommandResult.error_result("OAuth module not available")
430
+ except Exception as e:
431
+ return CommandResult.error_result(f"Error revoking tokens: {e}")
432
+
433
+ def _refresh_tokens(self, args) -> CommandResult:
434
+ """Refresh OAuth tokens for a service."""
435
+ service_name = args.service_name
436
+
437
+ try:
438
+ from claude_mpm.auth import OAuthManager
439
+ from claude_mpm.auth.providers.google import OAuthError
440
+
441
+ manager = OAuthManager()
442
+
443
+ console.print(
444
+ f"[cyan]Refreshing OAuth tokens for '{service_name}'...[/cyan]"
445
+ )
446
+ # refresh_if_needed() returns Optional[OAuthToken]
447
+ token = asyncio.run(manager.refresh_if_needed(service_name))
448
+
449
+ if token is not None:
450
+ console.print(
451
+ f"[green]OAuth tokens refreshed for '{service_name}'[/green]"
452
+ )
453
+ if token.expires_at:
454
+ console.print(f" New expiry: {token.expires_at}")
455
+ return CommandResult.success_result(
456
+ f"Tokens refreshed for '{service_name}'"
457
+ )
458
+ return CommandResult.error_result(
459
+ f"Failed to refresh tokens for '{service_name}' - no token found or no refresh token available"
460
+ )
461
+
462
+ except OAuthError as e:
463
+ return CommandResult.error_result(f"Failed to refresh: {e}")
464
+ except ImportError:
465
+ return CommandResult.error_result("OAuth module not available")
466
+ except Exception as e:
467
+ return CommandResult.error_result(f"Error refreshing tokens: {e}")
468
+
469
+
470
+ def manage_oauth(args) -> int:
471
+ """Main entry point for OAuth management commands.
472
+
473
+ Args:
474
+ args: Parsed command line arguments
475
+
476
+ Returns:
477
+ Exit code (0 for success, non-zero for errors)
478
+ """
479
+ command = OAuthCommand()
480
+ result = command.execute(args)
481
+ return result.exit_code
@@ -13,10 +13,8 @@ DESIGN DECISIONS:
13
13
  """
14
14
 
15
15
  from pathlib import Path
16
- from typing import Any, Dict
17
16
 
18
17
  import yaml
19
- from rich.console import Console
20
18
  from rich.table import Table
21
19
 
22
20
  from ...core.shared.config_loader import ConfigLoader
@@ -63,16 +61,15 @@ class ProfileCommand(BaseCommand):
63
61
  try:
64
62
  if args.profile_command == "list":
65
63
  return self._list_profiles(args)
66
- elif args.profile_command == "set":
64
+ if args.profile_command == "set":
67
65
  return self._set_profile(args)
68
- elif args.profile_command == "status":
66
+ if args.profile_command == "status":
69
67
  return self._show_status(args)
70
- elif args.profile_command == "show":
68
+ if args.profile_command == "show":
71
69
  return self._show_profile(args)
72
- else:
73
- return CommandResult.error_result(
74
- f"Unknown profile command: {args.profile_command}"
75
- )
70
+ return CommandResult.error_result(
71
+ f"Unknown profile command: {args.profile_command}"
72
+ )
76
73
  except Exception as e:
77
74
  return CommandResult.error_result(f"Profile command failed: {e}")
78
75
 
@@ -145,7 +142,9 @@ class ProfileCommand(BaseCommand):
145
142
 
146
143
  # Show summary
147
144
  summary = self.profile_manager.get_filtering_summary()
148
- console.print(f"[green]✓[/green] Active profile set to: [cyan]{profile_name}[/cyan]")
145
+ console.print(
146
+ f"[green]✓[/green] Active profile set to: [cyan]{profile_name}[/cyan]"
147
+ )
149
148
  console.print(
150
149
  f" Agents enabled: [cyan]{summary['enabled_agents_count']}[/cyan]"
151
150
  )
@@ -13,7 +13,7 @@ DESIGN DECISIONS:
13
13
  - Support multiple output formats (json, yaml, table, text)
14
14
  """
15
15
 
16
- import subprocess
16
+ import subprocess # nosec B404 - required for process management
17
17
  import sys
18
18
  from datetime import datetime, timezone
19
19
  from typing import Optional
@@ -489,6 +489,18 @@ class RunCommand(BaseCommand):
489
489
  if hasattr(args, "claude_args") and args.claude_args:
490
490
  claude_args.extend(args.claude_args)
491
491
 
492
+ # Add --resume if flag is set
493
+ if getattr(args, "resume", False) and "--resume" not in claude_args:
494
+ claude_args.insert(0, "--resume")
495
+
496
+ # Add --chrome if flag is set
497
+ if getattr(args, "chrome", False) and "--chrome" not in claude_args:
498
+ claude_args.insert(0, "--chrome")
499
+
500
+ # Add --no-chrome if flag is set
501
+ if getattr(args, "no_chrome", False) and "--no-chrome" not in claude_args:
502
+ claude_args.insert(0, "--no-chrome")
503
+
492
504
  # Create runner
493
505
  runner = ClaudeRunner(
494
506
  enable_tickets=enable_tickets,
@@ -553,7 +565,7 @@ class RunCommand(BaseCommand):
553
565
  wrapper_path = get_scripts_dir() / "interactive_wrapper.py"
554
566
  if wrapper_path.exists():
555
567
  print("Starting interactive session with command interception...")
556
- subprocess.run([sys.executable, str(wrapper_path)], check=False)
568
+ subprocess.run([sys.executable, str(wrapper_path)], check=False) # nosec B603 - trusted internal paths
557
569
  else:
558
570
  self.logger.warning(
559
571
  "Interactive wrapper not found, falling back to normal mode"
@@ -907,6 +919,26 @@ def run_session_legacy(args):
907
919
  else:
908
920
  logger.info("[INFO]️ --resume already in claude_args")
909
921
 
922
+ # Add --chrome to claude_args if the flag is set
923
+ chrome_flag_present = getattr(args, "chrome", False)
924
+ if chrome_flag_present:
925
+ logger.info("📌 --chrome flag detected in args")
926
+ if "--chrome" not in raw_claude_args:
927
+ raw_claude_args = ["--chrome", *raw_claude_args]
928
+ logger.info("✅ Added --chrome to claude_args")
929
+ else:
930
+ logger.info("ℹ️ --chrome already in claude_args")
931
+
932
+ # Add --no-chrome to claude_args if the flag is set
933
+ no_chrome_flag_present = getattr(args, "no_chrome", False)
934
+ if no_chrome_flag_present:
935
+ logger.info("📌 --no-chrome flag detected in args")
936
+ if "--no-chrome" not in raw_claude_args:
937
+ raw_claude_args = ["--no-chrome", *raw_claude_args]
938
+ logger.info("✅ Added --no-chrome to claude_args")
939
+ else:
940
+ logger.info("ℹ️ --no-chrome already in claude_args")
941
+
910
942
  # Filter out claude-mpm specific flags before passing to Claude CLI
911
943
  logger.debug(f"Pre-filter claude_args: {raw_claude_args}")
912
944
  claude_args = filter_claude_mpm_args(raw_claude_args)
@@ -1044,7 +1076,7 @@ def run_session_legacy(args):
1044
1076
  wrapper_path = get_scripts_dir() / "interactive_wrapper.py"
1045
1077
  if wrapper_path.exists():
1046
1078
  print("Starting interactive session with command interception...")
1047
- subprocess.run([sys.executable, str(wrapper_path)], check=False)
1079
+ subprocess.run([sys.executable, str(wrapper_path)], check=False) # nosec B603 - trusted internal paths
1048
1080
  else:
1049
1081
  logger.warning("Interactive wrapper not found, falling back to normal mode")
1050
1082
  runner.run_interactive(context)