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,294 @@
1
+ """MCP Service Registry for claude-mpm.
2
+
3
+ This module provides a registry of known MCP services with their
4
+ installation, configuration, and runtime requirements.
5
+
6
+ WHY: Centralizes MCP service definitions to enable enable/disable/list
7
+ operations with automatic configuration generation.
8
+ """
9
+
10
+ from dataclasses import dataclass, field
11
+ from enum import Enum
12
+ from typing import ClassVar
13
+
14
+
15
+ class InstallMethod(str, Enum):
16
+ """Installation method for MCP services."""
17
+
18
+ UVX = "uvx"
19
+ PIPX = "pipx"
20
+ NPX = "npx"
21
+ PIP = "pip"
22
+
23
+
24
+ @dataclass(frozen=True)
25
+ class MCPServiceDefinition:
26
+ """Definition of an MCP service with all configuration requirements.
27
+
28
+ Attributes:
29
+ name: Unique service identifier (e.g., "kuzu-memory")
30
+ package: PyPI/npm package name for installation
31
+ install_method: How to install (uvx, pipx, npx, pip)
32
+ command: Command to run the service
33
+ args: Default command arguments
34
+ required_env: Environment variables that must be set
35
+ optional_env: Environment variables that may be set
36
+ description: Human-readable description
37
+ env_defaults: Default values for optional env vars
38
+ enabled_by_default: Whether service is enabled by default
39
+ """
40
+
41
+ name: str
42
+ package: str
43
+ install_method: InstallMethod
44
+ command: str
45
+ args: list[str] = field(default_factory=list)
46
+ required_env: list[str] = field(default_factory=list)
47
+ optional_env: list[str] = field(default_factory=list)
48
+ description: str = ""
49
+ env_defaults: dict[str, str] = field(default_factory=dict)
50
+ enabled_by_default: bool = False
51
+ oauth_provider: str | None = None # "google", "microsoft", etc.
52
+ oauth_scopes: list[str] = field(default_factory=list) # OAuth scopes if applicable
53
+
54
+
55
+ class MCPServiceRegistry:
56
+ """Registry of known MCP services.
57
+
58
+ Provides service lookup, configuration generation, and
59
+ enable/disable state management.
60
+ """
61
+
62
+ # Registry of all known MCP services
63
+ SERVICES: ClassVar[dict[str, MCPServiceDefinition]] = {}
64
+
65
+ @classmethod
66
+ def register(cls, service: MCPServiceDefinition) -> None:
67
+ """Register a service definition."""
68
+ cls.SERVICES[service.name] = service
69
+
70
+ @classmethod
71
+ def get(cls, name: str) -> MCPServiceDefinition | None:
72
+ """Get a service definition by name."""
73
+ return cls.SERVICES.get(name)
74
+
75
+ @classmethod
76
+ def list_all(cls) -> list[MCPServiceDefinition]:
77
+ """List all registered services."""
78
+ return list(cls.SERVICES.values())
79
+
80
+ @classmethod
81
+ def list_names(cls) -> list[str]:
82
+ """List all registered service names."""
83
+ return list(cls.SERVICES.keys())
84
+
85
+ @classmethod
86
+ def exists(cls, name: str) -> bool:
87
+ """Check if a service exists in the registry."""
88
+ return name in cls.SERVICES
89
+
90
+ @classmethod
91
+ def get_default_enabled(cls) -> list[MCPServiceDefinition]:
92
+ """Get services that are enabled by default."""
93
+ return [s for s in cls.SERVICES.values() if s.enabled_by_default]
94
+
95
+ @classmethod
96
+ def generate_config(
97
+ cls,
98
+ service: MCPServiceDefinition,
99
+ env_overrides: dict[str, str] | None = None,
100
+ ) -> dict:
101
+ """Generate MCP configuration for a service.
102
+
103
+ Args:
104
+ service: The service definition
105
+ env_overrides: Environment variable overrides
106
+
107
+ Returns:
108
+ Configuration dict suitable for .mcp.json or ~/.claude.json
109
+ """
110
+ env = {}
111
+
112
+ # Add required env vars (must be provided or have defaults)
113
+ for var in service.required_env:
114
+ if env_overrides and var in env_overrides:
115
+ env[var] = env_overrides[var]
116
+ elif var in service.env_defaults:
117
+ env[var] = service.env_defaults[var]
118
+ # If required and not provided, leave it out - caller should validate
119
+
120
+ # Add optional env vars if provided or have defaults
121
+ for var in service.optional_env:
122
+ if env_overrides and var in env_overrides:
123
+ env[var] = env_overrides[var]
124
+ elif var in service.env_defaults:
125
+ env[var] = service.env_defaults[var]
126
+
127
+ config: dict = {
128
+ "command": service.command,
129
+ "args": service.args.copy(),
130
+ }
131
+
132
+ if env:
133
+ config["env"] = env
134
+
135
+ return config
136
+
137
+ @classmethod
138
+ def validate_env(
139
+ cls, service: MCPServiceDefinition, env: dict[str, str]
140
+ ) -> tuple[bool, list[str]]:
141
+ """Validate that all required env vars are provided.
142
+
143
+ Args:
144
+ service: The service definition
145
+ env: Environment variables to validate
146
+
147
+ Returns:
148
+ Tuple of (is_valid, list of missing required vars)
149
+ """
150
+ missing = []
151
+ for var in service.required_env:
152
+ if var not in env and var not in service.env_defaults:
153
+ missing.append(var)
154
+ return len(missing) == 0, missing
155
+
156
+
157
+ # ============================================================================
158
+ # Service Definitions
159
+ # ============================================================================
160
+
161
+ # KuzuMemory - Project memory and context management
162
+ KUZU_MEMORY = MCPServiceDefinition(
163
+ name="kuzu-memory",
164
+ package="kuzu-memory",
165
+ install_method=InstallMethod.UVX,
166
+ command="uvx",
167
+ args=["kuzu-memory"],
168
+ required_env=[],
169
+ optional_env=["KUZU_DB_PATH", "KUZU_LOG_LEVEL"],
170
+ description="Project memory and context management with graph database",
171
+ env_defaults={},
172
+ enabled_by_default=True,
173
+ )
174
+
175
+ # MCP Ticketer - Ticket and project management
176
+ MCP_TICKETER = MCPServiceDefinition(
177
+ name="mcp-ticketer",
178
+ package="mcp-ticketer",
179
+ install_method=InstallMethod.UVX,
180
+ command="uvx",
181
+ args=["mcp-ticketer"],
182
+ required_env=[],
183
+ optional_env=["TICKETER_BACKEND", "GITHUB_TOKEN", "LINEAR_API_KEY"],
184
+ description="Ticket and project management integration",
185
+ env_defaults={},
186
+ enabled_by_default=True,
187
+ )
188
+
189
+ # MCP Vector Search - Code semantic search
190
+ MCP_VECTOR_SEARCH = MCPServiceDefinition(
191
+ name="mcp-vector-search",
192
+ package="mcp-vector-search",
193
+ install_method=InstallMethod.UVX,
194
+ command="uvx",
195
+ args=["mcp-vector-search"],
196
+ required_env=[],
197
+ optional_env=["VECTOR_SEARCH_INDEX_PATH"],
198
+ description="Semantic code search with vector embeddings",
199
+ env_defaults={},
200
+ enabled_by_default=True,
201
+ )
202
+
203
+ # Google Workspace MCP - Google Drive, Docs, Sheets integration
204
+ # Package: https://pypi.org/project/workspace-mcp/
205
+ GOOGLE_WORKSPACE_MCP = MCPServiceDefinition(
206
+ name="workspace-mcp",
207
+ package="workspace-mcp",
208
+ install_method=InstallMethod.UVX,
209
+ command="uvx",
210
+ args=["workspace-mcp", "--tool-tier", "core"],
211
+ required_env=["GOOGLE_OAUTH_CLIENT_ID", "GOOGLE_OAUTH_CLIENT_SECRET"],
212
+ optional_env=[
213
+ "OAUTHLIB_INSECURE_TRANSPORT",
214
+ "USER_GOOGLE_EMAIL",
215
+ "GOOGLE_PSE_API_KEY",
216
+ "GOOGLE_PSE_ENGINE_ID",
217
+ ],
218
+ description="Google Workspace integration (Gmail, Calendar, Drive, Docs, Sheets, Slides)",
219
+ env_defaults={"OAUTHLIB_INSECURE_TRANSPORT": "1"},
220
+ enabled_by_default=False,
221
+ oauth_provider="google",
222
+ oauth_scopes=[
223
+ "openid",
224
+ "email",
225
+ "profile",
226
+ "https://www.googleapis.com/auth/gmail.modify",
227
+ "https://www.googleapis.com/auth/calendar",
228
+ "https://www.googleapis.com/auth/drive",
229
+ "https://www.googleapis.com/auth/documents",
230
+ "https://www.googleapis.com/auth/spreadsheets",
231
+ ],
232
+ )
233
+
234
+ # MCP GitHub - GitHub repository integration (future)
235
+ MCP_GITHUB = MCPServiceDefinition(
236
+ name="mcp-github",
237
+ package="@modelcontextprotocol/server-github",
238
+ install_method=InstallMethod.NPX,
239
+ command="npx",
240
+ args=["-y", "@modelcontextprotocol/server-github"],
241
+ required_env=["GITHUB_PERSONAL_ACCESS_TOKEN"],
242
+ optional_env=[],
243
+ description="GitHub repository integration",
244
+ env_defaults={},
245
+ enabled_by_default=False,
246
+ )
247
+
248
+ # MCP Filesystem - Local filesystem access (future)
249
+ MCP_FILESYSTEM = MCPServiceDefinition(
250
+ name="mcp-filesystem",
251
+ package="@modelcontextprotocol/server-filesystem",
252
+ install_method=InstallMethod.NPX,
253
+ command="npx",
254
+ args=["-y", "@modelcontextprotocol/server-filesystem"],
255
+ required_env=[],
256
+ optional_env=["FILESYSTEM_ROOT_PATH"],
257
+ description="Local filesystem access and management",
258
+ env_defaults={},
259
+ enabled_by_default=False,
260
+ )
261
+
262
+ # MCP Skillset - Skills and knowledge management
263
+ MCP_SKILLSET = MCPServiceDefinition(
264
+ name="mcp-skillset",
265
+ package="mcp-skillset",
266
+ install_method=InstallMethod.UVX,
267
+ command="uvx",
268
+ args=["mcp-skillset"],
269
+ required_env=[],
270
+ optional_env=["SKILLSET_PATH", "SKILLSET_LOG_LEVEL"],
271
+ description="Skills and knowledge management for Claude",
272
+ env_defaults={},
273
+ enabled_by_default=True,
274
+ )
275
+
276
+
277
+ # Register all services
278
+ def _register_builtin_services() -> None:
279
+ """Register all built-in service definitions."""
280
+ services = [
281
+ KUZU_MEMORY,
282
+ MCP_TICKETER,
283
+ MCP_VECTOR_SEARCH,
284
+ GOOGLE_WORKSPACE_MCP,
285
+ MCP_GITHUB,
286
+ MCP_FILESYSTEM,
287
+ MCP_SKILLSET,
288
+ ]
289
+ for service in services:
290
+ MCPServiceRegistry.register(service)
291
+
292
+
293
+ # Auto-register on module import
294
+ _register_builtin_services()
@@ -95,10 +95,10 @@ class DaemonManager:
95
95
  def _get_default_log_file(self) -> Path:
96
96
  """Get default log file path with port number to support multiple daemons."""
97
97
  project_root = Path.cwd()
98
- claude_mpm_dir = project_root / ".claude-mpm"
99
- claude_mpm_dir.mkdir(exist_ok=True)
98
+ logs_dir = project_root / ".claude-mpm" / "logs"
99
+ logs_dir.mkdir(parents=True, exist_ok=True)
100
100
  # Include port in filename to support multiple daemon instances
101
- return claude_mpm_dir / f"monitor-daemon-{self.port}.log"
101
+ return logs_dir / f"monitor-daemon-{self.port}.log"
102
102
 
103
103
  def cleanup_port_conflicts(self, max_retries: int = 3) -> bool:
104
104
  """Clean up any processes using the daemon port.
@@ -649,14 +649,24 @@ class DaemonManager:
649
649
 
650
650
  # Wait for the subprocess to write its PID file and bind to port
651
651
  # The subprocess will write the PID file after it starts successfully
652
- max_wait = 10 # seconds
652
+ # Allow configuration via environment variable (default 30s to account for agent/skill sync)
653
+ max_wait = int(os.environ.get("CLAUDE_MPM_MONITOR_TIMEOUT", "30"))
653
654
  start_time = time.time()
654
655
  pid_file_found = False
655
656
  port_bound = False
657
+ last_progress_log = 0.0
656
658
 
657
659
  self.logger.debug(f"Waiting up to {max_wait}s for daemon to start...")
658
660
 
659
661
  while time.time() - start_time < max_wait:
662
+ # Log progress every 5 seconds to show we're waiting
663
+ elapsed = time.time() - start_time
664
+ if elapsed - last_progress_log >= 5.0:
665
+ self.logger.info(
666
+ f"Waiting for monitor daemon... ({int(elapsed)}s elapsed, syncing agents/skills)"
667
+ )
668
+ last_progress_log = elapsed
669
+
660
670
  # Check if process is still running
661
671
  returncode = process.poll()
662
672
  if returncode is not None:
@@ -976,6 +986,7 @@ class DaemonManager:
976
986
  os.dup2(null_in.fileno(), sys.stdin.fileno())
977
987
 
978
988
  # Redirect stdout and stderr to log file
989
+ # Ensure logs directory exists
979
990
  self.log_file.parent.mkdir(parents=True, exist_ok=True)
980
991
  with self.log_file.open("a") as log_out:
981
992
  os.dup2(log_out.fileno(), sys.stdout.fileno())
@@ -128,12 +128,16 @@ class DaemonLifecycle:
128
128
  # Redirect stdout and stderr
129
129
  if self.log_file:
130
130
  # Redirect to log file
131
+ # Ensure logs directory exists
132
+ self.log_file.parent.mkdir(parents=True, exist_ok=True)
131
133
  with self.log_file.open("a") as log_out:
132
134
  os.dup2(log_out.fileno(), sys.stdout.fileno())
133
135
  os.dup2(log_out.fileno(), sys.stderr.fileno())
134
136
  else:
135
137
  # Default to a daemon log file instead of /dev/null for errors
136
- default_log = Path.home() / ".claude-mpm" / "monitor-daemon.log"
138
+ default_log = (
139
+ Path.home() / ".claude-mpm" / "logs" / "monitor-daemon.log"
140
+ )
137
141
  default_log.parent.mkdir(parents=True, exist_ok=True)
138
142
  with default_log.open("a") as log_out:
139
143
  os.dup2(log_out.fileno(), sys.stdout.fileno())
@@ -475,7 +479,9 @@ class DaemonLifecycle:
475
479
  try:
476
480
  # If no log file specified, create a default one
477
481
  if not self.log_file:
478
- default_log = Path.home() / ".claude-mpm" / "monitor-daemon.log"
482
+ default_log = (
483
+ Path.home() / ".claude-mpm" / "logs" / "monitor-daemon.log"
484
+ )
479
485
  default_log.parent.mkdir(parents=True, exist_ok=True)
480
486
  self.log_file = default_log
481
487
 
@@ -368,6 +368,83 @@ class UnifiedMonitorServer:
368
368
  finally:
369
369
  await self._cleanup_async()
370
370
 
371
+ def _categorize_event(self, event_name: str) -> str:
372
+ """Categorize event by name to determine Socket.IO event type.
373
+
374
+ Maps specific event names to their category for frontend filtering.
375
+
376
+ Args:
377
+ event_name: The raw event name (e.g., "subagent_start", "todo_updated")
378
+
379
+ Returns:
380
+ Category name (e.g., "hook_event", "system_event")
381
+ """
382
+ # Hook events - agent lifecycle and todo updates
383
+ if event_name in ("subagent_start", "subagent_stop", "todo_updated"):
384
+ return "hook_event"
385
+
386
+ # Tool events - both hook-style and direct tool events
387
+ if event_name in (
388
+ "pre_tool",
389
+ "post_tool",
390
+ "tool.start",
391
+ "tool.end",
392
+ "tool_use",
393
+ "tool_result",
394
+ ):
395
+ return "tool_event"
396
+
397
+ # Session events - session lifecycle
398
+ if event_name in (
399
+ "session.started",
400
+ "session.ended",
401
+ "session_start",
402
+ "session_end",
403
+ ):
404
+ return "session_event"
405
+
406
+ # Response events - API response lifecycle
407
+ if event_name in (
408
+ "response.start",
409
+ "response.end",
410
+ "response_started",
411
+ "response_ended",
412
+ ):
413
+ return "response_event"
414
+
415
+ # Agent events - agent delegation and returns
416
+ if event_name in (
417
+ "agent.delegated",
418
+ "agent.returned",
419
+ "agent_start",
420
+ "agent_end",
421
+ ):
422
+ return "agent_event"
423
+
424
+ # File events - file operations
425
+ if event_name in (
426
+ "file.read",
427
+ "file.write",
428
+ "file.edit",
429
+ "file_read",
430
+ "file_write",
431
+ ):
432
+ return "file_event"
433
+
434
+ # Claude API events
435
+ if event_name in ("user_prompt", "assistant_message"):
436
+ return "claude_event"
437
+
438
+ # System events
439
+ if event_name in ("system_ready", "system_shutdown"):
440
+ return "system_event"
441
+
442
+ # Log uncategorized events for debugging
443
+ self.logger.debug(f"Uncategorized event: {event_name}")
444
+
445
+ # Default to claude_event for unknown events
446
+ return "claude_event"
447
+
371
448
  def _setup_event_handlers(self):
372
449
  """Setup Socket.IO event handlers."""
373
450
  try:
@@ -474,7 +551,7 @@ class UnifiedMonitorServer:
474
551
  )
475
552
  if version_file.exists():
476
553
  version = version_file.read_text().strip()
477
- except Exception:
554
+ except Exception: # nosec B110
478
555
  pass
479
556
 
480
557
  return web.json_response(
@@ -499,10 +576,28 @@ class UnifiedMonitorServer:
499
576
  event = data.get("event", "claude_event")
500
577
  event_data = data.get("data", {})
501
578
 
502
- # Emit to Socket.IO clients via the appropriate event
579
+ # Extract actual event name from subtype or type within data
580
+ actual_event = (
581
+ event_data.get("subtype") or event_data.get("type") or event
582
+ )
583
+
584
+ # Categorize event and wrap in expected format
585
+ event_type = self._categorize_event(actual_event)
586
+ wrapped_event = {
587
+ "type": event_type,
588
+ "subtype": event,
589
+ "data": event_data,
590
+ "timestamp": event_data.get("timestamp")
591
+ or datetime.now(timezone.utc).isoformat() + "Z",
592
+ "session_id": event_data.get("session_id"),
593
+ }
594
+
595
+ # Emit to Socket.IO clients via the categorized event type
503
596
  if self.sio:
504
- await self.sio.emit(event, event_data)
505
- self.logger.debug(f"HTTP event forwarded to Socket.IO: {event}")
597
+ await self.sio.emit(event_type, wrapped_event)
598
+ self.logger.debug(
599
+ f"HTTP event forwarded to Socket.IO: {event} -> {event_type}"
600
+ )
506
601
 
507
602
  return web.Response(status=204) # No content response
508
603
 
@@ -859,7 +954,7 @@ class UnifiedMonitorServer:
859
954
  # Configuration endpoint for dashboard initialization
860
955
  async def config_handler(request):
861
956
  """Return configuration for dashboard initialization."""
862
- import subprocess
957
+ import subprocess # nosec B404
863
958
 
864
959
  config = {
865
960
  "workingDirectory": Path.cwd(),
@@ -870,7 +965,7 @@ class UnifiedMonitorServer:
870
965
 
871
966
  # Try to get current git branch
872
967
  try:
873
- result = subprocess.run(
968
+ result = subprocess.run( # nosec B603 B607
874
969
  ["git", "branch", "--show-current"],
875
970
  capture_output=True,
876
971
  text=True,
@@ -880,7 +975,7 @@ class UnifiedMonitorServer:
880
975
  )
881
976
  if result.returncode == 0 and result.stdout.strip():
882
977
  config["gitBranch"] = result.stdout.strip()
883
- except Exception:
978
+ except Exception: # nosec B110
884
979
  pass # Keep default "Unknown" value
885
980
 
886
981
  return web.json_response(config)
@@ -910,7 +1005,7 @@ class UnifiedMonitorServer:
910
1005
  # Git history handler
911
1006
  async def git_history_handler(request: web.Request) -> web.Response:
912
1007
  """Get git history for a file."""
913
- import subprocess
1008
+ import subprocess # nosec B404
914
1009
 
915
1010
  try:
916
1011
  data = await request.json()
@@ -939,7 +1034,7 @@ class UnifiedMonitorServer:
939
1034
  )
940
1035
 
941
1036
  # Get git log for file
942
- result = subprocess.run(
1037
+ result = subprocess.run( # nosec B603 B607
943
1038
  [
944
1039
  "git",
945
1040
  "log",
@@ -978,7 +1073,7 @@ class UnifiedMonitorServer:
978
1073
  # Git diff handler
979
1074
  async def git_diff_handler(request: web.Request) -> web.Response:
980
1075
  """Get git diff for a file with optional commit selection."""
981
- import subprocess
1076
+ import subprocess # nosec B404
982
1077
 
983
1078
  try:
984
1079
  file_path = request.query.get("path", "")
@@ -1010,7 +1105,7 @@ class UnifiedMonitorServer:
1010
1105
  )
1011
1106
 
1012
1107
  # Find git repository root
1013
- git_root_result = subprocess.run(
1108
+ git_root_result = subprocess.run( # nosec B603 B607
1014
1109
  ["git", "rev-parse", "--show-toplevel"],
1015
1110
  check=False,
1016
1111
  capture_output=True,
@@ -1034,7 +1129,7 @@ class UnifiedMonitorServer:
1034
1129
  git_root = Path(git_root_result.stdout.strip())
1035
1130
 
1036
1131
  # Check if file is tracked by git
1037
- ls_files_result = subprocess.run(
1132
+ ls_files_result = subprocess.run( # nosec B603 B607
1038
1133
  ["git", "ls-files", "--error-unmatch", str(path)],
1039
1134
  check=False,
1040
1135
  capture_output=True,
@@ -1056,7 +1151,7 @@ class UnifiedMonitorServer:
1056
1151
  )
1057
1152
 
1058
1153
  # Get commit history for this file (last 5 commits)
1059
- history_result = subprocess.run(
1154
+ history_result = subprocess.run( # nosec B603 B607
1060
1155
  [
1061
1156
  "git",
1062
1157
  "log",
@@ -1087,7 +1182,7 @@ class UnifiedMonitorServer:
1087
1182
  )
1088
1183
 
1089
1184
  # Check for uncommitted changes
1090
- uncommitted_result = subprocess.run(
1185
+ uncommitted_result = subprocess.run( # nosec B603 B607
1091
1186
  ["git", "diff", "HEAD", str(path)],
1092
1187
  check=False,
1093
1188
  capture_output=True,
@@ -1100,7 +1195,7 @@ class UnifiedMonitorServer:
1100
1195
  # Get diff based on commit parameter
1101
1196
  if commit_hash:
1102
1197
  # Get diff for specific commit
1103
- result = subprocess.run(
1198
+ result = subprocess.run( # nosec B603 B607
1104
1199
  ["git", "show", commit_hash, "--", str(path)],
1105
1200
  check=False,
1106
1201
  capture_output=True,
@@ -1469,7 +1564,7 @@ class UnifiedMonitorServer:
1469
1564
  gather = asyncio.gather(*tasks_to_cancel, return_exceptions=True)
1470
1565
  try:
1471
1566
  loop.run_until_complete(gather)
1472
- except Exception:
1567
+ except Exception: # nosec B110
1473
1568
  # Some tasks might fail to cancel, that's ok
1474
1569
  pass
1475
1570