claude-mpm 5.0.9__py3-none-any.whl → 5.6.23__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (614) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +4 -0
  3. claude_mpm/agents/BASE_AGENT.md +164 -0
  4. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +115 -0
  5. claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
  6. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +186 -0
  7. claude_mpm/agents/MEMORY.md +1 -1
  8. claude_mpm/agents/PM_INSTRUCTIONS.md +479 -616
  9. claude_mpm/agents/WORKFLOW.md +6 -253
  10. claude_mpm/agents/agent_loader.py +13 -44
  11. claude_mpm/agents/base_agent.json +1 -1
  12. claude_mpm/agents/frontmatter_validator.py +70 -2
  13. claude_mpm/agents/templates/circuit-breakers.md +457 -62
  14. claude_mpm/cli/__init__.py +5 -2
  15. claude_mpm/cli/__main__.py +4 -0
  16. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  17. claude_mpm/cli/commands/agent_state_manager.py +18 -27
  18. claude_mpm/cli/commands/agents.py +177 -41
  19. claude_mpm/cli/commands/agents_reconcile.py +197 -0
  20. claude_mpm/cli/commands/auto_configure.py +723 -236
  21. claude_mpm/cli/commands/autotodos.py +566 -0
  22. claude_mpm/cli/commands/commander.py +216 -0
  23. claude_mpm/cli/commands/config.py +88 -2
  24. claude_mpm/cli/commands/configure.py +1874 -170
  25. claude_mpm/cli/commands/configure_agent_display.py +27 -6
  26. claude_mpm/cli/commands/hook_errors.py +60 -60
  27. claude_mpm/cli/commands/monitor.py +2 -2
  28. claude_mpm/cli/commands/mpm_init/core.py +232 -46
  29. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  30. claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
  31. claude_mpm/cli/commands/postmortem.py +1 -1
  32. claude_mpm/cli/commands/profile.py +276 -0
  33. claude_mpm/cli/commands/run.py +35 -3
  34. claude_mpm/cli/commands/skill_source.py +51 -2
  35. claude_mpm/cli/commands/skills.py +379 -204
  36. claude_mpm/cli/commands/summarize.py +413 -0
  37. claude_mpm/cli/executor.py +141 -19
  38. claude_mpm/cli/interactive/__init__.py +10 -0
  39. claude_mpm/cli/interactive/agent_wizard.py +115 -60
  40. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  41. claude_mpm/cli/interactive/skill_selector.py +481 -0
  42. claude_mpm/cli/parsers/agents_parser.py +54 -9
  43. claude_mpm/cli/parsers/auto_configure_parser.py +13 -138
  44. claude_mpm/cli/parsers/base_parser.py +88 -1
  45. claude_mpm/cli/parsers/commander_parser.py +116 -0
  46. claude_mpm/cli/parsers/config_parser.py +153 -83
  47. claude_mpm/cli/parsers/profile_parser.py +147 -0
  48. claude_mpm/cli/parsers/run_parser.py +10 -0
  49. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  50. claude_mpm/cli/parsers/skills_parser.py +1 -1
  51. claude_mpm/cli/startup.py +1017 -266
  52. claude_mpm/cli/startup_display.py +74 -6
  53. claude_mpm/cli/startup_logging.py +2 -2
  54. claude_mpm/cli/utils.py +7 -3
  55. claude_mpm/commander/__init__.py +78 -0
  56. claude_mpm/commander/adapters/__init__.py +60 -0
  57. claude_mpm/commander/adapters/auggie.py +260 -0
  58. claude_mpm/commander/adapters/base.py +288 -0
  59. claude_mpm/commander/adapters/claude_code.py +392 -0
  60. claude_mpm/commander/adapters/codex.py +237 -0
  61. claude_mpm/commander/adapters/communication.py +366 -0
  62. claude_mpm/commander/adapters/example_usage.py +310 -0
  63. claude_mpm/commander/adapters/mpm.py +389 -0
  64. claude_mpm/commander/adapters/registry.py +204 -0
  65. claude_mpm/commander/api/__init__.py +16 -0
  66. claude_mpm/commander/api/app.py +121 -0
  67. claude_mpm/commander/api/errors.py +133 -0
  68. claude_mpm/commander/api/routes/__init__.py +8 -0
  69. claude_mpm/commander/api/routes/events.py +184 -0
  70. claude_mpm/commander/api/routes/inbox.py +171 -0
  71. claude_mpm/commander/api/routes/messages.py +148 -0
  72. claude_mpm/commander/api/routes/projects.py +271 -0
  73. claude_mpm/commander/api/routes/sessions.py +226 -0
  74. claude_mpm/commander/api/routes/work.py +296 -0
  75. claude_mpm/commander/api/schemas.py +186 -0
  76. claude_mpm/commander/chat/__init__.py +7 -0
  77. claude_mpm/commander/chat/cli.py +146 -0
  78. claude_mpm/commander/chat/commands.py +96 -0
  79. claude_mpm/commander/chat/repl.py +310 -0
  80. claude_mpm/commander/config.py +51 -0
  81. claude_mpm/commander/config_loader.py +115 -0
  82. claude_mpm/commander/core/__init__.py +10 -0
  83. claude_mpm/commander/core/block_manager.py +325 -0
  84. claude_mpm/commander/core/response_manager.py +323 -0
  85. claude_mpm/commander/daemon.py +603 -0
  86. claude_mpm/commander/env_loader.py +59 -0
  87. claude_mpm/commander/events/__init__.py +26 -0
  88. claude_mpm/commander/events/manager.py +332 -0
  89. claude_mpm/commander/frameworks/__init__.py +12 -0
  90. claude_mpm/commander/frameworks/base.py +146 -0
  91. claude_mpm/commander/frameworks/claude_code.py +58 -0
  92. claude_mpm/commander/frameworks/mpm.py +62 -0
  93. claude_mpm/commander/inbox/__init__.py +16 -0
  94. claude_mpm/commander/inbox/dedup.py +128 -0
  95. claude_mpm/commander/inbox/inbox.py +224 -0
  96. claude_mpm/commander/inbox/models.py +70 -0
  97. claude_mpm/commander/instance_manager.py +450 -0
  98. claude_mpm/commander/llm/__init__.py +6 -0
  99. claude_mpm/commander/llm/openrouter_client.py +167 -0
  100. claude_mpm/commander/llm/summarizer.py +70 -0
  101. claude_mpm/commander/memory/__init__.py +45 -0
  102. claude_mpm/commander/memory/compression.py +347 -0
  103. claude_mpm/commander/memory/embeddings.py +230 -0
  104. claude_mpm/commander/memory/entities.py +310 -0
  105. claude_mpm/commander/memory/example_usage.py +290 -0
  106. claude_mpm/commander/memory/integration.py +325 -0
  107. claude_mpm/commander/memory/search.py +381 -0
  108. claude_mpm/commander/memory/store.py +657 -0
  109. claude_mpm/commander/models/__init__.py +18 -0
  110. claude_mpm/commander/models/events.py +121 -0
  111. claude_mpm/commander/models/project.py +162 -0
  112. claude_mpm/commander/models/work.py +214 -0
  113. claude_mpm/commander/parsing/__init__.py +20 -0
  114. claude_mpm/commander/parsing/extractor.py +132 -0
  115. claude_mpm/commander/parsing/output_parser.py +270 -0
  116. claude_mpm/commander/parsing/patterns.py +100 -0
  117. claude_mpm/commander/persistence/__init__.py +11 -0
  118. claude_mpm/commander/persistence/event_store.py +274 -0
  119. claude_mpm/commander/persistence/state_store.py +309 -0
  120. claude_mpm/commander/persistence/work_store.py +164 -0
  121. claude_mpm/commander/polling/__init__.py +13 -0
  122. claude_mpm/commander/polling/event_detector.py +104 -0
  123. claude_mpm/commander/polling/output_buffer.py +49 -0
  124. claude_mpm/commander/polling/output_poller.py +153 -0
  125. claude_mpm/commander/project_session.py +268 -0
  126. claude_mpm/commander/proxy/__init__.py +12 -0
  127. claude_mpm/commander/proxy/formatter.py +89 -0
  128. claude_mpm/commander/proxy/output_handler.py +191 -0
  129. claude_mpm/commander/proxy/relay.py +155 -0
  130. claude_mpm/commander/registry.py +410 -0
  131. claude_mpm/commander/runtime/__init__.py +10 -0
  132. claude_mpm/commander/runtime/executor.py +191 -0
  133. claude_mpm/commander/runtime/monitor.py +346 -0
  134. claude_mpm/commander/session/__init__.py +6 -0
  135. claude_mpm/commander/session/context.py +81 -0
  136. claude_mpm/commander/session/manager.py +59 -0
  137. claude_mpm/commander/tmux_orchestrator.py +361 -0
  138. claude_mpm/commander/web/__init__.py +1 -0
  139. claude_mpm/commander/work/__init__.py +30 -0
  140. claude_mpm/commander/work/executor.py +207 -0
  141. claude_mpm/commander/work/queue.py +405 -0
  142. claude_mpm/commander/workflow/__init__.py +27 -0
  143. claude_mpm/commander/workflow/event_handler.py +241 -0
  144. claude_mpm/commander/workflow/notifier.py +146 -0
  145. claude_mpm/commands/mpm-config.md +36 -0
  146. claude_mpm/commands/mpm-doctor.md +16 -21
  147. claude_mpm/commands/mpm-help.md +12 -286
  148. claude_mpm/commands/mpm-init.md +88 -506
  149. claude_mpm/commands/mpm-monitor.md +22 -401
  150. claude_mpm/commands/mpm-organize.md +128 -0
  151. claude_mpm/commands/mpm-postmortem.md +13 -107
  152. claude_mpm/commands/mpm-session-resume.md +20 -363
  153. claude_mpm/commands/mpm-status.md +13 -69
  154. claude_mpm/commands/mpm-ticket-view.md +60 -495
  155. claude_mpm/commands/mpm-version.md +13 -107
  156. claude_mpm/commands/mpm.md +8 -0
  157. claude_mpm/config/agent_presets.py +8 -7
  158. claude_mpm/config/agent_sources.py +27 -0
  159. claude_mpm/config/skill_sources.py +16 -0
  160. claude_mpm/constants.py +1 -0
  161. claude_mpm/core/claude_runner.py +154 -2
  162. claude_mpm/core/config.py +37 -26
  163. claude_mpm/core/config_constants.py +74 -9
  164. claude_mpm/core/constants.py +56 -12
  165. claude_mpm/core/framework/formatters/content_formatter.py +3 -13
  166. claude_mpm/core/framework/loaders/agent_loader.py +8 -5
  167. claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
  168. claude_mpm/core/framework_loader.py +4 -2
  169. claude_mpm/core/hook_manager.py +51 -3
  170. claude_mpm/core/interactive_session.py +12 -11
  171. claude_mpm/core/logger.py +39 -9
  172. claude_mpm/core/logging_utils.py +35 -11
  173. claude_mpm/core/network_config.py +148 -0
  174. claude_mpm/core/oneshot_session.py +7 -6
  175. claude_mpm/core/optimized_startup.py +61 -0
  176. claude_mpm/core/output_style_manager.py +219 -44
  177. claude_mpm/core/shared/config_loader.py +3 -1
  178. claude_mpm/core/socketio_pool.py +16 -8
  179. claude_mpm/core/unified_agent_registry.py +134 -16
  180. claude_mpm/core/unified_config.py +76 -8
  181. claude_mpm/core/unified_paths.py +95 -90
  182. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  183. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  184. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  185. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
  186. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
  187. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
  188. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
  189. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
  190. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
  191. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
  192. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
  193. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  194. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
  195. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
  196. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
  197. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
  198. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
  199. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
  200. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  201. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  202. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
  203. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
  204. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
  205. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
  206. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
  207. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
  208. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
  209. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
  210. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  211. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
  212. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
  213. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
  214. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  215. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
  216. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  217. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
  218. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
  219. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
  220. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
  221. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
  222. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DR8nis88.js +2 -0
  223. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
  224. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  225. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
  226. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
  227. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
  228. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
  229. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
  230. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
  231. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  232. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
  233. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  234. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
  235. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
  236. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
  237. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
  238. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  239. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
  240. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
  241. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
  242. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
  243. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  244. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.RgBboRvH.js +1 -0
  245. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
  246. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  247. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  248. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  249. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  250. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  251. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  252. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  253. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  254. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  255. claude_mpm/experimental/cli_enhancements.py +2 -1
  256. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  257. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  258. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  259. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  260. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  261. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  262. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  263. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  264. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  265. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  266. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
  267. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  268. claude_mpm/hooks/claude_hooks/event_handlers.py +479 -128
  269. claude_mpm/hooks/claude_hooks/hook_handler.py +254 -83
  270. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  271. claude_mpm/hooks/claude_hooks/installer.py +149 -18
  272. claude_mpm/hooks/claude_hooks/memory_integration.py +67 -19
  273. claude_mpm/hooks/claude_hooks/response_tracking.py +44 -62
  274. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  275. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  276. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  277. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  278. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  279. claude_mpm/hooks/claude_hooks/services/connection_manager.py +69 -30
  280. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +36 -103
  281. claude_mpm/hooks/claude_hooks/services/state_manager.py +23 -36
  282. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +73 -75
  283. claude_mpm/hooks/kuzu_memory_hook.py +5 -5
  284. claude_mpm/hooks/memory_integration_hook.py +46 -1
  285. claude_mpm/hooks/session_resume_hook.py +89 -1
  286. claude_mpm/hooks/templates/pre_tool_use_template.py +10 -2
  287. claude_mpm/init.py +276 -19
  288. claude_mpm/models/agent_definition.py +7 -0
  289. claude_mpm/models/git_repository.py +3 -3
  290. claude_mpm/scripts/claude-hook-handler.sh +87 -20
  291. claude_mpm/scripts/launch_monitor.py +93 -13
  292. claude_mpm/scripts/start_activity_logging.py +0 -0
  293. claude_mpm/services/agents/agent_builder.py +3 -3
  294. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  295. claude_mpm/services/agents/agent_review_service.py +280 -0
  296. claude_mpm/services/agents/agent_selection_service.py +2 -2
  297. claude_mpm/services/agents/cache_git_manager.py +7 -7
  298. claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
  299. claude_mpm/services/agents/deployment/agent_discovery_service.py +6 -5
  300. claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
  301. claude_mpm/services/agents/deployment/agent_template_builder.py +42 -20
  302. claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
  303. claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
  304. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  305. claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
  306. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +348 -29
  307. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +570 -68
  308. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  309. claude_mpm/services/agents/git_source_manager.py +57 -4
  310. claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
  311. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  312. claude_mpm/services/agents/recommender.py +5 -3
  313. claude_mpm/services/agents/single_tier_deployment_service.py +6 -6
  314. claude_mpm/services/agents/sources/git_source_sync_service.py +129 -11
  315. claude_mpm/services/agents/startup_sync.py +27 -4
  316. claude_mpm/services/agents/toolchain_detector.py +10 -6
  317. claude_mpm/services/analysis/__init__.py +11 -1
  318. claude_mpm/services/analysis/clone_detector.py +1030 -0
  319. claude_mpm/services/cli/__init__.py +3 -0
  320. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  321. claude_mpm/services/cli/session_resume_helper.py +10 -2
  322. claude_mpm/services/command_deployment_service.py +81 -10
  323. claude_mpm/services/delegation_detector.py +175 -0
  324. claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
  325. claude_mpm/services/diagnostics/checks/agent_sources_check.py +31 -1
  326. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  327. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  328. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  329. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  330. claude_mpm/services/diagnostics/models.py +14 -1
  331. claude_mpm/services/event_bus/config.py +3 -1
  332. claude_mpm/services/event_log.py +325 -0
  333. claude_mpm/services/git/git_operations_service.py +101 -16
  334. claude_mpm/services/infrastructure/__init__.py +4 -0
  335. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  336. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  337. claude_mpm/services/monitor/daemon.py +9 -2
  338. claude_mpm/services/monitor/daemon_manager.py +54 -7
  339. claude_mpm/services/monitor/management/lifecycle.py +15 -3
  340. claude_mpm/services/monitor/server.py +796 -30
  341. claude_mpm/services/pm_skills_deployer.py +884 -0
  342. claude_mpm/services/profile_manager.py +337 -0
  343. claude_mpm/services/project/project_organizer.py +4 -0
  344. claude_mpm/services/self_upgrade_service.py +120 -12
  345. claude_mpm/services/skills/__init__.py +3 -0
  346. claude_mpm/services/skills/git_skill_source_manager.py +303 -12
  347. claude_mpm/services/skills/selective_skill_deployer.py +869 -0
  348. claude_mpm/services/skills/skill_discovery_service.py +74 -4
  349. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  350. claude_mpm/services/skills_deployer.py +294 -55
  351. claude_mpm/services/socketio/dashboard_server.py +1 -0
  352. claude_mpm/services/socketio/event_normalizer.py +51 -6
  353. claude_mpm/services/socketio/handlers/hook.py +14 -7
  354. claude_mpm/services/socketio/server/core.py +386 -108
  355. claude_mpm/services/socketio/server/main.py +12 -4
  356. claude_mpm/services/version_control/git_operations.py +103 -0
  357. claude_mpm/skills/__init__.py +2 -1
  358. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  359. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  360. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  361. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  362. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  363. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  364. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  365. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  366. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  367. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  368. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  369. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  370. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  371. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  372. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  373. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  374. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  375. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  376. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  377. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  378. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  379. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  380. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  381. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  382. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  383. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  384. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  385. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  386. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  387. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  388. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  389. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  390. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  391. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  392. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  393. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  394. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  395. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  396. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  397. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  398. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  399. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  400. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  401. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  402. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  403. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  404. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  405. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  406. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  407. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  408. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  409. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  410. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  411. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  412. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  413. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  414. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  415. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  416. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  417. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  418. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  419. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  420. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  421. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  422. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  423. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  424. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  425. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  426. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  427. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  428. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  429. claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
  430. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  431. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  432. claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
  433. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  434. claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
  435. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  436. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  437. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  438. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  439. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  440. claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
  441. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  442. claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
  443. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  444. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  445. claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
  446. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  447. claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
  448. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  449. claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
  450. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  451. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  452. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  453. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  454. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  455. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  456. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  457. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  458. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  459. claude_mpm/skills/bundled/security-scanning.md +112 -0
  460. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  461. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  462. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  463. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  464. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  465. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  466. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  467. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  468. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  469. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  470. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  471. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  472. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  473. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  474. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  475. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  476. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  477. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  478. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  479. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  480. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  481. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  482. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  483. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  484. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  485. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  486. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  487. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  488. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  489. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  490. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  491. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  492. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  493. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  494. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  495. claude_mpm/skills/registry.py +295 -90
  496. claude_mpm/skills/skill_manager.py +98 -3
  497. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  498. claude_mpm/utils/agent_dependency_loader.py +115 -4
  499. claude_mpm/utils/agent_filters.py +17 -44
  500. claude_mpm/utils/gitignore.py +3 -0
  501. claude_mpm/utils/migration.py +4 -4
  502. claude_mpm/utils/robust_installer.py +86 -21
  503. claude_mpm-5.6.23.dist-info/METADATA +393 -0
  504. {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/RECORD +508 -261
  505. claude_mpm-5.6.23.dist-info/entry_points.txt +5 -0
  506. claude_mpm-5.6.23.dist-info/licenses/LICENSE +94 -0
  507. claude_mpm-5.6.23.dist-info/licenses/LICENSE-FAQ.md +153 -0
  508. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
  509. claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
  510. claude_mpm/agents/BASE_OPS.md +0 -219
  511. claude_mpm/agents/BASE_PM.md +0 -480
  512. claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
  513. claude_mpm/agents/BASE_QA.md +0 -167
  514. claude_mpm/agents/BASE_RESEARCH.md +0 -53
  515. claude_mpm/agents/OUTPUT_STYLE.md +0 -290
  516. claude_mpm/agents/PM_INSTRUCTIONS_TEACH.md +0 -1322
  517. claude_mpm/agents/base_agent_loader.py +0 -601
  518. claude_mpm/cli/commands/agents_detect.py +0 -380
  519. claude_mpm/cli/commands/agents_recommend.py +0 -309
  520. claude_mpm/cli/ticket_cli.py +0 -35
  521. claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
  522. claude_mpm/commands/mpm-agents-detect.md +0 -177
  523. claude_mpm/commands/mpm-agents-list.md +0 -131
  524. claude_mpm/commands/mpm-agents-recommend.md +0 -223
  525. claude_mpm/commands/mpm-config-view.md +0 -150
  526. claude_mpm/commands/mpm-ticket-organize.md +0 -304
  527. claude_mpm/dashboard/analysis_runner.py +0 -455
  528. claude_mpm/dashboard/index.html +0 -13
  529. claude_mpm/dashboard/open_dashboard.py +0 -66
  530. claude_mpm/dashboard/static/css/activity.css +0 -1958
  531. claude_mpm/dashboard/static/css/connection-status.css +0 -370
  532. claude_mpm/dashboard/static/css/dashboard.css +0 -4701
  533. claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
  534. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
  535. claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
  536. claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
  537. claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
  538. claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
  539. claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
  540. claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
  541. claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
  542. claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
  543. claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
  544. claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
  545. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
  546. claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
  547. claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
  548. claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
  549. claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
  550. claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
  551. claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
  552. claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
  553. claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
  554. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
  555. claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
  556. claude_mpm/dashboard/static/js/connection-manager.js +0 -536
  557. claude_mpm/dashboard/static/js/dashboard.js +0 -1914
  558. claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
  559. claude_mpm/dashboard/static/js/socket-client.js +0 -1474
  560. claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
  561. claude_mpm/dashboard/static/socket.io.min.js +0 -7
  562. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
  563. claude_mpm/dashboard/templates/code_simple.html +0 -153
  564. claude_mpm/dashboard/templates/index.html +0 -606
  565. claude_mpm/dashboard/test_dashboard.html +0 -372
  566. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  567. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  568. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  569. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  570. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  571. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  572. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  573. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  574. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  575. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  576. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  577. claude_mpm/scripts/mcp_server.py +0 -75
  578. claude_mpm/scripts/mcp_wrapper.py +0 -39
  579. claude_mpm/services/mcp_gateway/__init__.py +0 -159
  580. claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
  581. claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
  582. claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
  583. claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
  584. claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
  585. claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
  586. claude_mpm/services/mcp_gateway/core/base.py +0 -312
  587. claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
  588. claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
  589. claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
  590. claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
  591. claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
  592. claude_mpm/services/mcp_gateway/main.py +0 -589
  593. claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
  594. claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
  595. claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
  596. claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
  597. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
  598. claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
  599. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
  600. claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
  601. claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
  602. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
  603. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
  604. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
  605. claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
  606. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
  607. claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
  608. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
  609. claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
  610. claude_mpm-5.0.9.dist-info/METADATA +0 -1028
  611. claude_mpm-5.0.9.dist-info/entry_points.txt +0 -10
  612. claude_mpm-5.0.9.dist-info/licenses/LICENSE +0 -21
  613. {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/WHEEL +0 -0
  614. {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/top_level.txt +0 -0
claude_mpm/cli/startup.py CHANGED
@@ -10,47 +10,128 @@ Part of cli/__init__.py refactoring to reduce file size and improve modularity.
10
10
 
11
11
  import os
12
12
  import sys
13
- import warnings
14
13
  from pathlib import Path
15
14
 
16
15
 
17
- def check_legacy_cache() -> None:
18
- """Check for legacy cache/agents/ directory and warn user.
16
+ def sync_hooks_on_startup(quiet: bool = False) -> bool:
17
+ """Ensure hooks are up-to-date on startup.
18
+
19
+ WHY: Users can have stale hook configurations in settings.json that cause errors.
20
+ Reinstalling hooks ensures the hook format matches the current code.
19
21
 
20
- WHY: cache/agents/ is deprecated in favor of cache/remote-agents/.
21
- Research confirmed that cache/remote-agents/ is the canonical location
22
- with 26 active code references, while cache/agents/ has only 7 legacy references.
22
+ DESIGN DECISION: Shows brief status message on success for user awareness.
23
+ Failures are logged but don't prevent startup to ensure claude-mpm remains functional.
23
24
 
24
- DESIGN DECISIONS:
25
- - Non-blocking warning: Doesn't stop execution, just informs user
26
- - Migration guidance: Provides clear path to migrate
27
- - One-time check: Only warns if legacy cache contains files
25
+ Args:
26
+ quiet: If True, suppress all output (used internally)
27
+
28
+ Returns:
29
+ bool: True if hooks were synced successfully, False otherwise
28
30
  """
29
- home = Path.home()
30
- legacy_cache = home / ".claude-mpm" / "cache" / "agents"
31
- canonical_cache = home / ".claude-mpm" / "cache" / "remote-agents"
32
- migration_marker = home / ".claude-mpm" / "cache" / ".migrated_to_remote_agents"
31
+ try:
32
+ from ..hooks.claude_hooks.installer import HookInstaller
33
33
 
34
- # Skip if already migrated or no legacy cache
35
- if migration_marker.exists() or not legacy_cache.exists():
36
- return
34
+ installer = HookInstaller()
35
+
36
+ # Show brief status (hooks sync is fast)
37
+ if not quiet:
38
+ print("Syncing Claude Code hooks...", end=" ", flush=True)
39
+
40
+ # Reinstall hooks (force=True ensures update)
41
+ success = installer.install_hooks(force=True)
42
+
43
+ if not quiet:
44
+ if success:
45
+ print("✓")
46
+ else:
47
+ print("(skipped)")
48
+
49
+ return success
50
+
51
+ except Exception as e:
52
+ if not quiet:
53
+ print("(error)")
54
+ # Log but don't fail startup
55
+ from ..core.logger import get_logger
56
+
57
+ logger = get_logger("startup")
58
+ logger.warning(f"Hook sync failed (non-fatal): {e}")
59
+ return False
60
+
61
+
62
+ def cleanup_legacy_agent_cache() -> None:
63
+ """Remove legacy hierarchical agent cache directories.
64
+
65
+ WHY: Old agent cache used category-based directory structure directly in cache.
66
+ New structure uses remote source paths. This cleanup prevents confusion from
67
+ stale cache directories.
37
68
 
38
- # Check if legacy cache has actual agent files
39
- legacy_files = list(legacy_cache.glob("*.md")) + list(legacy_cache.glob("*.json"))
40
- if not legacy_files:
69
+ Old structure (removed):
70
+ ~/.claude-mpm/cache/agents/engineer/
71
+ ~/.claude-mpm/cache/agents/ops/
72
+ ~/.claude-mpm/cache/agents/qa/
73
+ ...
74
+
75
+ New structure (kept):
76
+ ~/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents/agents/...
77
+
78
+ DESIGN DECISION: Runs early in startup before agent deployment to ensure
79
+ clean cache state. Removes only known legacy directories to avoid deleting
80
+ user data.
81
+ """
82
+ import shutil
83
+ from pathlib import Path
84
+
85
+ from ..core.logger import get_logger
86
+
87
+ logger = get_logger("startup")
88
+
89
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "agents"
90
+ if not cache_dir.exists():
41
91
  return
42
92
 
43
- # Only warn if canonical cache doesn't exist (indicating unmigrated system)
44
- if not canonical_cache.exists():
45
- warnings.warn(
46
- f"\n⚠️ DEPRECATION: Legacy cache directory detected\n"
47
- f" Location: {legacy_cache}\n"
48
- f" Files found: {len(legacy_files)}\n\n"
49
- f"The 'cache/agents/' directory is deprecated. Please migrate to 'cache/remote-agents/'.\n"
50
- f"Run: python scripts/migrate_cache_to_remote_agents.py\n",
51
- DeprecationWarning,
52
- stacklevel=2,
53
- )
93
+ # Known legacy category directories (from old hierarchical structure)
94
+ legacy_dirs = [
95
+ "claude-mpm",
96
+ "documentation",
97
+ "engineer",
98
+ "ops",
99
+ "qa",
100
+ "security",
101
+ "universal",
102
+ ]
103
+
104
+ removed = []
105
+
106
+ # Remove legacy category directories
107
+ for dir_name in legacy_dirs:
108
+ legacy_path = cache_dir / dir_name
109
+ if legacy_path.exists() and legacy_path.is_dir():
110
+ try:
111
+ shutil.rmtree(legacy_path)
112
+ removed.append(dir_name)
113
+ except Exception as e:
114
+ logger.debug(f"Failed to remove legacy directory {dir_name}: {e}")
115
+
116
+ # Also remove stray BASE-AGENT.md in cache root
117
+ base_agent = cache_dir / "BASE-AGENT.md"
118
+ if base_agent.exists():
119
+ try:
120
+ base_agent.unlink()
121
+ removed.append("BASE-AGENT.md")
122
+ except Exception as e:
123
+ logger.debug(f"Failed to remove BASE-AGENT.md: {e}")
124
+
125
+ if removed:
126
+ logger.info(f"Cleaned up legacy agent cache: {', '.join(removed)}")
127
+
128
+
129
+ def check_legacy_cache() -> None:
130
+ """Deprecated: Legacy cache checking is no longer needed.
131
+
132
+ This function is kept for backward compatibility but does nothing.
133
+ All agent cache operations now use the standardized cache/agents/ directory.
134
+ """
54
135
 
55
136
 
56
137
  def setup_early_environment(argv):
@@ -80,7 +161,25 @@ def setup_early_environment(argv):
80
161
  # CRITICAL: Suppress ALL logging by default
81
162
  # This catches all loggers (claude_mpm.*, service.*, framework_loader, etc.)
82
163
  # This will be overridden by setup_mcp_server_logging() based on user preference
83
- logging.getLogger().setLevel(logging.CRITICAL + 1) # Root logger catches everything
164
+ root_logger = logging.getLogger()
165
+ root_logger.setLevel(logging.CRITICAL + 1) # Root logger catches everything
166
+ root_logger.handlers = [] # Remove any handlers
167
+
168
+ # Also suppress common module loggers explicitly to prevent handler leakage
169
+ for logger_name in [
170
+ "claude_mpm",
171
+ "path_resolver",
172
+ "file_loader",
173
+ "framework_loader",
174
+ "service",
175
+ "instruction_loader",
176
+ "agent_loader",
177
+ "startup",
178
+ ]:
179
+ module_logger = logging.getLogger(logger_name)
180
+ module_logger.setLevel(logging.CRITICAL + 1)
181
+ module_logger.handlers = []
182
+ module_logger.propagate = False
84
183
 
85
184
  # Process argv
86
185
  if argv is None:
@@ -110,7 +209,17 @@ def should_skip_background_services(args, processed_argv):
110
209
  skip_commands = ["--version", "-v", "--help", "-h"]
111
210
  return any(cmd in (processed_argv or sys.argv[1:]) for cmd in skip_commands) or (
112
211
  hasattr(args, "command")
113
- and args.command in ["info", "doctor", "config", "mcp", "configure"]
212
+ and args.command
213
+ in [
214
+ "info",
215
+ "doctor",
216
+ "config",
217
+ "mcp",
218
+ "configure",
219
+ "hook-errors",
220
+ "autotodos",
221
+ "commander",
222
+ ]
114
223
  )
115
224
 
116
225
 
@@ -153,7 +262,7 @@ def deploy_bundled_skills():
153
262
  if not skills_config.get("auto_deploy", True):
154
263
  # Auto-deploy disabled, skip silently
155
264
  return
156
- except Exception:
265
+ except Exception: # nosec B110
157
266
  # If config loading fails, assume auto-deploy is enabled (default)
158
267
  pass
159
268
 
@@ -221,79 +330,243 @@ def discover_and_link_runtime_skills():
221
330
 
222
331
  def deploy_output_style_on_startup():
223
332
  """
224
- Deploy claude-mpm output style to Claude Code on CLI startup.
333
+ Deploy claude-mpm output styles to PROJECT-LEVEL directory on CLI startup.
334
+
335
+ WHY: Automatically deploy output styles to ensure consistent, professional
336
+ communication without emojis and exclamation points. Styles are project-specific
337
+ to allow different projects to have different communication styles.
225
338
 
226
- WHY: Automatically deploy and activate the output style to ensure consistent,
227
- professional communication without emojis and exclamation points. This ensures
228
- the style is available even when using Claude Code directly (not via chat command).
339
+ DESIGN DECISION: This is non-blocking and idempotent. Deploys to user-level
340
+ directory (~/.claude/output-styles/) which is the official Claude Code location
341
+ for custom output styles.
229
342
 
230
- DESIGN DECISION: This is non-blocking and idempotent. It uses OutputStyleManager
231
- which handles version detection, file deployment, and settings activation.
232
- Only works for Claude Code >= 1.0.83.
343
+ Deploys all styles:
344
+ - claude-mpm.md (professional mode)
345
+ - claude-mpm-teacher.md (teaching mode)
346
+ - claude-mpm-research.md (research mode - for codebase analysis)
233
347
  """
234
348
  try:
235
- from pathlib import Path
236
-
237
349
  from ..core.output_style_manager import OutputStyleManager
238
350
 
239
- # Create OutputStyleManager instance
240
- output_style_manager = OutputStyleManager()
351
+ # Initialize the output style manager
352
+ manager = OutputStyleManager()
241
353
 
242
- # Check if Claude Code supports output styles
243
- if not output_style_manager.supports_output_styles():
244
- # Silently skip - version too old or Claude not installed
354
+ # Check if Claude Code version supports output styles (>= 1.0.83)
355
+ if not manager.supports_output_styles():
356
+ # Skip deployment for older versions
357
+ # The manager will fall back to injecting content directly
245
358
  return
246
359
 
247
- # Check if already deployed and active
248
- settings_file = Path.home() / ".claude" / "settings.json"
249
- output_style_file = Path.home() / ".claude" / "output-styles" / "claude-mpm.md"
250
-
251
- already_configured = False
252
- if settings_file.exists() and output_style_file.exists():
253
- try:
254
- import json
255
-
256
- # Check if file has content (bug fix: was skipping empty files)
257
- if output_style_file.stat().st_size == 0:
258
- # File is empty, need to redeploy with content
259
- pass # Fall through to deployment below
260
- else:
261
- # File has content, check if already active
262
- settings = json.loads(settings_file.read_text())
263
- if settings.get("activeOutputStyle") == "claude-mpm":
264
- # Already deployed and active with content
265
- already_configured = True
266
- except Exception:
267
- pass # Continue with deployment if we can't read settings
268
-
269
- if already_configured:
270
- # Show feedback that output style is ready
271
- print("✓ Output style configured", flush=True)
360
+ # Check if all styles are already deployed and up-to-date
361
+ all_up_to_date = True
362
+ for style_config in manager.styles.values():
363
+ source_path = style_config["source"]
364
+ target_path = style_config["target"]
365
+
366
+ if not (
367
+ target_path.exists()
368
+ and source_path.exists()
369
+ and target_path.stat().st_size == source_path.stat().st_size
370
+ ):
371
+ all_up_to_date = False
372
+ break
373
+
374
+ if all_up_to_date:
375
+ # Show feedback that output styles are ready
376
+ print(" Output styles ready", flush=True)
272
377
  return
273
378
 
274
- # Read OUTPUT_STYLE.md content
275
- output_style_path = Path(__file__).parent.parent / "agents" / "OUTPUT_STYLE.md"
379
+ # Deploy all styles using the manager
380
+ results = manager.deploy_all_styles(activate_default=True)
276
381
 
277
- if not output_style_path.exists():
278
- # No output style file to deploy
279
- return
382
+ # Count successful deployments
383
+ deployed_count = sum(1 for success in results.values() if success)
280
384
 
281
- output_style_content = output_style_path.read_text()
385
+ if deployed_count > 0:
386
+ print(f"✓ Output styles deployed ({deployed_count} styles)", flush=True)
387
+ else:
388
+ # Deployment failed - log but don't fail startup
389
+ from ..core.logger import get_logger
282
390
 
283
- # Deploy the output style (deploys file and activates it)
284
- output_style_manager.deploy_output_style(output_style_content)
285
- print("✓ Output style configured", flush=True)
391
+ logger = get_logger("cli")
392
+ logger.debug("Failed to deploy any output styles")
286
393
 
287
394
  except Exception as e:
288
395
  # Non-critical - log but don't fail startup
289
396
  from ..core.logger import get_logger
290
397
 
291
398
  logger = get_logger("cli")
292
- logger.debug(f"Failed to deploy output style: {e}")
399
+ logger.debug(f"Failed to deploy output styles: {e}")
293
400
  # Continue execution - output style deployment shouldn't block startup
294
401
 
295
402
 
296
- def sync_remote_agents_on_startup():
403
+ def _cleanup_orphaned_agents(deploy_target: Path, deployed_agents: list[str]) -> int:
404
+ """Remove agents that are managed by claude-mpm but no longer deployed.
405
+
406
+ WHY: When agent configurations change, old agents should be removed to avoid
407
+ confusion and stale agent references. Only removes claude-mpm managed agents,
408
+ leaving user-created agents untouched.
409
+
410
+ SAFETY: Only removes files with claude-mpm ownership markers in frontmatter.
411
+ Files without frontmatter or without ownership indicators are preserved.
412
+
413
+ Args:
414
+ deploy_target: Path to .claude/agents/ directory
415
+ deployed_agents: List of agent filenames that should remain
416
+
417
+ Returns:
418
+ Number of agents removed
419
+ """
420
+ import re
421
+
422
+ import yaml
423
+
424
+ from ..core.logger import get_logger
425
+
426
+ logger = get_logger("cli")
427
+ removed_count = 0
428
+ deployed_set = set(deployed_agents)
429
+
430
+ if not deploy_target.exists():
431
+ return 0
432
+
433
+ # Scan all .md files in agents directory
434
+ for agent_file in deploy_target.glob("*.md"):
435
+ # Skip hidden files
436
+ if agent_file.name.startswith("."):
437
+ continue
438
+
439
+ # Skip if this agent should remain deployed
440
+ if agent_file.name in deployed_set:
441
+ continue
442
+
443
+ # Check if this is a claude-mpm managed agent
444
+ try:
445
+ content = agent_file.read_text(encoding="utf-8")
446
+
447
+ # Parse YAML frontmatter
448
+ if content.startswith("---"):
449
+ match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
450
+ if match:
451
+ frontmatter = yaml.safe_load(match.group(1))
452
+
453
+ # Check ownership indicators
454
+ is_ours = False
455
+ if frontmatter:
456
+ author = frontmatter.get("author", "")
457
+ source = frontmatter.get("source", "")
458
+ agent_id = frontmatter.get("agent_id", "")
459
+
460
+ # It's ours if it has any of these markers
461
+ if (
462
+ "Claude MPM" in str(author)
463
+ or source == "remote"
464
+ or agent_id
465
+ ):
466
+ is_ours = True
467
+
468
+ if is_ours:
469
+ # Safe to remove - it's our agent but not deployed
470
+ agent_file.unlink()
471
+ removed_count += 1
472
+ logger.info(f"Removed orphaned agent: {agent_file.name}")
473
+
474
+ except Exception as e:
475
+ logger.debug(f"Could not check agent {agent_file.name}: {e}")
476
+ # Don't remove if we can't verify ownership
477
+
478
+ return removed_count
479
+
480
+
481
+ def _save_deployment_state_after_reconciliation(
482
+ agent_result, project_path: Path
483
+ ) -> None:
484
+ """Save deployment state after reconciliation to prevent duplicate deployment.
485
+
486
+ WHY: After perform_startup_reconciliation() deploys agents to .claude/agents/,
487
+ we need to save a deployment state file so that ClaudeRunner.setup_agents()
488
+ can detect agents are already deployed and skip redundant deployment.
489
+
490
+ This prevents the "✓ Deployed 31 native agents" duplicate deployment that
491
+ occurs when setup_agents() doesn't know reconciliation already ran.
492
+
493
+ Args:
494
+ agent_result: DeploymentResult from perform_startup_reconciliation()
495
+ project_path: Project root directory
496
+
497
+ DESIGN DECISION: Use same state file format as ClaudeRunner._save_deployment_state()
498
+ Located at: .claude-mpm/cache/deployment_state.json
499
+
500
+ State file format:
501
+ {
502
+ "version": "5.6.13",
503
+ "agent_count": 15,
504
+ "deployment_hash": "sha256:...",
505
+ "deployed_at": 1234567890.123
506
+ }
507
+ """
508
+ import hashlib
509
+ import json
510
+ import time
511
+
512
+ from ..core.logger import get_logger
513
+
514
+ logger = get_logger("cli")
515
+
516
+ try:
517
+ # Get version from package
518
+ from claude_mpm import __version__
519
+
520
+ # Path to state file (matches ClaudeRunner._get_deployment_state_path())
521
+ state_file = project_path / ".claude-mpm" / "cache" / "deployment_state.json"
522
+ agents_dir = project_path / ".claude" / "agents"
523
+
524
+ # Count deployed agents
525
+ if agents_dir.exists():
526
+ agent_count = len(list(agents_dir.glob("*.md")))
527
+ else:
528
+ agent_count = 0
529
+
530
+ # Calculate deployment hash (matches ClaudeRunner._calculate_deployment_hash())
531
+ # CRITICAL: Must match exact hash algorithm used in ClaudeRunner
532
+ # Hashes filename + file content (not mtime) for consistency
533
+ deployment_hash = ""
534
+ if agents_dir.exists():
535
+ agent_files = sorted(agents_dir.glob("*.md"))
536
+ hash_obj = hashlib.sha256()
537
+ for agent_file in agent_files:
538
+ # Include filename and content in hash (matches ClaudeRunner)
539
+ hash_obj.update(agent_file.name.encode())
540
+ try:
541
+ hash_obj.update(agent_file.read_bytes())
542
+ except Exception as e:
543
+ logger.debug(f"Error reading {agent_file} for hash: {e}")
544
+
545
+ deployment_hash = hash_obj.hexdigest()
546
+
547
+ # Create state data
548
+ state_data = {
549
+ "version": __version__,
550
+ "agent_count": agent_count,
551
+ "deployment_hash": deployment_hash,
552
+ "deployed_at": time.time(),
553
+ }
554
+
555
+ # Ensure directory exists
556
+ state_file.parent.mkdir(parents=True, exist_ok=True)
557
+
558
+ # Write state file
559
+ state_file.write_text(json.dumps(state_data, indent=2))
560
+ logger.debug(
561
+ f"Saved deployment state after reconciliation: {agent_count} agents"
562
+ )
563
+
564
+ except Exception as e:
565
+ # Non-critical error - log but don't fail startup
566
+ logger.debug(f"Failed to save deployment state: {e}")
567
+
568
+
569
+ def sync_remote_agents_on_startup(force_sync: bool = False):
297
570
  """
298
571
  Synchronize agent templates from remote sources on startup.
299
572
 
@@ -308,18 +581,47 @@ def sync_remote_agents_on_startup():
308
581
  Workflow:
309
582
  1. Sync all enabled Git sources (download/cache files) - Phase 1 progress bar
310
583
  2. Deploy agents to ~/.claude/agents/ - Phase 2 progress bar
311
- 3. Log deployment results
584
+ 3. Cleanup orphaned agents (ours but no longer deployed) - Phase 3
585
+ 4. Cleanup legacy agent cache directories (after sync/deployment) - Phase 4
586
+ 5. Log deployment results
587
+
588
+ Args:
589
+ force_sync: Force download even if cache is fresh (bypasses ETag).
312
590
  """
313
- # Check for legacy cache and warn user if found
591
+ # DEPRECATED: Legacy warning - no-op function, kept for compatibility
314
592
  check_legacy_cache()
315
593
 
316
594
  try:
317
- from ..services.agents.deployment.agent_deployment import AgentDeploymentService
595
+ # Load active profile if configured
596
+ # Get project root (where .claude-mpm exists)
597
+ from pathlib import Path
598
+
599
+ from ..core.shared.config_loader import ConfigLoader
318
600
  from ..services.agents.startup_sync import sync_agents_on_startup
601
+ from ..services.profile_manager import ProfileManager
319
602
  from ..utils.progress import ProgressBar
320
603
 
604
+ project_root = Path.cwd()
605
+
606
+ profile_manager = ProfileManager(project_dir=project_root)
607
+ config_loader = ConfigLoader()
608
+ main_config = config_loader.load_main_config()
609
+ active_profile = main_config.get("active_profile")
610
+
611
+ if active_profile:
612
+ success = profile_manager.load_profile(active_profile)
613
+ if success:
614
+ summary = profile_manager.get_filtering_summary()
615
+ from ..core.logger import get_logger
616
+
617
+ logger = get_logger("cli")
618
+ logger.info(
619
+ f"Profile '{active_profile}' active: "
620
+ f"{summary['enabled_agents_count']} agents enabled"
621
+ )
622
+
321
623
  # Phase 1: Sync files from Git sources
322
- result = sync_agents_on_startup()
624
+ result = sync_agents_on_startup(force_refresh=force_sync)
323
625
 
324
626
  # Only proceed with deployment if sync was enabled and ran
325
627
  if result.get("enabled") and result.get("sources_synced", 0) > 0:
@@ -342,130 +644,95 @@ def sync_remote_agents_on_startup():
342
644
  logger.warning(f"Agent sync completed with {len(errors)} errors")
343
645
 
344
646
  # Phase 2: Deploy agents from cache to ~/.claude/agents/
345
- # This mirrors the skills deployment pattern (lines 371-407)
647
+ # Use reconciliation service to respect configuration.yaml settings
346
648
  try:
347
- # Initialize deployment service
348
- deployment_service = AgentDeploymentService()
349
-
350
- # Count agents in cache to show accurate progress
351
649
  from pathlib import Path
352
650
 
353
- cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
354
- agent_count = 0
355
-
356
- if cache_dir.exists():
357
- # Count MD files in cache (agent markdown files from Git)
358
- # BUGFIX: Only count files in agent directories, not docs/templates/READMEs
359
- # Valid agent paths must contain "/agents/" or be in root-level category dirs
360
- # Exclude PM templates, BASE-AGENT, and documentation files
361
- pm_templates = {
362
- "base-agent.md",
363
- "circuit_breakers.md",
364
- "pm_examples.md",
365
- "pm_red_flags.md",
366
- "research_gate_examples.md",
367
- "response_format.md",
368
- "ticket_completeness_examples.md",
369
- "validation_templates.md",
370
- "git_file_tracking.md",
371
- }
372
- # Documentation files to exclude (by filename)
373
- doc_files = {
374
- "readme.md",
375
- "changelog.md",
376
- "contributing.md",
377
- "implementation-summary.md",
378
- "reorganization-plan.md",
379
- "auto-deploy-index.md",
380
- }
381
-
382
- # Find all markdown files
383
- all_md_files = list(cache_dir.rglob("*.md"))
384
-
385
- # Filter to only agent files:
386
- # 1. Must have "/agents/" in path (from git repos)
387
- # 2. Must not be in PM templates or doc files
388
- # 3. Exclude BASE-AGENT.md which is not a deployable agent
389
- agent_files = [
390
- f
391
- for f in all_md_files
392
- if (
393
- # Must be in an agent directory (from git repos like bobmatnyc/claude-mpm-agents/agents/)
394
- "/agents/" in str(f)
395
- # Exclude PM templates, doc files, and BASE-AGENT
396
- and f.name.lower() not in pm_templates
397
- and f.name.lower() not in doc_files
398
- and f.name.lower() != "base-agent.md"
399
- )
400
- ]
401
- agent_count = len(agent_files)
651
+ from ..core.unified_config import UnifiedConfig
652
+ from ..services.agents.deployment.startup_reconciliation import (
653
+ perform_startup_reconciliation,
654
+ )
655
+
656
+ # Load configuration
657
+ unified_config = UnifiedConfig()
402
658
 
403
- if agent_count > 0:
404
- # Create progress bar for deployment phase
659
+ # Override with profile settings if active
660
+ if active_profile and profile_manager.active_profile:
661
+ # Get enabled agents from profile (returns Set[str])
662
+ profile_enabled_agents = (
663
+ profile_manager.active_profile.get_enabled_agents()
664
+ )
665
+ # Update config with profile's enabled list (convert Set to List)
666
+ unified_config.agents.enabled = list(profile_enabled_agents)
667
+ logger.info(
668
+ f"Profile '{active_profile}': Using {len(profile_enabled_agents)} enabled agents"
669
+ )
670
+
671
+ # Perform reconciliation to deploy configured agents
672
+ project_path = Path.cwd()
673
+ agent_result, _skill_result = perform_startup_reconciliation(
674
+ project_path=project_path, config=unified_config, silent=False
675
+ )
676
+
677
+ # Display results with progress bar
678
+ total_operations = (
679
+ len(agent_result.deployed)
680
+ + len(agent_result.removed)
681
+ + len(agent_result.unchanged)
682
+ )
683
+
684
+ if total_operations > 0:
405
685
  deploy_progress = ProgressBar(
406
- total=agent_count,
686
+ total=total_operations,
407
687
  prefix="Deploying agents",
408
688
  show_percentage=True,
409
689
  show_counter=True,
410
690
  )
411
-
412
- # Deploy agents with progress callback
413
- deploy_target = Path.home() / ".claude" / "agents"
414
- deployment_result = deployment_service.deploy_agents(
415
- target_dir=deploy_target,
416
- force_rebuild=False, # Only deploy if versions differ
417
- deployment_mode="update", # Version-aware updates
691
+ deploy_progress.update(total_operations)
692
+
693
+ # Build summary message
694
+ deployed = len(agent_result.deployed)
695
+ removed = len(agent_result.removed)
696
+ unchanged = len(agent_result.unchanged)
697
+
698
+ summary_parts = []
699
+ if deployed > 0:
700
+ summary_parts.append(f"{deployed} new")
701
+ if removed > 0:
702
+ summary_parts.append(f"{removed} removed")
703
+ if unchanged > 0:
704
+ summary_parts.append(f"{unchanged} unchanged")
705
+
706
+ summary = f"Complete: {', '.join(summary_parts)}"
707
+ deploy_progress.finish(summary)
708
+
709
+ # Display errors if any
710
+ if agent_result.errors:
711
+ logger.warning(
712
+ f"Agent deployment completed with {len(agent_result.errors)} errors"
418
713
  )
714
+ print("\n⚠️ Agent Deployment Errors:")
715
+ max_errors_to_show = 10
716
+ errors_to_display = agent_result.errors[:max_errors_to_show]
419
717
 
420
- # Update progress bar (single increment since deploy_agents is batch)
421
- deploy_progress.update(agent_count)
422
-
423
- # Finish deployment progress bar
424
- deployed = len(deployment_result.get("deployed", []))
425
- updated = len(deployment_result.get("updated", []))
426
- skipped = len(deployment_result.get("skipped", []))
427
- total_available = deployed + updated + skipped
428
-
429
- # Show total available agents (deployed + updated + already existing)
430
- if deployed > 0 or updated > 0:
431
- deploy_progress.finish(
432
- f"Complete: {deployed} deployed, {updated} updated, {skipped} already present ({total_available} total)"
433
- )
434
- else:
435
- deploy_progress.finish(
436
- f"Complete: {total_available} agents ready (all up-to-date)"
437
- )
438
-
439
- # Display deployment errors to user (not just logs)
440
- deploy_errors = deployment_result.get("errors", [])
441
- if deploy_errors:
442
- # Log for debugging
443
- logger.warning(
444
- f"Agent deployment completed with {len(deploy_errors)} errors: {deploy_errors}"
445
- )
446
-
447
- # Display errors to user with clear formatting
448
- print("\n⚠️ Agent Deployment Errors:")
718
+ for error in errors_to_display:
719
+ print(f" - {error}")
449
720
 
450
- # Show first 10 errors to avoid overwhelming output
451
- max_errors_to_show = 10
452
- errors_to_display = deploy_errors[:max_errors_to_show]
721
+ if len(agent_result.errors) > max_errors_to_show:
722
+ remaining = len(agent_result.errors) - max_errors_to_show
723
+ print(f" ... and {remaining} more error(s)")
453
724
 
454
- for error in errors_to_display:
455
- # Format error message for readability
456
- # Errors typically come as strings like "agent.md: Error message"
457
- print(f" - {error}")
458
-
459
- # If more errors exist, show count
460
- if len(deploy_errors) > max_errors_to_show:
461
- remaining = len(deploy_errors) - max_errors_to_show
462
- print(f" ... and {remaining} more error(s)")
725
+ print(
726
+ f"\n❌ Failed to deploy {len(agent_result.errors)} agent(s). "
727
+ "Please check the error messages above."
728
+ )
729
+ print(" Run with --verbose for detailed error information.\n")
463
730
 
464
- # Show summary message
465
- print(
466
- f"\n❌ Failed to deploy {len(deploy_errors)} agent(s). Please check the error messages above."
467
- )
468
- print(" Run with --verbose for detailed error information.\n")
731
+ # Save deployment state to prevent duplicate deployment in ClaudeRunner
732
+ # This ensures setup_agents() skips deployment since we already reconciled
733
+ _save_deployment_state_after_reconciliation(
734
+ agent_result=agent_result, project_path=project_path
735
+ )
469
736
 
470
737
  except Exception as e:
471
738
  # Deployment failure shouldn't block startup
@@ -474,6 +741,11 @@ def sync_remote_agents_on_startup():
474
741
  logger = get_logger("cli")
475
742
  logger.warning(f"Failed to deploy agents from cache: {e}")
476
743
 
744
+ # Phase 4: Cleanup legacy agent cache directories (after sync/deployment)
745
+ # CRITICAL: This must run AFTER sync completes because sync may recreate
746
+ # legacy directories. Running cleanup here ensures they're removed.
747
+ cleanup_legacy_agent_cache()
748
+
477
749
  except Exception as e:
478
750
  # Non-critical - log but don't fail startup
479
751
  from ..core.logger import get_logger
@@ -482,8 +754,14 @@ def sync_remote_agents_on_startup():
482
754
  logger.debug(f"Failed to sync remote agents: {e}")
483
755
  # Continue execution - agent sync failure shouldn't block startup
484
756
 
757
+ # Cleanup legacy cache even if sync failed
758
+ try:
759
+ cleanup_legacy_agent_cache()
760
+ except Exception: # nosec B110
761
+ pass # Ignore cleanup errors
762
+
485
763
 
486
- def sync_remote_skills_on_startup():
764
+ def sync_remote_skills_on_startup(force_sync: bool = False):
487
765
  """
488
766
  Synchronize skill templates from remote sources on startup.
489
767
 
@@ -496,16 +774,51 @@ def sync_remote_skills_on_startup():
496
774
 
497
775
  Workflow:
498
776
  1. Sync all enabled Git sources (download/cache files) - Phase 1 progress bar
499
- 2. Deploy skills to ~/.claude/skills/ with flat structure - Phase 2 progress bar
500
- 3. Log deployment results
777
+ 2. Scan deployed agents for skill requirements save to configuration.yaml
778
+ 3. Resolve which skills to deploy (user_defined vs agent_referenced)
779
+ 4. Apply profile filtering if active
780
+ 5. Deploy resolved skills to ~/.claude/skills/ - Phase 2 progress bar
781
+ 6. Log deployment results with source indication
782
+
783
+ Args:
784
+ force_sync: Force download even if cache is fresh (bypasses ETag).
501
785
  """
502
786
  try:
503
787
  from pathlib import Path
504
788
 
505
789
  from ..config.skill_sources import SkillSourceConfiguration
790
+ from ..core.shared.config_loader import ConfigLoader
791
+ from ..services.profile_manager import ProfileManager
506
792
  from ..services.skills.git_skill_source_manager import GitSkillSourceManager
793
+ from ..services.skills.selective_skill_deployer import (
794
+ get_required_skills_from_agents,
795
+ get_skills_to_deploy,
796
+ save_agent_skills_to_config,
797
+ )
507
798
  from ..utils.progress import ProgressBar
508
799
 
800
+ # Load active profile if configured
801
+ # Get project root (where .claude-mpm exists)
802
+ project_root = Path.cwd()
803
+
804
+ profile_manager = ProfileManager(project_dir=project_root)
805
+ config_loader = ConfigLoader()
806
+ main_config = config_loader.load_main_config()
807
+ active_profile = main_config.get("active_profile")
808
+
809
+ if active_profile:
810
+ success = profile_manager.load_profile(active_profile)
811
+ if success:
812
+ from ..core.logger import get_logger
813
+
814
+ logger = get_logger("cli")
815
+ summary = profile_manager.get_filtering_summary()
816
+ logger.info(
817
+ f"Profile '{active_profile}' active: "
818
+ f"{summary['enabled_skills_count']} skills enabled, "
819
+ f"{summary['disabled_patterns_count']} patterns disabled"
820
+ )
821
+
509
822
  config = SkillSourceConfiguration()
510
823
  manager = GitSkillSourceManager(config)
511
824
 
@@ -523,6 +836,8 @@ def sync_remote_skills_on_startup():
523
836
 
524
837
  # Discover total file count across all sources
525
838
  total_file_count = 0
839
+ total_skill_dirs = 0 # Count actual skill directories (folders with SKILL.md)
840
+
526
841
  for source in enabled_sources:
527
842
  try:
528
843
  # Parse GitHub URL
@@ -546,22 +861,33 @@ def sync_remote_skills_on_startup():
546
861
  ]
547
862
  total_file_count += len(relevant_files)
548
863
 
864
+ # Count skill directories (unique directories containing SKILL.md)
865
+ skill_dirs = set()
866
+ for f in all_files:
867
+ if f.endswith("/SKILL.md"):
868
+ # Extract directory path
869
+ skill_dir = "/".join(f.split("/")[:-1])
870
+ skill_dirs.add(skill_dir)
871
+ total_skill_dirs += len(skill_dirs)
872
+
549
873
  except Exception as e:
550
874
  logger.debug(f"Failed to discover files for {source.id}: {e}")
551
875
  # Use estimate if discovery fails
552
876
  total_file_count += 150
877
+ total_skill_dirs += 50 # Estimate ~50 skills
553
878
 
554
879
  # Create progress bar for sync phase with actual file count
880
+ # Note: We sync files (md, json, etc.), but will deploy skill directories
555
881
  sync_progress = ProgressBar(
556
882
  total=total_file_count if total_file_count > 0 else 1,
557
- prefix="Syncing skills",
883
+ prefix="Syncing skill files",
558
884
  show_percentage=True,
559
885
  show_counter=True,
560
886
  )
561
887
 
562
888
  # Sync all sources with progress callback
563
889
  results = manager.sync_all_sources(
564
- force=False, progress_callback=sync_progress.update
890
+ force=force_sync, progress_callback=sync_progress.update
565
891
  )
566
892
 
567
893
  # Finish sync progress bar with clear breakdown
@@ -571,69 +897,201 @@ def sync_remote_skills_on_startup():
571
897
 
572
898
  if cached > 0:
573
899
  sync_progress.finish(
574
- f"Complete: {downloaded} downloaded, {cached} cached ({total_files} total)"
900
+ f"Complete: {downloaded} downloaded, {cached} cached ({total_files} files, {total_skill_dirs} skills)"
575
901
  )
576
902
  else:
577
903
  # All new downloads (first sync)
578
- sync_progress.finish(f"Complete: {downloaded} files downloaded")
579
-
580
- # Phase 2: Deploy skills to ~/.claude/skills/
581
- # This flattens nested Git structure (e.g., collaboration/parallel-agents/SKILL.md)
582
- # into flat deployment (e.g., collaboration-dispatching-parallel-agents/SKILL.md)
583
- if results["synced_count"] > 0:
584
- # Get all skills to determine deployment count
585
- all_skills = manager.get_all_skills()
586
- skill_count = len(all_skills)
587
-
588
- if skill_count > 0:
589
- # Create progress bar for deployment phase
904
+ sync_progress.finish(
905
+ f"Complete: {downloaded} files downloaded ({total_skill_dirs} skills)"
906
+ )
907
+
908
+ # Phase 2: Scan agents and save to configuration.yaml
909
+ # This step populates configuration.yaml with agent-referenced skills
910
+ # CRITICAL: Always scan agents to populate agent_referenced, even when using cached skills.
911
+ # Without this, skill_filter=None causes ALL skills to deploy and NO cleanup to run.
912
+ agents_dir = Path.cwd() / ".claude" / "agents"
913
+
914
+ # Scan agents for skill requirements (ALWAYS run to ensure cleanup works)
915
+ agent_skills = get_required_skills_from_agents(agents_dir)
916
+ logger.info(
917
+ f"Agent scan found {len(agent_skills)} unique skills across deployed agents"
918
+ )
919
+
920
+ # Save to project-level configuration.yaml
921
+ project_config_path = Path.cwd() / ".claude-mpm" / "configuration.yaml"
922
+ save_agent_skills_to_config(list(agent_skills), project_config_path)
923
+ logger.debug(
924
+ f"Saved {len(agent_skills)} agent-referenced skills to {project_config_path}"
925
+ )
926
+
927
+ # Phase 3: Resolve which skills to deploy (user_defined or agent_referenced)
928
+ skills_to_deploy, skill_source = get_skills_to_deploy(project_config_path)
929
+
930
+ # CRITICAL DEBUG: Log deployment resolution to diagnose cleanup issues
931
+ if skills_to_deploy:
932
+ logger.info(
933
+ f"Resolved {len(skills_to_deploy)} skills from {skill_source} (cleanup will run)"
934
+ )
935
+ else:
936
+ logger.warning(
937
+ f"No skills resolved from {skill_source} - will deploy ALL skills WITHOUT cleanup! "
938
+ f"This may indicate agent_referenced is empty in configuration.yaml."
939
+ )
940
+
941
+ # Phase 4: Apply profile filtering if active
942
+ if active_profile and profile_manager.active_profile:
943
+ # Filter skills based on profile
944
+ if skills_to_deploy:
945
+ # Filter the resolved skill list
946
+ original_count = len(skills_to_deploy)
947
+ filtered_skills = [
948
+ skill
949
+ for skill in skills_to_deploy
950
+ if profile_manager.is_skill_enabled(skill)
951
+ ]
952
+ filtered_count = original_count - len(filtered_skills)
953
+
954
+ # SAFEGUARD: Warn if all skills were filtered out (misconfiguration)
955
+ if not filtered_skills and original_count > 0:
956
+ logger.warning(
957
+ f"Profile '{active_profile}' filtered ALL {original_count} skills. "
958
+ f"This may indicate a naming mismatch in the profile."
959
+ )
960
+ elif filtered_count > 0:
961
+ logger.info(
962
+ f"Profile '{active_profile}' filtered {filtered_count} skills "
963
+ f"({len(filtered_skills)} remaining)"
964
+ )
965
+
966
+ skills_to_deploy = filtered_skills
967
+ skill_source = f"{skill_source} + profile filtered"
968
+ else:
969
+ # No explicit skill list - filter from all available
970
+ all_skills = manager.get_all_skills()
971
+ filtered_skills = [
972
+ skill["name"]
973
+ for skill in all_skills
974
+ if profile_manager.is_skill_enabled(skill["name"])
975
+ ]
976
+ skills_to_deploy = filtered_skills
977
+ skill_source = "profile filtered"
978
+ logger.info(
979
+ f"Profile '{active_profile}': "
980
+ f"{len(filtered_skills)} skills enabled from {len(all_skills)} available"
981
+ )
982
+
983
+ # Get all skills to determine counts
984
+ all_skills = manager.get_all_skills()
985
+ total_skill_count = len(all_skills)
986
+
987
+ # Determine skill count based on resolution
988
+ skill_count = len(skills_to_deploy) if skills_to_deploy else total_skill_count
989
+
990
+ if skill_count > 0:
991
+ # Deploy skills with resolved filter
992
+ # Deploy ONLY to project directory (not user-level)
993
+ # DESIGN DECISION: Project-level deployment keeps skills isolated per project,
994
+ # avoiding pollution of user's global ~/.claude/skills/ directory.
995
+
996
+ # Deploy to project-local directory with cleanup
997
+ deployment_result = manager.deploy_skills(
998
+ target_dir=Path.cwd() / ".claude" / "skills",
999
+ force=force_sync,
1000
+ # CRITICAL FIX: Empty list should mean "deploy no skills", not "deploy all"
1001
+ # When skills_to_deploy is [], we want skill_filter=set() NOT skill_filter=None
1002
+ # None means "no filtering" (deploy all), empty set means "filter to nothing"
1003
+ skill_filter=set(skills_to_deploy)
1004
+ if skills_to_deploy is not None
1005
+ else None,
1006
+ )
1007
+
1008
+ # REMOVED: User-level deployment (lines 1068-1074)
1009
+ # Reason: Skills should be project-specific, not user-global.
1010
+ # Claude Code can read from project-level .claude/skills/ directory.
1011
+
1012
+ # Get actual counts from deployment result (use project-local for display)
1013
+ deployed = deployment_result.get("deployed_count", 0)
1014
+ skipped = deployment_result.get("skipped_count", 0)
1015
+ filtered = deployment_result.get("filtered_count", 0)
1016
+ removed = deployment_result.get("removed_count", 0)
1017
+ total_available = deployed + skipped
1018
+
1019
+ # Only show progress bar if there are skills to deploy
1020
+ if total_available > 0:
590
1021
  deploy_progress = ProgressBar(
591
- total=skill_count,
1022
+ total=total_available,
592
1023
  prefix="Deploying skill directories",
593
1024
  show_percentage=True,
594
1025
  show_counter=True,
595
1026
  )
596
-
597
- # Deploy skills with progress callback
598
- # Deploy to project directory (like agents), not user directory
599
- deployment_result = manager.deploy_skills(
600
- target_dir=Path.cwd() / ".claude" / "skills",
601
- force=False,
602
- progress_callback=deploy_progress.update,
1027
+ # Update progress bar to completion
1028
+ deploy_progress.update(total_available)
1029
+ else:
1030
+ # No skills to deploy - create dummy progress for message only
1031
+ deploy_progress = ProgressBar(
1032
+ total=1,
1033
+ prefix="Deploying skill directories",
1034
+ show_percentage=False,
1035
+ show_counter=False,
603
1036
  )
1037
+ deploy_progress.update(1)
604
1038
 
605
- # Finish deployment progress bar
606
- deployed = deployment_result.get("deployed_count", 0)
607
- skipped = deployment_result.get("skipped_count", 0)
608
- total_available = deployed + skipped
1039
+ # Show total available skills (deployed + already existing)
1040
+ # Include source indication (user_defined vs agent_referenced)
1041
+ # Note: total_skill_count is from cache, total_available is what's deployed/needed
1042
+ source_label = (
1043
+ "user override" if skill_source == "user_defined" else "from agents"
1044
+ )
609
1045
 
610
- # Show total available skills (deployed + already existing)
611
- # This is more user-friendly than just showing newly deployed count
1046
+ # Build finish message with cleanup info
1047
+ if deployed > 0 or removed > 0:
1048
+ parts = []
612
1049
  if deployed > 0:
1050
+ parts.append(f"{deployed} new")
1051
+ if skipped > 0:
1052
+ parts.append(f"{skipped} unchanged")
1053
+ if removed > 0:
1054
+ parts.append(f"{removed} removed")
1055
+
1056
+ status = ", ".join(parts)
1057
+
1058
+ if filtered > 0:
613
1059
  deploy_progress.finish(
614
- f"Complete: {deployed} deployed, {skipped} already present ({total_available} total)"
1060
+ f"Complete: {status} ({total_available} {source_label}, {filtered} files in cache)"
615
1061
  )
616
1062
  else:
617
1063
  deploy_progress.finish(
618
- f"Complete: {total_available} skills ready (all up-to-date)"
1064
+ f"Complete: {status} ({total_available} skills {source_label} from {total_skill_count} files in cache)"
619
1065
  )
1066
+ elif filtered > 0:
1067
+ # Skills filtered means agents require fewer skills than available
1068
+ deploy_progress.finish(
1069
+ f"No skills needed ({source_label}, {total_skill_count} files in cache)"
1070
+ )
1071
+ else:
1072
+ # No changes - all skills already deployed
1073
+ msg = f"Complete: {total_available} skills {source_label}"
1074
+ if removed > 0:
1075
+ msg += f", {removed} removed"
1076
+ msg += f" ({total_skill_count} files in cache)"
1077
+ deploy_progress.finish(msg)
1078
+
1079
+ # Log deployment errors if any
1080
+ from ..core.logger import get_logger
620
1081
 
621
- # Log deployment errors if any
622
- from ..core.logger import get_logger
623
-
624
- logger = get_logger("cli")
1082
+ logger = get_logger("cli")
625
1083
 
626
- errors = deployment_result.get("errors", [])
627
- if errors:
628
- logger.warning(
629
- f"Skill deployment completed with {len(errors)} errors: {errors}"
630
- )
1084
+ errors = deployment_result.get("errors", [])
1085
+ if errors:
1086
+ logger.warning(
1087
+ f"Skill deployment completed with {len(errors)} errors: {errors}"
1088
+ )
631
1089
 
632
- # Log sync errors if any
633
- if results["failed_count"] > 0:
634
- logger.warning(
635
- f"Skill sync completed with {results['failed_count']} failures"
636
- )
1090
+ # Log sync errors if any
1091
+ if results["failed_count"] > 0:
1092
+ logger.warning(
1093
+ f"Skill sync completed with {results['failed_count']} failures"
1094
+ )
637
1095
 
638
1096
  except Exception as e:
639
1097
  # Non-critical - log but don't fail startup
@@ -644,7 +1102,282 @@ def sync_remote_skills_on_startup():
644
1102
  # Continue execution - skill sync failure shouldn't block startup
645
1103
 
646
1104
 
647
- def run_background_services():
1105
+ def show_agent_summary():
1106
+ """
1107
+ Display agent availability summary on startup.
1108
+
1109
+ WHY: Users should see at a glance how many agents are available and installed
1110
+ without having to run /mpm-agents list.
1111
+
1112
+ DESIGN DECISION: Fast, non-blocking check that counts agents from the deployment
1113
+ directory. Shows simple "X installed / Y available" format. Failures are silent
1114
+ to avoid blocking startup.
1115
+ """
1116
+ try:
1117
+ from pathlib import Path
1118
+
1119
+ # Count deployed agents (installed)
1120
+ deploy_target = Path.cwd() / ".claude" / "agents"
1121
+ installed_count = 0
1122
+ if deploy_target.exists():
1123
+ # Count .md files, excluding README and other docs
1124
+ agent_files = [
1125
+ f
1126
+ for f in deploy_target.glob("*.md")
1127
+ if not f.name.startswith(("README", "INSTRUCTIONS", "."))
1128
+ ]
1129
+ installed_count = len(agent_files)
1130
+
1131
+ # Count available agents in cache (from remote sources)
1132
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "agents"
1133
+ available_count = 0
1134
+ if cache_dir.exists():
1135
+ # Use same filtering logic as agent deployment (lines 486-533 in startup.py)
1136
+ pm_templates = {
1137
+ "base-agent.md",
1138
+ "circuit_breakers.md",
1139
+ "pm_examples.md",
1140
+ "pm_red_flags.md",
1141
+ "research_gate_examples.md",
1142
+ "response_format.md",
1143
+ "ticket_completeness_examples.md",
1144
+ "validation_templates.md",
1145
+ "git_file_tracking.md",
1146
+ }
1147
+ doc_files = {
1148
+ "readme.md",
1149
+ "changelog.md",
1150
+ "contributing.md",
1151
+ "implementation-summary.md",
1152
+ "reorganization-plan.md",
1153
+ "auto-deploy-index.md",
1154
+ }
1155
+
1156
+ # Find all markdown files in agents/ directories
1157
+ all_md_files = list(cache_dir.rglob("*.md"))
1158
+ agent_files = [
1159
+ f
1160
+ for f in all_md_files
1161
+ if (
1162
+ "/agents/" in str(f)
1163
+ and f.name.lower() not in pm_templates
1164
+ and f.name.lower() not in doc_files
1165
+ and f.name.lower() != "base-agent.md"
1166
+ and not any(
1167
+ part in str(f).split("/")
1168
+ for part in ["dist", "build", ".cache"]
1169
+ )
1170
+ )
1171
+ ]
1172
+ available_count = len(agent_files)
1173
+
1174
+ # Display summary if we have agents
1175
+ if installed_count > 0 or available_count > 0:
1176
+ print(
1177
+ f"✓ Agents: {installed_count} deployed / {max(0, available_count - installed_count)} cached",
1178
+ flush=True,
1179
+ )
1180
+
1181
+ except Exception as e:
1182
+ # Silent failure - agent summary is informational only
1183
+ from ..core.logger import get_logger
1184
+
1185
+ logger = get_logger("cli")
1186
+ logger.debug(f"Failed to generate agent summary: {e}")
1187
+
1188
+
1189
+ def show_skill_summary():
1190
+ """
1191
+ Display skill availability summary on startup.
1192
+
1193
+ WHY: Users should see at a glance how many skills are deployed and available
1194
+ from cache, similar to the agent summary showing "X deployed / Y cached".
1195
+
1196
+ DESIGN DECISION: Fast, non-blocking check that counts skills from:
1197
+ - Deployed skills: PROJECT-level .claude/skills/ directory
1198
+ - Cached skills: ~/.claude-mpm/cache/skills/ directory (from remote sources)
1199
+
1200
+ Shows format: "✓ Skills: X deployed / Y cached"
1201
+ Failures are silent to avoid blocking startup.
1202
+ """
1203
+ try:
1204
+ from pathlib import Path
1205
+
1206
+ # Count deployed skills (PROJECT-level, not user-level)
1207
+ project_skills_dir = Path.cwd() / ".claude" / "skills"
1208
+ deployed_count = 0
1209
+ if project_skills_dir.exists():
1210
+ # Count directories with SKILL.md (excludes collection repos)
1211
+ # Exclude collection directories (obra-superpowers, etc.)
1212
+ skill_dirs = [
1213
+ d
1214
+ for d in project_skills_dir.iterdir()
1215
+ if d.is_dir()
1216
+ and (d / "SKILL.md").exists()
1217
+ and not (d / ".git").exists() # Exclude collection repos
1218
+ ]
1219
+ deployed_count = len(skill_dirs)
1220
+
1221
+ # Count cached skills (from remote sources, not deployed yet)
1222
+ # This matches the agent summary pattern: deployed vs cached
1223
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "skills"
1224
+ cached_count = 0
1225
+ if cache_dir.exists():
1226
+ # Scan all repository directories in cache
1227
+ # Cache structure: ~/.claude-mpm/cache/skills/{owner}/{repo}/...
1228
+ for repo_dir in cache_dir.rglob("*"):
1229
+ if not repo_dir.is_dir():
1230
+ continue
1231
+
1232
+ # Count skill directories (those with SKILL.md)
1233
+ # Skills can be nested in: skills/category/skill-name/SKILL.md
1234
+ # or in flat structure: skill-name/SKILL.md
1235
+ for root, dirs, files in os.walk(repo_dir):
1236
+ if "SKILL.md" in files:
1237
+ # Exclude build artifacts and hidden directories
1238
+ root_path = Path(root)
1239
+ if not any(
1240
+ part.startswith(".")
1241
+ or part in ["dist", "build", "__pycache__"]
1242
+ for part in root_path.parts
1243
+ ):
1244
+ cached_count += 1
1245
+
1246
+ # Display summary using agent summary format: "X deployed / Y cached"
1247
+ # Only show non-deployed cached skills (subtract deployed from cached)
1248
+ non_deployed_cached = max(0, cached_count - deployed_count)
1249
+ if deployed_count > 0 or non_deployed_cached > 0:
1250
+ print(
1251
+ f"✓ Skills: {deployed_count} deployed / {non_deployed_cached} cached",
1252
+ flush=True,
1253
+ )
1254
+
1255
+ except Exception as e:
1256
+ # Silent failure - skill summary is informational only
1257
+ from ..core.logger import get_logger
1258
+
1259
+ logger = get_logger("cli")
1260
+ logger.debug(f"Failed to generate skill summary: {e}")
1261
+
1262
+
1263
+ def verify_and_show_pm_skills():
1264
+ """Verify PM skills and display status with enhanced validation.
1265
+
1266
+ WHY: PM skills are CRITICAL for PM agent operation. PM must KNOW if
1267
+ framework knowledge is unavailable at startup. Enhanced validation
1268
+ checks all required skills exist, are not corrupted, and auto-repairs
1269
+ if needed.
1270
+
1271
+ Shows deployment status:
1272
+ - "✓ PM skills: 8/8 verified" if all required skills are valid
1273
+ - "⚠ PM skills: 2 missing, auto-repairing..." if issues detected
1274
+ - Non-blocking but visible warning if auto-repair fails
1275
+ """
1276
+ try:
1277
+ from pathlib import Path
1278
+
1279
+ from ..services.pm_skills_deployer import (
1280
+ REQUIRED_PM_SKILLS,
1281
+ PMSkillsDeployerService,
1282
+ )
1283
+
1284
+ deployer = PMSkillsDeployerService()
1285
+ project_dir = Path.cwd()
1286
+
1287
+ # Verify with auto-repair enabled
1288
+ result = deployer.verify_pm_skills(project_dir, auto_repair=True)
1289
+
1290
+ if result.verified:
1291
+ # Show verified status with count
1292
+ total_required = len(REQUIRED_PM_SKILLS)
1293
+ print(
1294
+ f"✓ PM skills: {total_required}/{total_required} verified", flush=True
1295
+ )
1296
+ else:
1297
+ # Show warning with details
1298
+ missing_count = len(result.missing_skills)
1299
+ corrupted_count = len(result.corrupted_skills)
1300
+
1301
+ # Build status message
1302
+ issues = []
1303
+ if missing_count > 0:
1304
+ issues.append(f"{missing_count} missing")
1305
+ if corrupted_count > 0:
1306
+ issues.append(f"{corrupted_count} corrupted")
1307
+
1308
+ status = ", ".join(issues)
1309
+
1310
+ # Check if auto-repair was attempted
1311
+ if "Auto-repaired" in result.message:
1312
+ # Auto-repair succeeded
1313
+ total_required = len(REQUIRED_PM_SKILLS)
1314
+ print(
1315
+ f"✓ PM skills: {total_required}/{total_required} verified (auto-repaired)",
1316
+ flush=True,
1317
+ )
1318
+ else:
1319
+ # Auto-repair failed or not attempted
1320
+ print(f"⚠ PM skills: {status}", flush=True)
1321
+
1322
+ # Log warnings for debugging
1323
+ from ..core.logger import get_logger
1324
+
1325
+ logger = get_logger("cli")
1326
+ for warning in result.warnings:
1327
+ logger.warning(f"PM skills: {warning}")
1328
+
1329
+ except ImportError:
1330
+ # PM skills deployer not available - skip silently
1331
+ pass
1332
+ except Exception as e:
1333
+ from ..core.logger import get_logger
1334
+
1335
+ logger = get_logger("cli")
1336
+ logger.debug(f"PM skills verification failed: {e}")
1337
+
1338
+
1339
+ def auto_install_chrome_devtools_on_startup():
1340
+ """
1341
+ Automatically install chrome-devtools-mcp on startup if enabled.
1342
+
1343
+ WHY: Browser automation capabilities should be available out-of-the-box without
1344
+ manual MCP server configuration. chrome-devtools-mcp provides powerful browser
1345
+ interaction tools for Claude Code.
1346
+
1347
+ DESIGN DECISION: Non-blocking installation that doesn't prevent startup if it fails.
1348
+ Respects user configuration setting (enabled by default). Only installs if not
1349
+ already configured in Claude.
1350
+ """
1351
+ try:
1352
+ # Check if auto-install is disabled in config
1353
+ from ..config.config_loader import ConfigLoader
1354
+
1355
+ config_loader = ConfigLoader()
1356
+ try:
1357
+ config = config_loader.load_main_config()
1358
+ chrome_devtools_config = config.get("chrome_devtools", {})
1359
+ if not chrome_devtools_config.get("auto_install", True):
1360
+ # Auto-install disabled, skip silently
1361
+ return
1362
+ except Exception: # nosec B110
1363
+ # If config loading fails, assume auto-install is enabled (default)
1364
+ pass
1365
+
1366
+ # Import and run chrome-devtools installation
1367
+ from ..cli.chrome_devtools_installer import auto_install_chrome_devtools
1368
+
1369
+ auto_install_chrome_devtools(quiet=False)
1370
+
1371
+ except Exception as e:
1372
+ # Import logger here to avoid circular imports
1373
+ from ..core.logger import get_logger
1374
+
1375
+ logger = get_logger("cli")
1376
+ logger.debug(f"Failed to auto-install chrome-devtools-mcp: {e}")
1377
+ # Continue execution - chrome-devtools installation failure shouldn't block startup
1378
+
1379
+
1380
+ def run_background_services(force_sync: bool = False):
648
1381
  """
649
1382
  Initialize all background services on startup.
650
1383
 
@@ -655,12 +1388,23 @@ def run_background_services():
655
1388
  explicitly requests them via agent-manager commands. This prevents unwanted
656
1389
  file creation in project .claude/ directories.
657
1390
  See: SystemInstructionsDeployer and agent_deployment.py line 504-509
1391
+
1392
+ Args:
1393
+ force_sync: Force download even if cache is fresh (bypasses ETag).
658
1394
  """
1395
+ # Sync hooks early to ensure up-to-date configuration
1396
+ # RATIONALE: Hooks should be synced before other services to fix stale configs
1397
+ # This is fast (<100ms) and non-blocking, so it doesn't delay startup
1398
+ sync_hooks_on_startup() # Shows "Syncing Claude Code hooks... ✓"
1399
+
659
1400
  initialize_project_registry()
660
1401
  check_mcp_auto_configuration()
661
1402
  verify_mcp_gateway_startup()
662
1403
  check_for_updates_async()
663
- sync_remote_agents_on_startup() # Sync agents from remote sources
1404
+ sync_remote_agents_on_startup(
1405
+ force_sync=force_sync
1406
+ ) # Sync agents from remote sources
1407
+ show_agent_summary() # Display agent counts after deployment
664
1408
 
665
1409
  # Skills deployment order (precedence: remote > bundled)
666
1410
  # 1. Deploy bundled skills first (base layer from package)
@@ -668,11 +1412,18 @@ def run_background_services():
668
1412
  # 3. Discover and link runtime skills (user-added skills)
669
1413
  # This ensures remote skills take precedence over bundled skills when names conflict
670
1414
  deploy_bundled_skills() # Base layer: package-bundled skills
671
- sync_remote_skills_on_startup() # Override layer: Git-based skills (takes precedence)
1415
+ sync_remote_skills_on_startup(
1416
+ force_sync=force_sync
1417
+ ) # Override layer: Git-based skills (takes precedence)
672
1418
  discover_and_link_runtime_skills() # Discovery: user-added skills
1419
+ show_skill_summary() # Display skill counts after deployment
1420
+ verify_and_show_pm_skills() # PM skills verification and status
673
1421
 
674
1422
  deploy_output_style_on_startup()
675
1423
 
1424
+ # Auto-install chrome-devtools-mcp for browser automation
1425
+ auto_install_chrome_devtools_on_startup()
1426
+
676
1427
 
677
1428
  def setup_mcp_server_logging(args):
678
1429
  """
@@ -776,11 +1527,19 @@ def check_mcp_auto_configuration():
776
1527
  check_and_configure_mcp()
777
1528
 
778
1529
  # Clear the "Checking..." message by overwriting with spaces
779
- print("\r" + " " * 30 + "\r", end="", flush=True)
1530
+ # Only use carriage return clearing if stdout is a real TTY
1531
+ if sys.stdout.isatty():
1532
+ print("\r" + " " * 30 + "\r", end="", flush=True)
1533
+ else:
1534
+ print() # Simple newline for non-TTY (like Claude Code REPL)
780
1535
 
781
1536
  except Exception as e:
782
1537
  # Clear progress message on error
783
- print("\r" + " " * 30 + "\r", end="", flush=True)
1538
+ # Only use carriage return clearing if stdout is a real TTY
1539
+ if sys.stdout.isatty():
1540
+ print("\r" + " " * 30 + "\r", end="", flush=True)
1541
+ else:
1542
+ print() # Simple newline for non-TTY (like Claude Code REPL)
784
1543
 
785
1544
  # Non-critical - log but don't fail
786
1545
  from ..core.logger import get_logger
@@ -800,18 +1559,10 @@ def verify_mcp_gateway_startup():
800
1559
  DESIGN DECISION: This is non-blocking - failures are logged but don't prevent
801
1560
  startup to ensure claude-mpm remains functional even if MCP gateway has issues.
802
1561
  """
803
- # Quick verification of MCP services installation
804
- try:
805
- from ..core.logger import get_logger
806
- from ..services.mcp_service_verifier import verify_mcp_services_on_startup
807
-
808
- logger = get_logger("mcp_verify")
809
- all_ok, message = verify_mcp_services_on_startup()
810
- if not all_ok:
811
- logger.warning(message)
812
- except Exception:
813
- # Non-critical - continue with startup
814
- pass
1562
+ # DISABLED: MCP service verification removed - Claude Code handles MCP natively
1563
+ # The previous check warned about missing MCP services, but users should configure
1564
+ # MCP servers through Claude Code's native MCP management, not through claude-mpm.
1565
+ # See: https://docs.anthropic.com/en/docs/claude-code/mcp
815
1566
 
816
1567
  try:
817
1568
  import asyncio
@@ -871,7 +1622,7 @@ def verify_mcp_gateway_startup():
871
1622
  loop.run_until_complete(
872
1623
  asyncio.gather(*pending, return_exceptions=True)
873
1624
  )
874
- except Exception:
1625
+ except Exception: # nosec B110
875
1626
  pass # Ignore cleanup errors
876
1627
  finally:
877
1628
  loop.close()
@@ -965,7 +1716,7 @@ def check_for_updates_async():
965
1716
 
966
1717
  logger = get_logger("upgrade_check")
967
1718
  logger.debug(f"Update check failed (non-critical): {e}")
968
- except Exception:
1719
+ except Exception: # nosec B110
969
1720
  pass # Avoid any errors in error handling
970
1721
  finally:
971
1722
  # Properly clean up event loop
@@ -980,7 +1731,7 @@ def check_for_updates_async():
980
1731
  loop.run_until_complete(
981
1732
  asyncio.gather(*pending, return_exceptions=True)
982
1733
  )
983
- except Exception:
1734
+ except Exception: # nosec B110
984
1735
  pass # Ignore cleanup errors
985
1736
  finally:
986
1737
  loop.close()