claude-mpm 3.4.10__py3-none-any.whl → 5.4.55__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (950) hide show
  1. claude_mpm/BUILD_NUMBER +1 -0
  2. claude_mpm/VERSION +1 -0
  3. claude_mpm/__init__.py +50 -12
  4. claude_mpm/__main__.py +7 -2
  5. claude_mpm/agents/BASE_AGENT.md +164 -0
  6. claude_mpm/agents/BASE_ENGINEER.md +658 -0
  7. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +290 -0
  8. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +2002 -0
  9. claude_mpm/agents/MEMORY.md +72 -0
  10. claude_mpm/agents/PM_INSTRUCTIONS.md +1402 -0
  11. claude_mpm/agents/WORKFLOW.md +111 -0
  12. claude_mpm/agents/__init__.py +92 -80
  13. claude_mpm/agents/agent-template.yaml +83 -0
  14. claude_mpm/agents/agent_loader.py +560 -745
  15. claude_mpm/agents/agent_loader_integration.py +53 -55
  16. claude_mpm/agents/agents_metadata.py +186 -27
  17. claude_mpm/agents/async_agent_loader.py +436 -0
  18. claude_mpm/agents/base_agent.json +8 -4
  19. claude_mpm/agents/frontmatter_validator.py +754 -0
  20. claude_mpm/agents/system_agent_config.py +222 -155
  21. claude_mpm/agents/templates/README.md +465 -0
  22. claude_mpm/agents/templates/__init__.py +17 -13
  23. claude_mpm/agents/templates/circuit-breakers.md +1391 -0
  24. claude_mpm/agents/templates/context-management-examples.md +544 -0
  25. claude_mpm/agents/templates/git-file-tracking.md +584 -0
  26. claude_mpm/agents/templates/pm-examples.md +474 -0
  27. claude_mpm/agents/templates/pm-red-flags.md +310 -0
  28. claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
  29. claude_mpm/agents/templates/research-gate-examples.md +669 -0
  30. claude_mpm/agents/templates/response-format.md +583 -0
  31. claude_mpm/agents/templates/structured-questions-examples.md +615 -0
  32. claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
  33. claude_mpm/agents/templates/ticketing-examples.md +277 -0
  34. claude_mpm/agents/templates/validation-templates.md +312 -0
  35. claude_mpm/cli/__init__.py +90 -128
  36. claude_mpm/cli/__main__.py +33 -0
  37. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  38. claude_mpm/cli/commands/__init__.py +36 -12
  39. claude_mpm/cli/commands/agent_manager.py +1403 -0
  40. claude_mpm/cli/commands/agent_source.py +774 -0
  41. claude_mpm/cli/commands/agent_state_manager.py +335 -0
  42. claude_mpm/cli/commands/agents.py +2503 -168
  43. claude_mpm/cli/commands/agents_cleanup.py +210 -0
  44. claude_mpm/cli/commands/agents_discover.py +338 -0
  45. claude_mpm/cli/commands/aggregate.py +540 -0
  46. claude_mpm/cli/commands/analyze.py +553 -0
  47. claude_mpm/cli/commands/analyze_code.py +528 -0
  48. claude_mpm/cli/commands/auto_configure.py +1053 -0
  49. claude_mpm/cli/commands/cleanup.py +588 -0
  50. claude_mpm/cli/commands/cleanup_orphaned_agents.py +150 -0
  51. claude_mpm/cli/commands/config.py +586 -0
  52. claude_mpm/cli/commands/configure.py +2654 -0
  53. claude_mpm/cli/commands/configure_agent_display.py +282 -0
  54. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  55. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  56. claude_mpm/cli/commands/configure_models.py +18 -0
  57. claude_mpm/cli/commands/configure_navigation.py +184 -0
  58. claude_mpm/cli/commands/configure_paths.py +104 -0
  59. claude_mpm/cli/commands/configure_persistence.py +254 -0
  60. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  61. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  62. claude_mpm/cli/commands/configure_validators.py +73 -0
  63. claude_mpm/cli/commands/dashboard.py +286 -0
  64. claude_mpm/cli/commands/debug.py +1386 -0
  65. claude_mpm/cli/commands/doctor.py +243 -0
  66. claude_mpm/cli/commands/hook_errors.py +277 -0
  67. claude_mpm/cli/commands/info.py +195 -74
  68. claude_mpm/cli/commands/local_deploy.py +534 -0
  69. claude_mpm/cli/commands/mcp.py +205 -0
  70. claude_mpm/cli/commands/mcp_command_router.py +161 -0
  71. claude_mpm/cli/commands/mcp_config.py +154 -0
  72. claude_mpm/cli/commands/mcp_config_commands.py +20 -0
  73. claude_mpm/cli/commands/mcp_external_commands.py +249 -0
  74. claude_mpm/cli/commands/mcp_install_commands.py +346 -0
  75. claude_mpm/cli/commands/mcp_pipx_config.py +208 -0
  76. claude_mpm/cli/commands/mcp_server_commands.py +155 -0
  77. claude_mpm/cli/commands/mcp_setup_external.py +868 -0
  78. claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
  79. claude_mpm/cli/commands/memory.py +585 -846
  80. claude_mpm/cli/commands/monitor.py +228 -310
  81. claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
  82. claude_mpm/cli/commands/mpm_init/core.py +759 -0
  83. claude_mpm/cli/commands/mpm_init/display.py +341 -0
  84. claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
  85. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  86. claude_mpm/cli/commands/mpm_init/modes.py +397 -0
  87. claude_mpm/cli/commands/mpm_init/prompts.py +722 -0
  88. claude_mpm/cli/commands/mpm_init_cli.py +396 -0
  89. claude_mpm/cli/commands/mpm_init_handler.py +195 -0
  90. claude_mpm/cli/commands/postmortem.py +401 -0
  91. claude_mpm/cli/commands/profile.py +276 -0
  92. claude_mpm/cli/commands/run.py +910 -488
  93. claude_mpm/cli/commands/search.py +458 -0
  94. claude_mpm/cli/commands/skill_source.py +694 -0
  95. claude_mpm/cli/commands/skills.py +1246 -0
  96. claude_mpm/cli/commands/summarize.py +413 -0
  97. claude_mpm/cli/commands/tickets.py +536 -53
  98. claude_mpm/cli/commands/uninstall.py +176 -0
  99. claude_mpm/cli/commands/upgrade.py +152 -0
  100. claude_mpm/cli/commands/verify.py +119 -0
  101. claude_mpm/cli/executor.py +297 -0
  102. claude_mpm/cli/helpers.py +105 -0
  103. claude_mpm/cli/interactive/__init__.py +21 -0
  104. claude_mpm/cli/interactive/agent_wizard.py +1947 -0
  105. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  106. claude_mpm/cli/parser.py +87 -563
  107. claude_mpm/cli/parsers/__init__.py +35 -0
  108. claude_mpm/cli/parsers/agent_manager_parser.py +393 -0
  109. claude_mpm/cli/parsers/agent_source_parser.py +171 -0
  110. claude_mpm/cli/parsers/agents_parser.py +575 -0
  111. claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
  112. claude_mpm/cli/parsers/analyze_parser.py +135 -0
  113. claude_mpm/cli/parsers/auto_configure_parser.py +120 -0
  114. claude_mpm/cli/parsers/base_parser.py +644 -0
  115. claude_mpm/cli/parsers/config_parser.py +208 -0
  116. claude_mpm/cli/parsers/configure_parser.py +138 -0
  117. claude_mpm/cli/parsers/dashboard_parser.py +113 -0
  118. claude_mpm/cli/parsers/debug_parser.py +319 -0
  119. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  120. claude_mpm/cli/parsers/mcp_parser.py +195 -0
  121. claude_mpm/cli/parsers/memory_parser.py +138 -0
  122. claude_mpm/cli/parsers/monitor_parser.py +142 -0
  123. claude_mpm/cli/parsers/mpm_init_parser.py +311 -0
  124. claude_mpm/cli/parsers/profile_parser.py +147 -0
  125. claude_mpm/cli/parsers/run_parser.py +157 -0
  126. claude_mpm/cli/parsers/search_parser.py +245 -0
  127. claude_mpm/cli/parsers/skill_source_parser.py +169 -0
  128. claude_mpm/cli/parsers/skills_parser.py +277 -0
  129. claude_mpm/cli/parsers/source_parser.py +138 -0
  130. claude_mpm/cli/parsers/tickets_parser.py +203 -0
  131. claude_mpm/cli/shared/__init__.py +40 -0
  132. claude_mpm/cli/shared/argument_patterns.py +205 -0
  133. claude_mpm/cli/shared/base_command.py +242 -0
  134. claude_mpm/cli/shared/error_handling.py +242 -0
  135. claude_mpm/cli/shared/output_formatters.py +241 -0
  136. claude_mpm/cli/startup.py +1743 -0
  137. claude_mpm/cli/startup_display.py +480 -0
  138. claude_mpm/cli/startup_logging.py +839 -0
  139. claude_mpm/cli/utils.py +136 -47
  140. claude_mpm/cli_module/__init__.py +6 -6
  141. claude_mpm/cli_module/args.py +188 -140
  142. claude_mpm/cli_module/commands.py +79 -70
  143. claude_mpm/cli_module/migration_example.py +42 -64
  144. claude_mpm/commands/__init__.py +14 -0
  145. claude_mpm/commands/mpm-config.md +28 -0
  146. claude_mpm/commands/mpm-doctor.md +20 -0
  147. claude_mpm/commands/mpm-help.md +20 -0
  148. claude_mpm/commands/mpm-init.md +120 -0
  149. claude_mpm/commands/mpm-monitor.md +31 -0
  150. claude_mpm/commands/mpm-organize.md +120 -0
  151. claude_mpm/commands/mpm-postmortem.md +21 -0
  152. claude_mpm/commands/mpm-session-resume.md +30 -0
  153. claude_mpm/commands/mpm-status.md +20 -0
  154. claude_mpm/commands/mpm-ticket-view.md +109 -0
  155. claude_mpm/commands/mpm-version.md +20 -0
  156. claude_mpm/commands/mpm.md +31 -0
  157. claude_mpm/config/__init__.py +42 -2
  158. claude_mpm/config/agent_config.py +402 -0
  159. claude_mpm/config/agent_presets.py +488 -0
  160. claude_mpm/config/agent_sources.py +352 -0
  161. claude_mpm/config/experimental_features.py +217 -0
  162. claude_mpm/config/model_config.py +428 -0
  163. claude_mpm/config/paths.py +258 -0
  164. claude_mpm/config/skill_presets.py +392 -0
  165. claude_mpm/config/skill_sources.py +590 -0
  166. claude_mpm/config/socketio_config.py +125 -83
  167. claude_mpm/constants.py +132 -22
  168. claude_mpm/core/__init__.py +62 -36
  169. claude_mpm/core/agent_name_normalizer.py +71 -73
  170. claude_mpm/core/agent_registry.py +385 -492
  171. claude_mpm/core/agent_session_manager.py +81 -70
  172. claude_mpm/core/api_validator.py +330 -0
  173. claude_mpm/core/base_service.py +159 -122
  174. claude_mpm/core/cache.py +560 -0
  175. claude_mpm/core/claude_runner.py +696 -916
  176. claude_mpm/core/config.py +613 -122
  177. claude_mpm/core/config_aliases.py +74 -73
  178. claude_mpm/core/config_constants.py +314 -0
  179. claude_mpm/core/constants.py +361 -0
  180. claude_mpm/core/container.py +646 -104
  181. claude_mpm/core/enums.py +452 -0
  182. claude_mpm/core/error_handler.py +623 -0
  183. claude_mpm/core/exceptions.py +536 -0
  184. claude_mpm/core/factories.py +105 -109
  185. claude_mpm/core/file_utils.py +764 -0
  186. claude_mpm/core/framework/__init__.py +25 -0
  187. claude_mpm/core/framework/formatters/__init__.py +11 -0
  188. claude_mpm/core/framework/formatters/capability_generator.py +367 -0
  189. claude_mpm/core/framework/formatters/content_formatter.py +278 -0
  190. claude_mpm/core/framework/formatters/context_generator.py +185 -0
  191. claude_mpm/core/framework/loaders/__init__.py +13 -0
  192. claude_mpm/core/framework/loaders/agent_loader.py +213 -0
  193. claude_mpm/core/framework/loaders/file_loader.py +176 -0
  194. claude_mpm/core/framework/loaders/instruction_loader.py +222 -0
  195. claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
  196. claude_mpm/core/framework/processors/__init__.py +11 -0
  197. claude_mpm/core/framework/processors/memory_processor.py +230 -0
  198. claude_mpm/core/framework/processors/metadata_processor.py +146 -0
  199. claude_mpm/core/framework/processors/template_processor.py +244 -0
  200. claude_mpm/core/framework_loader.py +485 -414
  201. claude_mpm/core/hook_error_memory.py +381 -0
  202. claude_mpm/core/hook_manager.py +246 -86
  203. claude_mpm/core/hook_performance_config.py +147 -0
  204. claude_mpm/core/injectable_service.py +72 -63
  205. claude_mpm/core/instruction_reinforcement_hook.py +267 -0
  206. claude_mpm/core/interactive_session.py +670 -0
  207. claude_mpm/core/interfaces.py +570 -164
  208. claude_mpm/core/lazy.py +467 -0
  209. claude_mpm/core/log_manager.py +707 -0
  210. claude_mpm/core/logger.py +295 -134
  211. claude_mpm/core/logging_config.py +474 -0
  212. claude_mpm/core/logging_utils.py +520 -0
  213. claude_mpm/core/minimal_framework_loader.py +24 -22
  214. claude_mpm/core/mixins.py +30 -29
  215. claude_mpm/core/oneshot_session.py +594 -0
  216. claude_mpm/core/optimized_agent_loader.py +479 -0
  217. claude_mpm/core/optimized_startup.py +554 -0
  218. claude_mpm/core/output_style_manager.py +483 -0
  219. claude_mpm/core/pm_hook_interceptor.py +197 -82
  220. claude_mpm/core/protocols/__init__.py +23 -0
  221. claude_mpm/core/protocols/runner_protocol.py +103 -0
  222. claude_mpm/core/protocols/session_protocol.py +131 -0
  223. claude_mpm/core/service_registry.py +153 -116
  224. claude_mpm/core/session_manager.py +179 -64
  225. claude_mpm/core/shared/__init__.py +17 -0
  226. claude_mpm/core/shared/config_loader.py +326 -0
  227. claude_mpm/core/shared/path_resolver.py +281 -0
  228. claude_mpm/core/shared/singleton_manager.py +221 -0
  229. claude_mpm/core/socketio_pool.py +400 -137
  230. claude_mpm/core/system_context.py +38 -0
  231. claude_mpm/core/tool_access_control.py +64 -57
  232. claude_mpm/core/types.py +307 -0
  233. claude_mpm/core/typing_utils.py +553 -0
  234. claude_mpm/core/unified_agent_registry.py +969 -0
  235. claude_mpm/core/unified_config.py +570 -0
  236. claude_mpm/core/unified_paths.py +941 -0
  237. claude_mpm/dashboard/__init__.py +12 -0
  238. claude_mpm/dashboard/api/simple_directory.py +261 -0
  239. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  240. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +1 -0
  241. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +1 -0
  242. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +1 -0
  243. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +24 -0
  244. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B0uc0UOD.js +36 -0
  245. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7RN905-.js +1 -0
  246. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7xVLGWV.js +2 -0
  247. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BIF9m_hv.js +61 -0
  248. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +1 -0
  249. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BPYeabCQ.js +1 -0
  250. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  251. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
  252. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Be7GpZd6.js +7 -0
  253. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bh0LDWpI.js +145 -0
  254. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BofRWZRR.js +10 -0
  255. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BovzEFCE.js +30 -0
  256. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C30mlcqg.js +165 -0
  257. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4B-KCzX.js +1 -0
  258. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4JcI4KD.js +122 -0
  259. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CBBdVcY8.js +1 -0
  260. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CDuw-vjf.js +1 -0
  261. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C_Usid8X.js +15 -0
  262. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cfqx1Qun.js +10 -0
  263. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CiIAseT4.js +128 -0
  264. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  265. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CnA0NrzZ.js +1 -0
  266. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cs_tUR18.js +24 -0
  267. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  268. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CyWMqx4W.js +43 -0
  269. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzZX-COe.js +220 -0
  270. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzeYkLYB.js +65 -0
  271. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D3k0OPJN.js +4 -0
  272. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9lljYKQ.js +1 -0
  273. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DGkLK5U1.js +267 -0
  274. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DI7hHRFL.js +1 -0
  275. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DLVjFsZ3.js +139 -0
  276. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUrLdbGD.js +89 -0
  277. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  278. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DY1XQ8fi.js +2 -0
  279. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DZX00Y4g.js +1 -0
  280. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +1 -0
  281. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DaimHw_p.js +68 -0
  282. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +323 -0
  283. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dhb8PKl3.js +1 -0
  284. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dle-35c7.js +64 -0
  285. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DmxopI1J.js +1 -0
  286. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DwBR2MJi.js +60 -0
  287. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/GYwsonyD.js +1 -0
  288. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  289. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
  290. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/RJiighC3.js +1 -0
  291. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Vzk33B_K.js +2 -0
  292. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ZGh7QtNv.js +7 -0
  293. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bT1r9zLR.js +1 -0
  294. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bTOqqlTd.js +1 -0
  295. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/eNVUfhuA.js +1 -0
  296. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/iEWssX7S.js +162 -0
  297. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/sQeU3Y1z.js +1 -0
  298. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uuIeMWc-.js +1 -0
  299. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.D6-I5TpK.js +2 -0
  300. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +1 -0
  301. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.m1gL8KXf.js +1 -0
  302. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.CgNOuw-d.js +1 -0
  303. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +1 -0
  304. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  305. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  306. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  307. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  308. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  309. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  310. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  311. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  312. claude_mpm/experimental/__init__.py +10 -0
  313. claude_mpm/experimental/cli_enhancements.py +104 -89
  314. claude_mpm/generators/__init__.py +1 -1
  315. claude_mpm/generators/agent_profile_generator.py +76 -66
  316. claude_mpm/hooks/__init__.py +37 -1
  317. claude_mpm/hooks/base_hook.py +37 -32
  318. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  319. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  320. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  321. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  322. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  323. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  324. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  325. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  326. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  327. claude_mpm/hooks/claude_hooks/connection_pool.py +250 -0
  328. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  329. claude_mpm/hooks/claude_hooks/event_handlers.py +888 -0
  330. claude_mpm/hooks/claude_hooks/hook_handler.py +652 -875
  331. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +10 -7
  332. claude_mpm/hooks/claude_hooks/installer.py +806 -0
  333. claude_mpm/hooks/claude_hooks/memory_integration.py +249 -0
  334. claude_mpm/hooks/claude_hooks/response_tracking.py +412 -0
  335. claude_mpm/hooks/claude_hooks/services/__init__.py +15 -0
  336. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  337. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  338. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  339. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  340. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  341. claude_mpm/hooks/claude_hooks/services/connection_manager.py +229 -0
  342. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +254 -0
  343. claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
  344. claude_mpm/hooks/claude_hooks/services/state_manager.py +284 -0
  345. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
  346. claude_mpm/hooks/claude_hooks/tool_analysis.py +224 -0
  347. claude_mpm/hooks/failure_learning/__init__.py +54 -0
  348. claude_mpm/hooks/failure_learning/failure_detection_hook.py +230 -0
  349. claude_mpm/hooks/failure_learning/fix_detection_hook.py +212 -0
  350. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +281 -0
  351. claude_mpm/hooks/instruction_reinforcement.py +301 -0
  352. claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
  353. claude_mpm/hooks/kuzu_memory_hook.py +386 -0
  354. claude_mpm/hooks/kuzu_response_hook.py +179 -0
  355. claude_mpm/hooks/memory_integration_hook.py +201 -107
  356. claude_mpm/hooks/session_resume_hook.py +121 -0
  357. claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
  358. claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
  359. claude_mpm/hooks/tool_call_interceptor.py +92 -76
  360. claude_mpm/hooks/validation_hooks.py +62 -54
  361. claude_mpm/init.py +518 -83
  362. claude_mpm/models/__init__.py +9 -9
  363. claude_mpm/models/agent_definition.py +40 -23
  364. claude_mpm/models/agent_session.py +538 -0
  365. claude_mpm/models/git_repository.py +198 -0
  366. claude_mpm/models/resume_log.py +340 -0
  367. claude_mpm/schemas/__init__.py +12 -0
  368. claude_mpm/scripts/__init__.py +15 -0
  369. claude_mpm/scripts/claude-hook-handler.sh +227 -0
  370. claude_mpm/scripts/launch_monitor.py +165 -0
  371. claude_mpm/scripts/mpm_doctor.py +322 -0
  372. claude_mpm/scripts/socketio_daemon.py +189 -200
  373. claude_mpm/scripts/start_activity_logging.py +91 -0
  374. claude_mpm/services/__init__.py +208 -39
  375. claude_mpm/services/agent_capabilities_service.py +266 -0
  376. claude_mpm/services/agents/__init__.py +89 -0
  377. claude_mpm/services/agents/agent_builder.py +514 -0
  378. claude_mpm/services/agents/agent_preset_service.py +238 -0
  379. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  380. claude_mpm/services/agents/agent_review_service.py +280 -0
  381. claude_mpm/services/agents/agent_selection_service.py +484 -0
  382. claude_mpm/services/agents/auto_config_manager.py +796 -0
  383. claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
  384. claude_mpm/services/agents/cache_git_manager.py +621 -0
  385. claude_mpm/services/agents/deployment/__init__.py +21 -0
  386. claude_mpm/services/agents/deployment/agent_config_provider.py +410 -0
  387. claude_mpm/services/agents/deployment/agent_configuration_manager.py +358 -0
  388. claude_mpm/services/agents/deployment/agent_definition_factory.py +80 -0
  389. claude_mpm/services/agents/deployment/agent_deployment.py +1037 -0
  390. claude_mpm/services/agents/deployment/agent_discovery_service.py +546 -0
  391. claude_mpm/services/agents/deployment/agent_environment_manager.py +288 -0
  392. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +383 -0
  393. claude_mpm/services/agents/deployment/agent_format_converter.py +505 -0
  394. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +160 -0
  395. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +957 -0
  396. claude_mpm/services/agents/deployment/agent_metrics_collector.py +273 -0
  397. claude_mpm/services/agents/deployment/agent_operation_service.py +573 -0
  398. claude_mpm/services/agents/deployment/agent_record_service.py +418 -0
  399. claude_mpm/services/agents/deployment/agent_restore_handler.py +84 -0
  400. claude_mpm/services/agents/deployment/agent_state_service.py +381 -0
  401. claude_mpm/services/agents/deployment/agent_template_builder.py +1369 -0
  402. claude_mpm/services/agents/deployment/agent_validator.py +376 -0
  403. claude_mpm/services/agents/deployment/agent_version_manager.py +322 -0
  404. claude_mpm/services/{agent_versioning.py → agents/deployment/agent_versioning.py} +10 -13
  405. claude_mpm/services/agents/deployment/agents_directory_resolver.py +149 -0
  406. claude_mpm/services/agents/deployment/async_agent_deployment.py +768 -0
  407. claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
  408. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  409. claude_mpm/services/agents/deployment/config/deployment_config.py +181 -0
  410. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  411. claude_mpm/services/agents/deployment/deployment_config_loader.py +178 -0
  412. claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
  413. claude_mpm/services/agents/deployment/deployment_type_detector.py +120 -0
  414. claude_mpm/services/agents/deployment/deployment_wrapper.py +129 -0
  415. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  416. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  417. claude_mpm/services/agents/deployment/facade/deployment_executor.py +70 -0
  418. claude_mpm/services/agents/deployment/facade/deployment_facade.py +269 -0
  419. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  420. claude_mpm/services/agents/deployment/interface_adapter.py +226 -0
  421. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  422. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  423. claude_mpm/services/agents/deployment/local_template_deployment.py +362 -0
  424. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +1478 -0
  425. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  426. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  427. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +162 -0
  428. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  429. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  430. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +240 -0
  431. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +110 -0
  432. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +80 -0
  433. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +92 -0
  434. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +101 -0
  435. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  436. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +102 -0
  437. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  438. claude_mpm/services/agents/deployment/processors/agent_processor.py +269 -0
  439. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +311 -0
  440. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +862 -0
  441. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  442. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  443. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  444. claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
  445. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  446. claude_mpm/services/agents/deployment/strategies/base_strategy.py +113 -0
  447. claude_mpm/services/agents/deployment/strategies/project_strategy.py +148 -0
  448. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  449. claude_mpm/services/agents/deployment/strategies/system_strategy.py +131 -0
  450. claude_mpm/services/agents/deployment/strategies/user_strategy.py +130 -0
  451. claude_mpm/services/agents/deployment/system_instructions_deployer.py +228 -0
  452. claude_mpm/services/agents/deployment/validation/__init__.py +21 -0
  453. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  454. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  455. claude_mpm/services/agents/deployment/validation/template_validator.py +319 -0
  456. claude_mpm/services/agents/deployment/validation/validation_result.py +214 -0
  457. claude_mpm/services/agents/git_source_manager.py +682 -0
  458. claude_mpm/services/agents/loading/__init__.py +11 -0
  459. claude_mpm/services/{agent_profile_loader.py → agents/loading/agent_profile_loader.py} +306 -228
  460. claude_mpm/services/{base_agent_manager.py → agents/loading/base_agent_manager.py} +106 -91
  461. claude_mpm/services/agents/loading/framework_agent_loader.py +433 -0
  462. claude_mpm/services/agents/local_template_manager.py +784 -0
  463. claude_mpm/services/agents/management/__init__.py +9 -0
  464. claude_mpm/services/{agent_capabilities_generator.py → agents/management/agent_capabilities_generator.py} +92 -69
  465. claude_mpm/services/{agent_management_service.py → agents/management/agent_management_service.py} +219 -168
  466. claude_mpm/services/agents/memory/__init__.py +22 -0
  467. claude_mpm/services/agents/memory/agent_memory_manager.py +784 -0
  468. claude_mpm/services/{agent_persistence_service.py → agents/memory/agent_persistence_service.py} +20 -18
  469. claude_mpm/services/agents/memory/content_manager.py +470 -0
  470. claude_mpm/services/agents/memory/memory_categorization_service.py +167 -0
  471. claude_mpm/services/agents/memory/memory_file_service.py +129 -0
  472. claude_mpm/services/agents/memory/memory_format_service.py +201 -0
  473. claude_mpm/services/agents/memory/memory_limits_service.py +101 -0
  474. claude_mpm/services/agents/memory/template_generator.py +83 -0
  475. claude_mpm/services/agents/observers.py +547 -0
  476. claude_mpm/services/agents/recommender.py +617 -0
  477. claude_mpm/services/agents/registry/__init__.py +30 -0
  478. claude_mpm/services/agents/registry/deployed_agent_discovery.py +273 -0
  479. claude_mpm/services/{agent_modification_tracker.py → agents/registry/modification_tracker.py} +370 -295
  480. claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
  481. claude_mpm/services/agents/sources/__init__.py +13 -0
  482. claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
  483. claude_mpm/services/agents/sources/git_source_sync_service.py +1202 -0
  484. claude_mpm/services/agents/startup_sync.py +259 -0
  485. claude_mpm/services/agents/toolchain_detector.py +478 -0
  486. claude_mpm/services/analysis/__init__.py +35 -0
  487. claude_mpm/services/analysis/clone_detector.py +1030 -0
  488. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  489. claude_mpm/services/analysis/postmortem_service.py +765 -0
  490. claude_mpm/services/async_session_logger.py +665 -0
  491. claude_mpm/services/claude_session_logger.py +321 -0
  492. claude_mpm/services/cli/__init__.py +18 -0
  493. claude_mpm/services/cli/agent_cleanup_service.py +408 -0
  494. claude_mpm/services/cli/agent_dependency_service.py +395 -0
  495. claude_mpm/services/cli/agent_listing_service.py +463 -0
  496. claude_mpm/services/cli/agent_output_formatter.py +605 -0
  497. claude_mpm/services/cli/agent_validation_service.py +590 -0
  498. claude_mpm/services/cli/memory_crud_service.py +622 -0
  499. claude_mpm/services/cli/memory_output_formatter.py +604 -0
  500. claude_mpm/services/cli/resume_service.py +617 -0
  501. claude_mpm/services/cli/session_manager.py +604 -0
  502. claude_mpm/services/cli/session_pause_manager.py +504 -0
  503. claude_mpm/services/cli/session_resume_helper.py +372 -0
  504. claude_mpm/services/cli/startup_checker.py +362 -0
  505. claude_mpm/services/cli/unified_dashboard_manager.py +439 -0
  506. claude_mpm/services/command_deployment_service.py +446 -0
  507. claude_mpm/services/command_handler_service.py +221 -0
  508. claude_mpm/services/communication/__init__.py +22 -0
  509. claude_mpm/services/core/__init__.py +108 -0
  510. claude_mpm/services/core/base.py +269 -0
  511. claude_mpm/services/core/cache_manager.py +309 -0
  512. claude_mpm/services/core/interfaces/__init__.py +273 -0
  513. claude_mpm/services/core/interfaces/agent.py +514 -0
  514. claude_mpm/services/core/interfaces/communication.py +316 -0
  515. claude_mpm/services/core/interfaces/health.py +169 -0
  516. claude_mpm/services/core/interfaces/infrastructure.py +357 -0
  517. claude_mpm/services/core/interfaces/model.py +281 -0
  518. claude_mpm/services/core/interfaces/process.py +372 -0
  519. claude_mpm/services/core/interfaces/project.py +121 -0
  520. claude_mpm/services/core/interfaces/restart.py +307 -0
  521. claude_mpm/services/core/interfaces/service.py +405 -0
  522. claude_mpm/services/core/interfaces/stability.py +260 -0
  523. claude_mpm/services/core/interfaces.py +81 -0
  524. claude_mpm/services/core/memory_manager.py +682 -0
  525. claude_mpm/services/core/models/__init__.py +70 -0
  526. claude_mpm/services/core/models/agent_config.py +384 -0
  527. claude_mpm/services/core/models/health.py +162 -0
  528. claude_mpm/services/core/models/process.py +239 -0
  529. claude_mpm/services/core/models/restart.py +302 -0
  530. claude_mpm/services/core/models/stability.py +264 -0
  531. claude_mpm/services/core/models/toolchain.py +306 -0
  532. claude_mpm/services/core/path_resolver.py +517 -0
  533. claude_mpm/services/core/service_container.py +520 -0
  534. claude_mpm/services/core/service_interfaces.py +436 -0
  535. claude_mpm/services/diagnostics/__init__.py +18 -0
  536. claude_mpm/services/diagnostics/checks/__init__.py +38 -0
  537. claude_mpm/services/diagnostics/checks/agent_check.py +370 -0
  538. claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
  539. claude_mpm/services/diagnostics/checks/base_check.py +60 -0
  540. claude_mpm/services/diagnostics/checks/claude_code_check.py +270 -0
  541. claude_mpm/services/diagnostics/checks/common_issues_check.py +363 -0
  542. claude_mpm/services/diagnostics/checks/configuration_check.py +306 -0
  543. claude_mpm/services/diagnostics/checks/filesystem_check.py +233 -0
  544. claude_mpm/services/diagnostics/checks/installation_check.py +520 -0
  545. claude_mpm/services/diagnostics/checks/instructions_check.py +415 -0
  546. claude_mpm/services/diagnostics/checks/mcp_check.py +330 -0
  547. claude_mpm/services/diagnostics/checks/mcp_services_check.py +1058 -0
  548. claude_mpm/services/diagnostics/checks/monitor_check.py +281 -0
  549. claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
  550. claude_mpm/services/diagnostics/checks/startup_log_check.py +319 -0
  551. claude_mpm/services/diagnostics/diagnostic_runner.py +286 -0
  552. claude_mpm/services/diagnostics/doctor_reporter.py +578 -0
  553. claude_mpm/services/diagnostics/models.py +138 -0
  554. claude_mpm/services/event_aggregator.py +582 -0
  555. claude_mpm/services/event_bus/__init__.py +18 -0
  556. claude_mpm/services/event_bus/config.py +186 -0
  557. claude_mpm/services/event_bus/direct_relay.py +312 -0
  558. claude_mpm/services/event_bus/event_bus.py +396 -0
  559. claude_mpm/services/event_bus/relay.py +326 -0
  560. claude_mpm/services/events/__init__.py +44 -0
  561. claude_mpm/services/events/consumers/__init__.py +18 -0
  562. claude_mpm/services/events/consumers/dead_letter.py +306 -0
  563. claude_mpm/services/events/consumers/logging.py +184 -0
  564. claude_mpm/services/events/consumers/metrics.py +241 -0
  565. claude_mpm/services/events/consumers/socketio.py +377 -0
  566. claude_mpm/services/events/core.py +480 -0
  567. claude_mpm/services/events/interfaces.py +214 -0
  568. claude_mpm/services/events/producers/__init__.py +14 -0
  569. claude_mpm/services/events/producers/hook.py +269 -0
  570. claude_mpm/services/events/producers/system.py +329 -0
  571. claude_mpm/services/exceptions.py +433 -353
  572. claude_mpm/services/framework_claude_md_generator/__init__.py +81 -80
  573. claude_mpm/services/framework_claude_md_generator/content_assembler.py +74 -67
  574. claude_mpm/services/framework_claude_md_generator/content_validator.py +66 -62
  575. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +82 -60
  576. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +36 -37
  577. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +41 -40
  578. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +15 -15
  579. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +5 -4
  580. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  581. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  582. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  583. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  584. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +5 -4
  585. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  586. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  587. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +26 -30
  588. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +6 -5
  589. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  590. claude_mpm/services/framework_claude_md_generator/version_manager.py +31 -30
  591. claude_mpm/services/git/__init__.py +21 -0
  592. claude_mpm/services/git/git_operations_service.py +579 -0
  593. claude_mpm/services/github/__init__.py +21 -0
  594. claude_mpm/services/github/github_cli_service.py +397 -0
  595. claude_mpm/services/hook_installer_service.py +506 -0
  596. claude_mpm/services/hook_service.py +159 -111
  597. claude_mpm/services/infrastructure/__init__.py +52 -0
  598. claude_mpm/services/infrastructure/context_preservation.py +569 -0
  599. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  600. claude_mpm/services/infrastructure/logging.py +209 -0
  601. claude_mpm/services/infrastructure/monitoring/__init__.py +39 -0
  602. claude_mpm/services/infrastructure/monitoring/aggregator.py +432 -0
  603. claude_mpm/services/infrastructure/monitoring/base.py +122 -0
  604. claude_mpm/services/infrastructure/monitoring/legacy.py +203 -0
  605. claude_mpm/services/infrastructure/monitoring/network.py +219 -0
  606. claude_mpm/services/infrastructure/monitoring/process.py +343 -0
  607. claude_mpm/services/infrastructure/monitoring/resources.py +244 -0
  608. claude_mpm/services/infrastructure/monitoring/service.py +368 -0
  609. claude_mpm/services/infrastructure/monitoring.py +71 -0
  610. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  611. claude_mpm/services/instructions/__init__.py +9 -0
  612. claude_mpm/services/instructions/instruction_cache_service.py +374 -0
  613. claude_mpm/services/local_ops/__init__.py +155 -0
  614. claude_mpm/services/local_ops/crash_detector.py +257 -0
  615. claude_mpm/services/local_ops/health_checks/__init__.py +26 -0
  616. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  617. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  618. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  619. claude_mpm/services/local_ops/health_manager.py +427 -0
  620. claude_mpm/services/local_ops/log_monitor.py +396 -0
  621. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  622. claude_mpm/services/local_ops/process_manager.py +595 -0
  623. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  624. claude_mpm/services/local_ops/restart_manager.py +401 -0
  625. claude_mpm/services/local_ops/restart_policy.py +387 -0
  626. claude_mpm/services/local_ops/state_manager.py +372 -0
  627. claude_mpm/services/local_ops/unified_manager.py +600 -0
  628. claude_mpm/services/mcp_config_manager.py +1542 -0
  629. claude_mpm/services/mcp_service_verifier.py +732 -0
  630. claude_mpm/services/memory/__init__.py +19 -0
  631. claude_mpm/services/{memory_builder.py → memory/builder.py} +465 -373
  632. claude_mpm/services/memory/cache/__init__.py +14 -0
  633. claude_mpm/services/{shared_prompt_cache.py → memory/cache/shared_prompt_cache.py} +237 -200
  634. claude_mpm/services/memory/cache/simple_cache.py +331 -0
  635. claude_mpm/services/memory/failure_tracker.py +578 -0
  636. claude_mpm/services/memory/indexed_memory.py +648 -0
  637. claude_mpm/services/{memory_optimizer.py → memory/optimizer.py} +272 -243
  638. claude_mpm/services/memory/router.py +951 -0
  639. claude_mpm/services/memory_hook_service.py +470 -0
  640. claude_mpm/services/model/__init__.py +147 -0
  641. claude_mpm/services/model/base_provider.py +365 -0
  642. claude_mpm/services/model/claude_provider.py +412 -0
  643. claude_mpm/services/model/model_router.py +452 -0
  644. claude_mpm/services/model/ollama_provider.py +415 -0
  645. claude_mpm/services/monitor/__init__.py +20 -0
  646. claude_mpm/services/monitor/daemon.py +698 -0
  647. claude_mpm/services/monitor/daemon_manager.py +1076 -0
  648. claude_mpm/services/monitor/event_emitter.py +350 -0
  649. claude_mpm/services/monitor/handlers/__init__.py +21 -0
  650. claude_mpm/services/monitor/handlers/code_analysis.py +332 -0
  651. claude_mpm/services/monitor/handlers/dashboard.py +299 -0
  652. claude_mpm/services/monitor/handlers/file.py +264 -0
  653. claude_mpm/services/monitor/handlers/hooks.py +512 -0
  654. claude_mpm/services/monitor/management/__init__.py +18 -0
  655. claude_mpm/services/monitor/management/health.py +124 -0
  656. claude_mpm/services/monitor/management/lifecycle.py +730 -0
  657. claude_mpm/services/monitor/server.py +1493 -0
  658. claude_mpm/services/monitor_build_service.py +349 -0
  659. claude_mpm/services/native_agent_converter.py +356 -0
  660. claude_mpm/services/orphan_detection.py +786 -0
  661. claude_mpm/services/pm_skills_deployer.py +707 -0
  662. claude_mpm/services/port_manager.py +597 -0
  663. claude_mpm/services/pr/__init__.py +14 -0
  664. claude_mpm/services/pr/pr_template_service.py +329 -0
  665. claude_mpm/services/profile_manager.py +337 -0
  666. claude_mpm/services/project/__init__.py +44 -0
  667. claude_mpm/services/{project_analyzer.py → project/analyzer.py} +541 -291
  668. claude_mpm/services/project/analyzer_v2.py +566 -0
  669. claude_mpm/services/project/architecture_analyzer.py +461 -0
  670. claude_mpm/services/project/archive_manager.py +1045 -0
  671. claude_mpm/services/project/dependency_analyzer.py +462 -0
  672. claude_mpm/services/project/detection_strategies.py +719 -0
  673. claude_mpm/services/project/documentation_manager.py +554 -0
  674. claude_mpm/services/project/enhanced_analyzer.py +572 -0
  675. claude_mpm/services/project/language_analyzer.py +265 -0
  676. claude_mpm/services/project/metrics_collector.py +407 -0
  677. claude_mpm/services/project/project_organizer.py +1009 -0
  678. claude_mpm/services/project/registry.py +636 -0
  679. claude_mpm/services/project/toolchain_analyzer.py +583 -0
  680. claude_mpm/services/project_port_allocator.py +596 -0
  681. claude_mpm/services/recovery_manager.py +293 -240
  682. claude_mpm/services/response_tracker.py +267 -0
  683. claude_mpm/services/runner_configuration_service.py +605 -0
  684. claude_mpm/services/self_upgrade_service.py +608 -0
  685. claude_mpm/services/session_management_service.py +314 -0
  686. claude_mpm/services/session_manager.py +380 -0
  687. claude_mpm/services/shared/__init__.py +21 -0
  688. claude_mpm/services/shared/async_service_base.py +216 -0
  689. claude_mpm/services/shared/config_service_base.py +301 -0
  690. claude_mpm/services/shared/lifecycle_service_base.py +308 -0
  691. claude_mpm/services/shared/manager_base.py +315 -0
  692. claude_mpm/services/shared/service_factory.py +309 -0
  693. claude_mpm/services/skills/__init__.py +21 -0
  694. claude_mpm/services/skills/git_skill_source_manager.py +1324 -0
  695. claude_mpm/services/skills/selective_skill_deployer.py +744 -0
  696. claude_mpm/services/skills/skill_discovery_service.py +568 -0
  697. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  698. claude_mpm/services/skills_config.py +547 -0
  699. claude_mpm/services/skills_deployer.py +1168 -0
  700. claude_mpm/services/socketio/__init__.py +25 -0
  701. claude_mpm/services/socketio/client_proxy.py +229 -0
  702. claude_mpm/services/socketio/dashboard_server.py +362 -0
  703. claude_mpm/services/socketio/event_normalizer.py +798 -0
  704. claude_mpm/services/socketio/handlers/__init__.py +30 -0
  705. claude_mpm/services/socketio/handlers/base.py +136 -0
  706. claude_mpm/services/socketio/handlers/code_analysis.py +682 -0
  707. claude_mpm/services/socketio/handlers/connection.py +643 -0
  708. claude_mpm/services/socketio/handlers/connection_handler.py +333 -0
  709. claude_mpm/services/socketio/handlers/file.py +263 -0
  710. claude_mpm/services/socketio/handlers/git.py +962 -0
  711. claude_mpm/services/socketio/handlers/hook.py +211 -0
  712. claude_mpm/services/socketio/handlers/memory.py +26 -0
  713. claude_mpm/services/socketio/handlers/project.py +24 -0
  714. claude_mpm/services/socketio/handlers/registry.py +214 -0
  715. claude_mpm/services/socketio/migration_utils.py +343 -0
  716. claude_mpm/services/socketio/monitor_client.py +364 -0
  717. claude_mpm/services/socketio/server/__init__.py +18 -0
  718. claude_mpm/services/socketio/server/broadcaster.py +569 -0
  719. claude_mpm/services/socketio/server/connection_manager.py +579 -0
  720. claude_mpm/services/socketio/server/core.py +1079 -0
  721. claude_mpm/services/socketio/server/eventbus_integration.py +245 -0
  722. claude_mpm/services/socketio/server/main.py +501 -0
  723. claude_mpm/services/socketio_client_manager.py +173 -143
  724. claude_mpm/services/socketio_server.py +38 -1657
  725. claude_mpm/services/subprocess_launcher_service.py +322 -0
  726. claude_mpm/services/system_instructions_service.py +270 -0
  727. claude_mpm/services/ticket_manager.py +25 -209
  728. claude_mpm/services/ticket_services/__init__.py +26 -0
  729. claude_mpm/services/ticket_services/crud_service.py +328 -0
  730. claude_mpm/services/ticket_services/formatter_service.py +290 -0
  731. claude_mpm/services/ticket_services/search_service.py +324 -0
  732. claude_mpm/services/ticket_services/validation_service.py +303 -0
  733. claude_mpm/services/ticket_services/workflow_service.py +244 -0
  734. claude_mpm/services/unified/__init__.py +65 -0
  735. claude_mpm/services/unified/analyzer_strategies/__init__.py +44 -0
  736. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +518 -0
  737. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +680 -0
  738. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +900 -0
  739. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +745 -0
  740. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +733 -0
  741. claude_mpm/services/unified/config_strategies/__init__.py +175 -0
  742. claude_mpm/services/unified/config_strategies/config_schema.py +731 -0
  743. claude_mpm/services/unified/config_strategies/context_strategy.py +747 -0
  744. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1005 -0
  745. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +881 -0
  746. claude_mpm/services/unified/config_strategies/unified_config_service.py +823 -0
  747. claude_mpm/services/unified/config_strategies/validation_strategy.py +1148 -0
  748. claude_mpm/services/unified/deployment_strategies/__init__.py +97 -0
  749. claude_mpm/services/unified/deployment_strategies/base.py +553 -0
  750. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +573 -0
  751. claude_mpm/services/unified/deployment_strategies/local.py +607 -0
  752. claude_mpm/services/unified/deployment_strategies/utils.py +667 -0
  753. claude_mpm/services/unified/deployment_strategies/vercel.py +471 -0
  754. claude_mpm/services/unified/interfaces.py +475 -0
  755. claude_mpm/services/unified/migration.py +509 -0
  756. claude_mpm/services/unified/strategies.py +534 -0
  757. claude_mpm/services/unified/unified_analyzer.py +542 -0
  758. claude_mpm/services/unified/unified_config.py +691 -0
  759. claude_mpm/services/unified/unified_deployment.py +466 -0
  760. claude_mpm/services/utility_service.py +280 -0
  761. claude_mpm/services/version_control/__init__.py +34 -37
  762. claude_mpm/services/version_control/branch_strategy.py +26 -17
  763. claude_mpm/services/version_control/conflict_resolution.py +52 -36
  764. claude_mpm/services/version_control/git_operations.py +183 -49
  765. claude_mpm/services/version_control/semantic_versioning.py +172 -61
  766. claude_mpm/services/version_control/version_parser.py +546 -0
  767. claude_mpm/services/version_service.py +379 -0
  768. claude_mpm/services/visualization/__init__.py +15 -0
  769. claude_mpm/services/visualization/mermaid_generator.py +937 -0
  770. claude_mpm/skills/__init__.py +42 -0
  771. claude_mpm/skills/agent_skills_injector.py +324 -0
  772. claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
  773. claude_mpm/skills/bundled/__init__.py +6 -0
  774. claude_mpm/skills/bundled/api-documentation.md +393 -0
  775. claude_mpm/skills/bundled/async-testing.md +571 -0
  776. claude_mpm/skills/bundled/code-review.md +143 -0
  777. claude_mpm/skills/bundled/database-migration.md +199 -0
  778. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  779. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  780. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  781. claude_mpm/skills/bundled/git-workflow.md +414 -0
  782. claude_mpm/skills/bundled/imagemagick.md +204 -0
  783. claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
  784. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  785. claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
  786. claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
  787. claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
  788. claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
  789. claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -0
  790. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  791. claude_mpm/skills/bundled/pdf.md +141 -0
  792. claude_mpm/skills/bundled/performance-profiling.md +573 -0
  793. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  794. claude_mpm/skills/bundled/security-scanning.md +439 -0
  795. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  796. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  797. claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
  798. claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
  799. claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
  800. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
  801. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  802. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  803. claude_mpm/skills/bundled/xlsx.md +157 -0
  804. claude_mpm/skills/registry.py +286 -0
  805. claude_mpm/skills/skill_manager.py +405 -0
  806. claude_mpm/skills/skills_registry.py +347 -0
  807. claude_mpm/skills/skills_service.py +739 -0
  808. claude_mpm/storage/__init__.py +9 -0
  809. claude_mpm/storage/state_storage.py +546 -0
  810. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  811. claude_mpm/templates/questions/__init__.py +38 -0
  812. claude_mpm/templates/questions/base.py +193 -0
  813. claude_mpm/templates/questions/pr_strategy.py +311 -0
  814. claude_mpm/templates/questions/project_init.py +385 -0
  815. claude_mpm/templates/questions/ticket_mgmt.py +394 -0
  816. claude_mpm/ticket_wrapper.py +2 -2
  817. claude_mpm/tools/__init__.py +10 -0
  818. claude_mpm/tools/__main__.py +208 -0
  819. claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
  820. claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
  821. claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
  822. claude_mpm/tools/code_tree_analyzer/core.py +380 -0
  823. claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
  824. claude_mpm/tools/code_tree_analyzer/events.py +168 -0
  825. claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
  826. claude_mpm/tools/code_tree_analyzer/models.py +39 -0
  827. claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
  828. claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
  829. claude_mpm/tools/code_tree_builder.py +631 -0
  830. claude_mpm/tools/code_tree_events.py +420 -0
  831. claude_mpm/tools/socketio_debug.py +671 -0
  832. claude_mpm/utils/__init__.py +8 -8
  833. claude_mpm/utils/agent_dependency_loader.py +1090 -0
  834. claude_mpm/utils/agent_filters.py +261 -0
  835. claude_mpm/utils/common.py +544 -0
  836. claude_mpm/utils/config_manager.py +168 -126
  837. claude_mpm/utils/console.py +11 -0
  838. claude_mpm/utils/database_connector.py +298 -0
  839. claude_mpm/utils/dependency_cache.py +373 -0
  840. claude_mpm/utils/dependency_manager.py +60 -59
  841. claude_mpm/utils/dependency_strategies.py +381 -0
  842. claude_mpm/utils/display_helper.py +260 -0
  843. claude_mpm/utils/environment_context.py +313 -0
  844. claude_mpm/utils/error_handler.py +78 -66
  845. claude_mpm/utils/file_utils.py +305 -0
  846. claude_mpm/utils/framework_detection.py +12 -11
  847. claude_mpm/utils/git_analyzer.py +407 -0
  848. claude_mpm/utils/gitignore.py +244 -0
  849. claude_mpm/utils/import_migration_example.py +12 -60
  850. claude_mpm/utils/imports.py +48 -45
  851. claude_mpm/utils/log_cleanup.py +627 -0
  852. claude_mpm/utils/migration.py +372 -0
  853. claude_mpm/utils/path_operations.py +110 -104
  854. claude_mpm/utils/progress.py +387 -0
  855. claude_mpm/utils/robust_installer.py +823 -0
  856. claude_mpm/utils/session_logging.py +121 -0
  857. claude_mpm/utils/structured_questions.py +619 -0
  858. claude_mpm/utils/subprocess_utils.py +343 -0
  859. claude_mpm/validation/__init__.py +1 -1
  860. claude_mpm/validation/agent_validator.py +214 -108
  861. claude_mpm/validation/frontmatter_validator.py +252 -0
  862. claude_mpm-5.4.55.dist-info/METADATA +999 -0
  863. claude_mpm-5.4.55.dist-info/RECORD +868 -0
  864. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.55.dist-info}/entry_points.txt +1 -3
  865. claude_mpm-5.4.55.dist-info/licenses/LICENSE +94 -0
  866. claude_mpm-5.4.55.dist-info/licenses/LICENSE-FAQ.md +153 -0
  867. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -88
  868. claude_mpm/agents/INSTRUCTIONS.md +0 -352
  869. claude_mpm/agents/backups/INSTRUCTIONS.md +0 -352
  870. claude_mpm/agents/base_agent_loader.py +0 -529
  871. claude_mpm/agents/schema/agent_schema.json +0 -314
  872. claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -36
  873. claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +0 -46
  874. claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +0 -45
  875. claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +0 -49
  876. claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +0 -46
  877. claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +0 -45
  878. claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +0 -49
  879. claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +0 -46
  880. claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +0 -46
  881. claude_mpm/agents/templates/data_engineer.json +0 -110
  882. claude_mpm/agents/templates/documentation.json +0 -109
  883. claude_mpm/agents/templates/engineer.json +0 -113
  884. claude_mpm/agents/templates/ops.json +0 -109
  885. claude_mpm/agents/templates/pm.json +0 -25
  886. claude_mpm/agents/templates/qa.json +0 -111
  887. claude_mpm/agents/templates/research.json +0 -65
  888. claude_mpm/agents/templates/security.json +0 -113
  889. claude_mpm/agents/templates/test_integration.json +0 -112
  890. claude_mpm/agents/templates/version_control.json +0 -107
  891. claude_mpm/cli/commands/ui.py +0 -57
  892. claude_mpm/core/simple_runner.py +0 -1046
  893. claude_mpm/dashboard/open_dashboard.py +0 -34
  894. claude_mpm/deployment_paths.py +0 -261
  895. claude_mpm/hooks/builtin/__init__.py +0 -1
  896. claude_mpm/hooks/builtin/logging_hook_example.py +0 -165
  897. claude_mpm/hooks/builtin/memory_hooks_example.py +0 -67
  898. claude_mpm/hooks/builtin/mpm_command_hook.py +0 -125
  899. claude_mpm/hooks/builtin/post_delegation_hook_example.py +0 -124
  900. claude_mpm/hooks/builtin/pre_delegation_hook_example.py +0 -125
  901. claude_mpm/hooks/builtin/submit_hook_example.py +0 -100
  902. claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +0 -237
  903. claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +0 -240
  904. claude_mpm/hooks/builtin/workflow_start_hook.py +0 -181
  905. claude_mpm/orchestration/__init__.py +0 -6
  906. claude_mpm/orchestration/archive/direct_orchestrator.py +0 -195
  907. claude_mpm/orchestration/archive/factory.py +0 -215
  908. claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +0 -188
  909. claude_mpm/orchestration/archive/hook_integration_example.py +0 -178
  910. claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +0 -826
  911. claude_mpm/orchestration/archive/orchestrator.py +0 -501
  912. claude_mpm/orchestration/archive/pexpect_orchestrator.py +0 -252
  913. claude_mpm/orchestration/archive/pty_orchestrator.py +0 -270
  914. claude_mpm/orchestration/archive/simple_orchestrator.py +0 -82
  915. claude_mpm/orchestration/archive/subprocess_orchestrator.py +0 -801
  916. claude_mpm/orchestration/archive/system_prompt_orchestrator.py +0 -278
  917. claude_mpm/orchestration/archive/wrapper_orchestrator.py +0 -187
  918. claude_mpm/schemas/workflow_validator.py +0 -411
  919. claude_mpm/services/agent_deployment.py +0 -1534
  920. claude_mpm/services/agent_lifecycle_manager.py +0 -1169
  921. claude_mpm/services/agent_memory_manager.py +0 -1415
  922. claude_mpm/services/agent_registry.py +0 -676
  923. claude_mpm/services/deployed_agent_discovery.py +0 -226
  924. claude_mpm/services/framework_agent_loader.py +0 -337
  925. claude_mpm/services/framework_claude_md_generator.py +0 -621
  926. claude_mpm/services/health_monitor.py +0 -892
  927. claude_mpm/services/memory_router.py +0 -538
  928. claude_mpm/services/parent_directory_manager/__init__.py +0 -577
  929. claude_mpm/services/parent_directory_manager/backup_manager.py +0 -258
  930. claude_mpm/services/parent_directory_manager/config_manager.py +0 -210
  931. claude_mpm/services/parent_directory_manager/deduplication_manager.py +0 -279
  932. claude_mpm/services/parent_directory_manager/framework_protector.py +0 -143
  933. claude_mpm/services/parent_directory_manager/operations.py +0 -186
  934. claude_mpm/services/parent_directory_manager/state_manager.py +0 -624
  935. claude_mpm/services/parent_directory_manager/template_deployer.py +0 -579
  936. claude_mpm/services/parent_directory_manager/validation_manager.py +0 -378
  937. claude_mpm/services/parent_directory_manager/version_control_helper.py +0 -339
  938. claude_mpm/services/parent_directory_manager/version_manager.py +0 -222
  939. claude_mpm/services/standalone_socketio_server.py +0 -1300
  940. claude_mpm/services/ticket_manager_di.py +0 -318
  941. claude_mpm/services/ticketing_service_original.py +0 -508
  942. claude_mpm/ui/__init__.py +0 -1
  943. claude_mpm/ui/rich_terminal_ui.py +0 -295
  944. claude_mpm/ui/terminal_ui.py +0 -328
  945. claude_mpm/utils/paths.py +0 -289
  946. claude_mpm-3.4.10.dist-info/METADATA +0 -183
  947. claude_mpm-3.4.10.dist-info/RECORD +0 -201
  948. claude_mpm-3.4.10.dist-info/licenses/LICENSE +0 -21
  949. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.55.dist-info}/WHEEL +0 -0
  950. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.55.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1743 @@
1
+ """
2
+ CLI Startup Functions
3
+ =====================
4
+
5
+ This module contains initialization functions that run on CLI startup,
6
+ including project registry, MCP configuration, and update checks.
7
+
8
+ Part of cli/__init__.py refactoring to reduce file size and improve modularity.
9
+ """
10
+
11
+ import os
12
+ import sys
13
+ from pathlib import Path
14
+
15
+
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.
21
+
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.
24
+
25
+ Args:
26
+ quiet: If True, suppress all output (used internally)
27
+
28
+ Returns:
29
+ bool: True if hooks were synced successfully, False otherwise
30
+ """
31
+ try:
32
+ from ..hooks.claude_hooks.installer import HookInstaller
33
+
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.
68
+
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():
91
+ return
92
+
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
+ """
135
+
136
+
137
+ def setup_early_environment(argv):
138
+ """
139
+ Set up early environment variables and logging suppression.
140
+
141
+ WHY: Some commands need special environment handling before any logging
142
+ or service initialization occurs.
143
+
144
+ CRITICAL: Suppress ALL logging by default until setup_mcp_server_logging()
145
+ configures the user's preference. This prevents early loggers (like
146
+ ProjectInitializer and service.* loggers) from logging at INFO level before
147
+ we know the user's logging preference.
148
+
149
+ Args:
150
+ argv: Command line arguments
151
+
152
+ Returns:
153
+ Processed argv list
154
+ """
155
+ import logging
156
+
157
+ # Disable telemetry and set cleanup flags early
158
+ os.environ.setdefault("DISABLE_TELEMETRY", "1")
159
+ os.environ.setdefault("CLAUDE_MPM_SKIP_CLEANUP", "0")
160
+
161
+ # CRITICAL: Suppress ALL logging by default
162
+ # This catches all loggers (claude_mpm.*, service.*, framework_loader, etc.)
163
+ # This will be overridden by setup_mcp_server_logging() based on user preference
164
+ logging.getLogger().setLevel(logging.CRITICAL + 1) # Root logger catches everything
165
+
166
+ # Process argv
167
+ if argv is None:
168
+ argv = sys.argv[1:]
169
+
170
+ # EARLY CHECK: Additional suppression for configure command
171
+ if "configure" in argv or (len(argv) > 0 and argv[0] == "configure"):
172
+ os.environ["CLAUDE_MPM_SKIP_CLEANUP"] = "1"
173
+
174
+ return argv
175
+
176
+
177
+ def should_skip_background_services(args, processed_argv):
178
+ """
179
+ Determine if background services should be skipped for this command.
180
+
181
+ WHY: Some commands (help, version, configure, doctor) don't need
182
+ background services and should start faster.
183
+
184
+ Args:
185
+ args: Parsed arguments
186
+ processed_argv: Processed command line arguments
187
+
188
+ Returns:
189
+ bool: True if background services should be skipped
190
+ """
191
+ skip_commands = ["--version", "-v", "--help", "-h"]
192
+ return any(cmd in (processed_argv or sys.argv[1:]) for cmd in skip_commands) or (
193
+ hasattr(args, "command")
194
+ and args.command in ["info", "doctor", "config", "mcp", "configure"]
195
+ )
196
+
197
+
198
+ def setup_configure_command_environment(args):
199
+ """
200
+ Set up special environment for configure command.
201
+
202
+ WHY: Configure command needs clean state without background services
203
+ and with suppressed logging.
204
+
205
+ Args:
206
+ args: Parsed arguments
207
+ """
208
+ if hasattr(args, "command") and args.command == "configure":
209
+ os.environ["CLAUDE_MPM_SKIP_CLEANUP"] = "1"
210
+ import logging
211
+
212
+ logging.getLogger("claude_mpm").setLevel(logging.WARNING)
213
+
214
+
215
+ def deploy_bundled_skills():
216
+ """
217
+ Deploy bundled Claude Code skills on startup.
218
+
219
+ WHY: Automatically deploy skills from the bundled/ directory to .claude/skills/
220
+ to ensure skills are available for agents without manual intervention.
221
+
222
+ DESIGN DECISION: Deployment happens with minimal feedback (checkmark on success).
223
+ Failures are logged but don't block startup to ensure claude-mpm remains
224
+ functional even if skills deployment fails. Respects auto_deploy config setting.
225
+ """
226
+ try:
227
+ # Check if auto-deploy is disabled in config
228
+ from ..config.config_loader import ConfigLoader
229
+
230
+ config_loader = ConfigLoader()
231
+ try:
232
+ config = config_loader.load_config()
233
+ skills_config = config.get("skills", {})
234
+ if not skills_config.get("auto_deploy", True):
235
+ # Auto-deploy disabled, skip silently
236
+ return
237
+ except Exception:
238
+ # If config loading fails, assume auto-deploy is enabled (default)
239
+ pass
240
+
241
+ # Import and run skills deployment
242
+ from ..skills.skills_service import SkillsService
243
+
244
+ skills_service = SkillsService()
245
+ deployment_result = skills_service.deploy_bundled_skills()
246
+
247
+ # Log results
248
+ from ..core.logger import get_logger
249
+
250
+ logger = get_logger("cli")
251
+
252
+ if deployment_result.get("deployed"):
253
+ # Show simple feedback for deployed skills
254
+ deployed_count = len(deployment_result["deployed"])
255
+ print(f"✓ Bundled skills ready ({deployed_count} deployed)", flush=True)
256
+ logger.info(f"Skills: Deployed {deployed_count} skill(s)")
257
+ elif not deployment_result.get("errors"):
258
+ # No deployment needed, skills already present
259
+ print("✓ Bundled skills ready", flush=True)
260
+
261
+ if deployment_result.get("errors"):
262
+ logger.warning(
263
+ f"Skills: {len(deployment_result['errors'])} skill(s) failed to deploy"
264
+ )
265
+
266
+ except Exception as e:
267
+ # Import logger here to avoid circular imports
268
+ from ..core.logger import get_logger
269
+
270
+ logger = get_logger("cli")
271
+ logger.debug(f"Failed to deploy bundled skills: {e}")
272
+ # Continue execution - skills deployment failure shouldn't block startup
273
+
274
+
275
+ def discover_and_link_runtime_skills():
276
+ """
277
+ Discover and link runtime skills from user/project directories.
278
+
279
+ WHY: Automatically discover and link skills added to .claude/skills/
280
+ without requiring manual configuration.
281
+
282
+ DESIGN DECISION: Provides simple feedback on completion.
283
+ Failures are logged but don't block startup to ensure
284
+ claude-mpm remains functional even if skills discovery fails.
285
+ """
286
+ try:
287
+ from ..cli.interactive.skills_wizard import (
288
+ discover_and_link_runtime_skills as discover_skills,
289
+ )
290
+
291
+ discover_skills()
292
+ # Show simple success feedback
293
+ print("✓ Runtime skills linked", flush=True)
294
+ except Exception as e:
295
+ # Import logger here to avoid circular imports
296
+ from ..core.logger import get_logger
297
+
298
+ logger = get_logger("cli")
299
+ logger.debug(f"Failed to discover runtime skills: {e}")
300
+ # Continue execution - skills discovery failure shouldn't block startup
301
+
302
+
303
+ def deploy_output_style_on_startup():
304
+ """
305
+ Deploy claude-mpm output styles to PROJECT-LEVEL directory on CLI startup.
306
+
307
+ WHY: Automatically deploy output styles to ensure consistent, professional
308
+ communication without emojis and exclamation points. Styles are project-specific
309
+ to allow different projects to have different communication styles.
310
+
311
+ DESIGN DECISION: This is non-blocking and idempotent. Deploys to project-level
312
+ directory (.claude/settings/output-styles/) instead of user-level to maintain
313
+ project isolation.
314
+
315
+ Deploys two styles:
316
+ - claude-mpm-style.md (professional mode)
317
+ - claude-mpm-teacher.md (teaching mode)
318
+ """
319
+ try:
320
+ import shutil
321
+ from pathlib import Path
322
+
323
+ # Source files (in framework package)
324
+ package_dir = Path(__file__).parent.parent / "agents"
325
+ professional_source = package_dir / "CLAUDE_MPM_OUTPUT_STYLE.md"
326
+ teacher_source = package_dir / "CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md"
327
+
328
+ # Target directory (PROJECT-LEVEL, not user-level)
329
+ project_dir = Path.cwd()
330
+ output_styles_dir = project_dir / ".claude" / "settings" / "output-styles"
331
+ professional_target = output_styles_dir / "claude-mpm-style.md"
332
+ teacher_target = output_styles_dir / "claude-mpm-teacher.md"
333
+
334
+ # Create directory if it doesn't exist
335
+ output_styles_dir.mkdir(parents=True, exist_ok=True)
336
+
337
+ # Check if already deployed (both files exist and have content)
338
+ already_deployed = (
339
+ professional_target.exists()
340
+ and teacher_target.exists()
341
+ and professional_target.stat().st_size > 0
342
+ and teacher_target.stat().st_size > 0
343
+ )
344
+
345
+ if already_deployed:
346
+ # Show feedback that output styles are ready
347
+ print("✓ Output styles ready", flush=True)
348
+ return
349
+
350
+ # Deploy both styles
351
+ deployed_count = 0
352
+ if professional_source.exists():
353
+ shutil.copy2(professional_source, professional_target)
354
+ deployed_count += 1
355
+
356
+ if teacher_source.exists():
357
+ shutil.copy2(teacher_source, teacher_target)
358
+ deployed_count += 1
359
+
360
+ if deployed_count > 0:
361
+ print(f"✓ Output styles deployed ({deployed_count} styles)", flush=True)
362
+ else:
363
+ # Source files missing - log but don't fail
364
+ from ..core.logger import get_logger
365
+
366
+ logger = get_logger("cli")
367
+ logger.debug("Output style source files not found")
368
+
369
+ except Exception as e:
370
+ # Non-critical - log but don't fail startup
371
+ from ..core.logger import get_logger
372
+
373
+ logger = get_logger("cli")
374
+ logger.debug(f"Failed to deploy output styles: {e}")
375
+ # Continue execution - output style deployment shouldn't block startup
376
+
377
+
378
+ def _cleanup_orphaned_agents(deploy_target: Path, deployed_agents: list[str]) -> int:
379
+ """Remove agents that are managed by claude-mpm but no longer deployed.
380
+
381
+ WHY: When agent configurations change, old agents should be removed to avoid
382
+ confusion and stale agent references. Only removes claude-mpm managed agents,
383
+ leaving user-created agents untouched.
384
+
385
+ SAFETY: Only removes files with claude-mpm ownership markers in frontmatter.
386
+ Files without frontmatter or without ownership indicators are preserved.
387
+
388
+ Args:
389
+ deploy_target: Path to .claude/agents/ directory
390
+ deployed_agents: List of agent filenames that should remain
391
+
392
+ Returns:
393
+ Number of agents removed
394
+ """
395
+ import re
396
+
397
+ import yaml
398
+
399
+ from ..core.logger import get_logger
400
+
401
+ logger = get_logger("cli")
402
+ removed_count = 0
403
+ deployed_set = set(deployed_agents)
404
+
405
+ if not deploy_target.exists():
406
+ return 0
407
+
408
+ # Scan all .md files in agents directory
409
+ for agent_file in deploy_target.glob("*.md"):
410
+ # Skip hidden files
411
+ if agent_file.name.startswith("."):
412
+ continue
413
+
414
+ # Skip if this agent should remain deployed
415
+ if agent_file.name in deployed_set:
416
+ continue
417
+
418
+ # Check if this is a claude-mpm managed agent
419
+ try:
420
+ content = agent_file.read_text(encoding="utf-8")
421
+
422
+ # Parse YAML frontmatter
423
+ if content.startswith("---"):
424
+ match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
425
+ if match:
426
+ frontmatter = yaml.safe_load(match.group(1))
427
+
428
+ # Check ownership indicators
429
+ is_ours = False
430
+ if frontmatter:
431
+ author = frontmatter.get("author", "")
432
+ source = frontmatter.get("source", "")
433
+ agent_id = frontmatter.get("agent_id", "")
434
+
435
+ # It's ours if it has any of these markers
436
+ if (
437
+ "Claude MPM" in str(author)
438
+ or source == "remote"
439
+ or agent_id
440
+ ):
441
+ is_ours = True
442
+
443
+ if is_ours:
444
+ # Safe to remove - it's our agent but not deployed
445
+ agent_file.unlink()
446
+ removed_count += 1
447
+ logger.info(f"Removed orphaned agent: {agent_file.name}")
448
+
449
+ except Exception as e:
450
+ logger.debug(f"Could not check agent {agent_file.name}: {e}")
451
+ # Don't remove if we can't verify ownership
452
+
453
+ return removed_count
454
+
455
+
456
+ def sync_remote_agents_on_startup():
457
+ """
458
+ Synchronize agent templates from remote sources on startup.
459
+
460
+ WHY: Ensures agents are up-to-date from remote Git sources (GitHub)
461
+ without manual intervention. Uses ETag-based caching for efficient
462
+ updates (95%+ bandwidth reduction).
463
+
464
+ DESIGN DECISION: Non-blocking synchronization that doesn't prevent
465
+ startup if network is unavailable. Failures are logged but don't
466
+ block startup to ensure claude-mpm remains functional.
467
+
468
+ Workflow:
469
+ 1. Cleanup legacy agent cache directories (if any)
470
+ 2. Sync all enabled Git sources (download/cache files) - Phase 1 progress bar
471
+ 3. Deploy agents to ~/.claude/agents/ - Phase 2 progress bar
472
+ 4. Cleanup orphaned agents (ours but no longer deployed) - Phase 3
473
+ 5. Log deployment results
474
+ """
475
+ # Cleanup legacy cache directories first (before syncing)
476
+ cleanup_legacy_agent_cache()
477
+
478
+ # DEPRECATED: Legacy warning - replaced by automatic cleanup above
479
+ check_legacy_cache()
480
+
481
+ try:
482
+ # Load active profile if configured
483
+ # Get project root (where .claude-mpm exists)
484
+ from pathlib import Path
485
+
486
+ from ..core.shared.config_loader import ConfigLoader
487
+ from ..services.agents.deployment.agent_deployment import AgentDeploymentService
488
+ from ..services.agents.startup_sync import sync_agents_on_startup
489
+ from ..services.profile_manager import ProfileManager
490
+ from ..utils.progress import ProgressBar
491
+
492
+ project_root = Path.cwd()
493
+
494
+ profile_manager = ProfileManager(project_dir=project_root)
495
+ config_loader = ConfigLoader()
496
+ main_config = config_loader.load_main_config()
497
+ active_profile = main_config.get("active_profile")
498
+
499
+ if active_profile:
500
+ success = profile_manager.load_profile(active_profile)
501
+ if success:
502
+ summary = profile_manager.get_filtering_summary()
503
+ from ..core.logger import get_logger
504
+
505
+ logger = get_logger("cli")
506
+ logger.info(
507
+ f"Profile '{active_profile}' active: "
508
+ f"{summary['enabled_agents_count']} agents enabled"
509
+ )
510
+
511
+ # Phase 1: Sync files from Git sources
512
+ result = sync_agents_on_startup()
513
+
514
+ # Only proceed with deployment if sync was enabled and ran
515
+ if result.get("enabled") and result.get("sources_synced", 0) > 0:
516
+ from ..core.logger import get_logger
517
+
518
+ logger = get_logger("cli")
519
+
520
+ downloaded = result.get("total_downloaded", 0)
521
+ cached = result.get("cache_hits", 0)
522
+ duration = result.get("duration_ms", 0)
523
+
524
+ if downloaded > 0 or cached > 0:
525
+ logger.debug(
526
+ f"Agent sync: {downloaded} updated, {cached} cached ({duration}ms)"
527
+ )
528
+
529
+ # Log errors if any
530
+ errors = result.get("errors", [])
531
+ if errors:
532
+ logger.warning(f"Agent sync completed with {len(errors)} errors")
533
+
534
+ # Phase 2: Deploy agents from cache to ~/.claude/agents/
535
+ # This mirrors the skills deployment pattern (lines 371-407)
536
+ try:
537
+ # Initialize deployment service with profile-filtered configuration
538
+ from ..core.config import Config
539
+
540
+ deploy_config = None
541
+ if active_profile and profile_manager.active_profile:
542
+ # Create config with excluded agents based on profile
543
+ # Get all agents that should be excluded (not in enabled list)
544
+ from pathlib import Path
545
+
546
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "agents"
547
+ if cache_dir.exists():
548
+ # Find all agent files
549
+ # Supports both flat cache and {owner}/{repo}/agents/ structure
550
+ all_agent_files = [
551
+ f
552
+ for f in cache_dir.rglob("*.md")
553
+ if "/agents/" in str(f)
554
+ and f.stem.lower() != "base-agent"
555
+ and f.name.lower()
556
+ not in {"readme.md", "changelog.md", "contributing.md"}
557
+ ]
558
+
559
+ # Build exclusion list for agents not in profile
560
+ excluded_agents = []
561
+ for agent_file in all_agent_files:
562
+ agent_name = agent_file.stem
563
+ if not profile_manager.is_agent_enabled(agent_name):
564
+ excluded_agents.append(agent_name)
565
+
566
+ if excluded_agents:
567
+ # Get singleton config and update with profile settings
568
+ # BUGFIX: Config is a singleton that ignores dict parameter if already initialized.
569
+ # Creating Config({...}) doesn't store excluded_agents - use set() instead.
570
+ deploy_config = Config()
571
+ deploy_config.set(
572
+ "agent_deployment.excluded_agents", excluded_agents
573
+ )
574
+ deploy_config.set(
575
+ "agent_deployment.filter_non_mpm_agents", False
576
+ )
577
+ deploy_config.set("agent_deployment.case_sensitive", False)
578
+ deploy_config.set(
579
+ "agent_deployment.exclude_dependencies", False
580
+ )
581
+ logger.info(
582
+ f"Profile '{active_profile}': Excluding {len(excluded_agents)} agents from deployment"
583
+ )
584
+
585
+ deployment_service = AgentDeploymentService(config=deploy_config)
586
+
587
+ # Count agents in cache to show accurate progress
588
+ from pathlib import Path
589
+
590
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "agents"
591
+ agent_count = 0
592
+
593
+ if cache_dir.exists():
594
+ # BUGFIX (cache-count-inflation): Clean up stale cache files
595
+ # from old repositories before counting to prevent inflated counts.
596
+ # Issue: Old caches like bobmatnyc/claude-mpm-agents/agents/
597
+ # were counted alongside current agents, inflating count
598
+ # from 44 to 85.
599
+ #
600
+ # Solution: Remove files with nested /agents/ paths
601
+ # (e.g., cache/agents/user/repo/agents/...)
602
+ # Keep only current agents (e.g., cache/agents/engineer/...)
603
+ removed_count = 0
604
+ stale_dirs = set()
605
+
606
+ for md_file in cache_dir.rglob("*.md"):
607
+ # Stale cache files have multiple /agents/ in their path RELATIVE to cache_dir
608
+ # Current: cache/agents/bobmatnyc/claude-mpm-agents/agents/engineer/...
609
+ # (1 occurrence in relative path: /agents/)
610
+ # Old flat: cache/agents/engineer/...
611
+ # (0 occurrences in relative path - no repo structure)
612
+ # The issue: str(md_file).count("/agents/") counts BOTH cache/agents/ AND repo/agents/
613
+ # Fix: Count /agents/ in path RELATIVE to cache_dir (after cache/agents/)
614
+ relative_path = str(md_file.relative_to(cache_dir))
615
+ if relative_path.count("/agents/") > 1:
616
+ # Track parent directory for cleanup
617
+ # Extract subdirectory under cache/agents/
618
+ # (e.g., "bobmatnyc")
619
+ parts = md_file.parts
620
+ cache_agents_idx = parts.index("agents")
621
+ if cache_agents_idx + 1 < len(parts):
622
+ stale_subdir = parts[cache_agents_idx + 1]
623
+ # Only remove if it's not a known category directory
624
+ if stale_subdir not in [
625
+ "engineer",
626
+ "ops",
627
+ "qa",
628
+ "universal",
629
+ "documentation",
630
+ "claude-mpm",
631
+ "security",
632
+ ]:
633
+ stale_dirs.add(cache_dir / stale_subdir)
634
+
635
+ md_file.unlink()
636
+ removed_count += 1
637
+
638
+ # Remove empty stale directories
639
+ for stale_dir in stale_dirs:
640
+ if stale_dir.exists() and stale_dir.is_dir():
641
+ try:
642
+ # Remove directory and all contents
643
+ import shutil
644
+
645
+ shutil.rmtree(stale_dir)
646
+ except Exception:
647
+ pass # Ignore cleanup errors
648
+
649
+ if removed_count > 0:
650
+ from loguru import logger
651
+
652
+ logger.info(
653
+ f"Cleaned up {removed_count} stale cache files "
654
+ f"from old repositories"
655
+ )
656
+
657
+ # Count MD files in cache (agent markdown files from
658
+ # current repos)
659
+ # BUGFIX: Only count files in agent directories,
660
+ # not docs/templates/READMEs
661
+ # Valid agent paths must contain "/agents/" exactly ONCE
662
+ # (current structure)
663
+ # Exclude PM templates, BASE-AGENT, and documentation files
664
+ pm_templates = {
665
+ "base-agent.md",
666
+ "circuit_breakers.md",
667
+ "pm_examples.md",
668
+ "pm_red_flags.md",
669
+ "research_gate_examples.md",
670
+ "response_format.md",
671
+ "ticket_completeness_examples.md",
672
+ "validation_templates.md",
673
+ "git_file_tracking.md",
674
+ }
675
+ # Documentation files to exclude (by filename)
676
+ doc_files = {
677
+ "readme.md",
678
+ "changelog.md",
679
+ "contributing.md",
680
+ "implementation-summary.md",
681
+ "reorganization-plan.md",
682
+ "auto-deploy-index.md",
683
+ }
684
+
685
+ # Find all markdown files (after cleanup)
686
+ all_md_files = list(cache_dir.rglob("*.md"))
687
+
688
+ # Filter to only agent files:
689
+ # 1. Must have "/agents/" in path (current structure supports
690
+ # both flat and {owner}/{repo}/agents/ patterns)
691
+ # 2. Must not be in PM templates or doc files
692
+ # 3. Exclude BASE-AGENT.md which is not a deployable agent
693
+ # 4. Exclude build artifacts (dist/, build/, .cache/)
694
+ # to prevent double-counting
695
+ agent_files = [
696
+ f
697
+ for f in all_md_files
698
+ if (
699
+ # Must be in an agent directory
700
+ # Supports: cache/agents/{category}/... (flat)
701
+ # Supports: cache/agents/{owner}/{repo}/agents/{category}/... (GitHub sync)
702
+ "/agents/" in str(f)
703
+ # Exclude PM templates, doc files, and BASE-AGENT
704
+ and f.name.lower() not in pm_templates
705
+ and f.name.lower() not in doc_files
706
+ and f.name.lower() != "base-agent.md"
707
+ # Exclude build artifacts (prevents double-counting
708
+ # source + built files)
709
+ and not any(
710
+ part in str(f).split("/")
711
+ for part in ["dist", "build", ".cache"]
712
+ )
713
+ )
714
+ ]
715
+ agent_count = len(agent_files)
716
+
717
+ if agent_count > 0:
718
+ # Deploy agents to project-level directory where Claude Code expects them
719
+ deploy_target = Path.cwd() / ".claude" / "agents"
720
+ deployment_result = deployment_service.deploy_agents(
721
+ target_dir=deploy_target,
722
+ force_rebuild=False, # Only deploy if versions differ
723
+ deployment_mode="update", # Version-aware updates
724
+ config=deploy_config, # Pass config to respect profile filtering
725
+ )
726
+
727
+ # Get actual counts from deployment result (reflects configured agents)
728
+ deployed = len(deployment_result.get("deployed", []))
729
+ updated = len(deployment_result.get("updated", []))
730
+ skipped = len(deployment_result.get("skipped", []))
731
+ total_configured = deployed + updated + skipped
732
+
733
+ # FALLBACK: If deployment result doesn't track skipped agents (async path),
734
+ # count existing agents in target directory as "already deployed"
735
+ # This ensures accurate reporting when agents are already up-to-date
736
+ if total_configured == 0 and deploy_target.exists():
737
+ existing_agents = list(deploy_target.glob("*.md"))
738
+ # Filter out non-agent files (e.g., README.md, INSTRUCTIONS.md)
739
+ agent_count_in_target = len(
740
+ [
741
+ f
742
+ for f in existing_agents
743
+ if not f.name.startswith(("README", "INSTRUCTIONS"))
744
+ ]
745
+ )
746
+ if agent_count_in_target > 0:
747
+ # All agents already deployed - count them as skipped
748
+ skipped = agent_count_in_target
749
+ total_configured = agent_count_in_target
750
+
751
+ # Create progress bar with actual configured agent count (not raw file count)
752
+ deploy_progress = ProgressBar(
753
+ total=total_configured if total_configured > 0 else 1,
754
+ prefix="Deploying agents",
755
+ show_percentage=True,
756
+ show_counter=True,
757
+ )
758
+
759
+ # Update progress bar to completion
760
+ deploy_progress.update(
761
+ total_configured if total_configured > 0 else 1
762
+ )
763
+
764
+ # Cleanup orphaned agents (ours but no longer deployed)
765
+ # Get list of deployed agent filenames (what should remain)
766
+ deployed_filenames = []
767
+ for agent_name in deployment_result.get("deployed", []):
768
+ deployed_filenames.append(f"{agent_name}.md")
769
+ for agent_name in deployment_result.get("updated", []):
770
+ deployed_filenames.append(f"{agent_name}.md")
771
+ for agent_name in deployment_result.get("skipped", []):
772
+ deployed_filenames.append(f"{agent_name}.md")
773
+
774
+ # Run cleanup and get count of removed agents
775
+ removed = _cleanup_orphaned_agents(
776
+ deploy_target, deployed_filenames
777
+ )
778
+
779
+ # Show total configured agents (deployed + updated + already existing)
780
+ # Include cache count for context and removed count if any
781
+ if deployed > 0 or updated > 0:
782
+ if removed > 0:
783
+ deploy_progress.finish(
784
+ f"Complete: {deployed} new, {updated} updated, {skipped} unchanged, "
785
+ f"{removed} removed ({total_configured} configured from {agent_count} files in cache)"
786
+ )
787
+ else:
788
+ deploy_progress.finish(
789
+ f"Complete: {deployed} new, {updated} updated, {skipped} unchanged "
790
+ f"({total_configured} configured from {agent_count} files in cache)"
791
+ )
792
+ elif removed > 0:
793
+ deploy_progress.finish(
794
+ f"Complete: {total_configured} agents deployed, "
795
+ f"{removed} removed ({agent_count} files in cache)"
796
+ )
797
+ else:
798
+ deploy_progress.finish(
799
+ f"Complete: {total_configured} agents deployed "
800
+ f"({agent_count} files in cache)"
801
+ )
802
+
803
+ # Display deployment errors to user (not just logs)
804
+ deploy_errors = deployment_result.get("errors", [])
805
+ if deploy_errors:
806
+ # Log for debugging
807
+ logger.warning(
808
+ f"Agent deployment completed with {len(deploy_errors)} errors: {deploy_errors}"
809
+ )
810
+
811
+ # Display errors to user with clear formatting
812
+ print("\n⚠️ Agent Deployment Errors:")
813
+
814
+ # Show first 10 errors to avoid overwhelming output
815
+ max_errors_to_show = 10
816
+ errors_to_display = deploy_errors[:max_errors_to_show]
817
+
818
+ for error in errors_to_display:
819
+ # Format error message for readability
820
+ # Errors typically come as strings like "agent.md: Error message"
821
+ print(f" - {error}")
822
+
823
+ # If more errors exist, show count
824
+ if len(deploy_errors) > max_errors_to_show:
825
+ remaining = len(deploy_errors) - max_errors_to_show
826
+ print(f" ... and {remaining} more error(s)")
827
+
828
+ # Show summary message
829
+ print(
830
+ f"\n❌ Failed to deploy {len(deploy_errors)} agent(s). Please check the error messages above."
831
+ )
832
+ print(" Run with --verbose for detailed error information.\n")
833
+
834
+ except Exception as e:
835
+ # Deployment failure shouldn't block startup
836
+ from ..core.logger import get_logger
837
+
838
+ logger = get_logger("cli")
839
+ logger.warning(f"Failed to deploy agents from cache: {e}")
840
+
841
+ except Exception as e:
842
+ # Non-critical - log but don't fail startup
843
+ from ..core.logger import get_logger
844
+
845
+ logger = get_logger("cli")
846
+ logger.debug(f"Failed to sync remote agents: {e}")
847
+ # Continue execution - agent sync failure shouldn't block startup
848
+
849
+
850
+ def sync_remote_skills_on_startup():
851
+ """
852
+ Synchronize skill templates from remote sources on startup.
853
+
854
+ WHY: Ensures skills are up-to-date from remote Git sources (GitHub)
855
+ without manual intervention. Provides consistency with agent syncing.
856
+
857
+ DESIGN DECISION: Non-blocking synchronization that doesn't prevent
858
+ startup if network is unavailable. Failures are logged but don't
859
+ block startup to ensure claude-mpm remains functional.
860
+
861
+ Workflow:
862
+ 1. Sync all enabled Git sources (download/cache files) - Phase 1 progress bar
863
+ 2. Scan deployed agents for skill requirements → save to configuration.yaml
864
+ 3. Resolve which skills to deploy (user_defined vs agent_referenced)
865
+ 4. Apply profile filtering if active
866
+ 5. Deploy resolved skills to ~/.claude/skills/ - Phase 2 progress bar
867
+ 6. Log deployment results with source indication
868
+ """
869
+ try:
870
+ from pathlib import Path
871
+
872
+ from ..config.skill_sources import SkillSourceConfiguration
873
+ from ..core.shared.config_loader import ConfigLoader
874
+ from ..services.profile_manager import ProfileManager
875
+ from ..services.skills.git_skill_source_manager import GitSkillSourceManager
876
+ from ..services.skills.selective_skill_deployer import (
877
+ get_required_skills_from_agents,
878
+ get_skills_to_deploy,
879
+ save_agent_skills_to_config,
880
+ )
881
+ from ..utils.progress import ProgressBar
882
+
883
+ # Load active profile if configured
884
+ # Get project root (where .claude-mpm exists)
885
+ project_root = Path.cwd()
886
+
887
+ profile_manager = ProfileManager(project_dir=project_root)
888
+ config_loader = ConfigLoader()
889
+ main_config = config_loader.load_main_config()
890
+ active_profile = main_config.get("active_profile")
891
+
892
+ if active_profile:
893
+ success = profile_manager.load_profile(active_profile)
894
+ if success:
895
+ from ..core.logger import get_logger
896
+
897
+ logger = get_logger("cli")
898
+ summary = profile_manager.get_filtering_summary()
899
+ logger.info(
900
+ f"Profile '{active_profile}' active: "
901
+ f"{summary['enabled_skills_count']} skills enabled, "
902
+ f"{summary['disabled_patterns_count']} patterns disabled"
903
+ )
904
+
905
+ config = SkillSourceConfiguration()
906
+ manager = GitSkillSourceManager(config)
907
+
908
+ # Get enabled sources
909
+ enabled_sources = config.get_enabled_sources()
910
+ if not enabled_sources:
911
+ return # No sources enabled, nothing to sync
912
+
913
+ # Phase 1: Sync files from Git sources
914
+ # We need to discover file count first to show accurate progress
915
+ # This requires pre-scanning repositories via GitHub API
916
+ from ..core.logger import get_logger
917
+
918
+ logger = get_logger("cli")
919
+
920
+ # Discover total file count across all sources
921
+ total_file_count = 0
922
+ total_skill_dirs = 0 # Count actual skill directories (folders with SKILL.md)
923
+
924
+ for source in enabled_sources:
925
+ try:
926
+ # Parse GitHub URL
927
+ url_parts = (
928
+ source.url.rstrip("/").replace(".git", "").split("github.com/")
929
+ )
930
+ if len(url_parts) == 2:
931
+ repo_path = url_parts[1].strip("/")
932
+ owner_repo = "/".join(repo_path.split("/")[:2])
933
+
934
+ # Use Tree API to discover all files
935
+ all_files = manager._discover_repository_files_via_tree_api(
936
+ owner_repo, source.branch
937
+ )
938
+
939
+ # Count relevant files (markdown, JSON)
940
+ relevant_files = [
941
+ f
942
+ for f in all_files
943
+ if f.endswith(".md") or f.endswith(".json") or f == ".gitignore"
944
+ ]
945
+ total_file_count += len(relevant_files)
946
+
947
+ # Count skill directories (unique directories containing SKILL.md)
948
+ skill_dirs = set()
949
+ for f in all_files:
950
+ if f.endswith("/SKILL.md"):
951
+ # Extract directory path
952
+ skill_dir = "/".join(f.split("/")[:-1])
953
+ skill_dirs.add(skill_dir)
954
+ total_skill_dirs += len(skill_dirs)
955
+
956
+ except Exception as e:
957
+ logger.debug(f"Failed to discover files for {source.id}: {e}")
958
+ # Use estimate if discovery fails
959
+ total_file_count += 150
960
+ total_skill_dirs += 50 # Estimate ~50 skills
961
+
962
+ # Create progress bar for sync phase with actual file count
963
+ # Note: We sync files (md, json, etc.), but will deploy skill directories
964
+ sync_progress = ProgressBar(
965
+ total=total_file_count if total_file_count > 0 else 1,
966
+ prefix="Syncing skill files",
967
+ show_percentage=True,
968
+ show_counter=True,
969
+ )
970
+
971
+ # Sync all sources with progress callback
972
+ results = manager.sync_all_sources(
973
+ force=False, progress_callback=sync_progress.update
974
+ )
975
+
976
+ # Finish sync progress bar with clear breakdown
977
+ downloaded = results["total_files_updated"]
978
+ cached = results["total_files_cached"]
979
+ total_files = downloaded + cached
980
+
981
+ if cached > 0:
982
+ sync_progress.finish(
983
+ f"Complete: {downloaded} downloaded, {cached} cached ({total_files} files, {total_skill_dirs} skills)"
984
+ )
985
+ else:
986
+ # All new downloads (first sync)
987
+ sync_progress.finish(
988
+ f"Complete: {downloaded} files downloaded ({total_skill_dirs} skills)"
989
+ )
990
+
991
+ # Phase 2: Scan agents and save to configuration.yaml
992
+ # This step populates configuration.yaml with agent-referenced skills
993
+ # BUGFIX: Removed `if results["synced_count"] > 0` condition to ensure
994
+ # agent_referenced is always populated, even when using cached skills.
995
+ # Previous behavior: If skills were cached, agent scan was skipped,
996
+ # leaving agent_referenced: [] empty, which prevented cleanup.
997
+ agents_dir = Path.cwd() / ".claude" / "agents"
998
+
999
+ # Scan agents for skill requirements (always run, not just on sync)
1000
+ agent_skills = get_required_skills_from_agents(agents_dir)
1001
+
1002
+ # Save to project-level configuration.yaml
1003
+ project_config_path = Path.cwd() / ".claude-mpm" / "configuration.yaml"
1004
+ save_agent_skills_to_config(list(agent_skills), project_config_path)
1005
+
1006
+ # Phase 3: Resolve which skills to deploy (user_defined or agent_referenced)
1007
+ skills_to_deploy, skill_source = get_skills_to_deploy(project_config_path)
1008
+
1009
+ # Phase 4: Apply profile filtering if active
1010
+ if active_profile and profile_manager.active_profile:
1011
+ # Filter skills based on profile
1012
+ if skills_to_deploy:
1013
+ # Filter the resolved skill list
1014
+ original_count = len(skills_to_deploy)
1015
+ filtered_skills = [
1016
+ skill
1017
+ for skill in skills_to_deploy
1018
+ if profile_manager.is_skill_enabled(skill)
1019
+ ]
1020
+ filtered_count = original_count - len(filtered_skills)
1021
+
1022
+ # SAFEGUARD: Warn if all skills were filtered out (misconfiguration)
1023
+ if not filtered_skills and original_count > 0:
1024
+ logger.warning(
1025
+ f"Profile '{active_profile}' filtered ALL {original_count} skills. "
1026
+ f"This may indicate a naming mismatch in the profile."
1027
+ )
1028
+ elif filtered_count > 0:
1029
+ logger.info(
1030
+ f"Profile '{active_profile}' filtered {filtered_count} skills "
1031
+ f"({len(filtered_skills)} remaining)"
1032
+ )
1033
+
1034
+ skills_to_deploy = filtered_skills
1035
+ skill_source = f"{skill_source} + profile filtered"
1036
+ else:
1037
+ # No explicit skill list - filter from all available
1038
+ all_skills = manager.get_all_skills()
1039
+ filtered_skills = [
1040
+ skill["name"]
1041
+ for skill in all_skills
1042
+ if profile_manager.is_skill_enabled(skill["name"])
1043
+ ]
1044
+ skills_to_deploy = filtered_skills
1045
+ skill_source = "profile filtered"
1046
+ logger.info(
1047
+ f"Profile '{active_profile}': "
1048
+ f"{len(filtered_skills)} skills enabled from {len(all_skills)} available"
1049
+ )
1050
+
1051
+ # Get all skills to determine counts
1052
+ all_skills = manager.get_all_skills()
1053
+ total_skill_count = len(all_skills)
1054
+
1055
+ # Determine skill count based on resolution
1056
+ skill_count = (
1057
+ len(skills_to_deploy) if skills_to_deploy else total_skill_count
1058
+ )
1059
+
1060
+ if skill_count > 0:
1061
+ # Deploy skills with resolved filter
1062
+ # Deploy ONLY to project directory (not user-level)
1063
+ # DESIGN DECISION: Project-level deployment keeps skills isolated per project,
1064
+ # avoiding pollution of user's global ~/.claude/skills/ directory.
1065
+
1066
+ # Deploy to project-local directory with cleanup
1067
+ deployment_result = manager.deploy_skills(
1068
+ target_dir=Path.cwd() / ".claude" / "skills",
1069
+ force=False,
1070
+ skill_filter=set(skills_to_deploy) if skills_to_deploy else None,
1071
+ )
1072
+
1073
+ # REMOVED: User-level deployment (lines 1068-1074)
1074
+ # Reason: Skills should be project-specific, not user-global.
1075
+ # Claude Code can read from project-level .claude/skills/ directory.
1076
+
1077
+ # Get actual counts from deployment result (use project-local for display)
1078
+ deployed = deployment_result.get("deployed_count", 0)
1079
+ skipped = deployment_result.get("skipped_count", 0)
1080
+ filtered = deployment_result.get("filtered_count", 0)
1081
+ total_available = deployed + skipped
1082
+
1083
+ # Only show progress bar if there are skills to deploy
1084
+ if total_available > 0:
1085
+ deploy_progress = ProgressBar(
1086
+ total=total_available,
1087
+ prefix="Deploying skill directories",
1088
+ show_percentage=True,
1089
+ show_counter=True,
1090
+ )
1091
+ # Update progress bar to completion
1092
+ deploy_progress.update(total_available)
1093
+ else:
1094
+ # No skills to deploy - create dummy progress for message only
1095
+ deploy_progress = ProgressBar(
1096
+ total=1,
1097
+ prefix="Deploying skill directories",
1098
+ show_percentage=False,
1099
+ show_counter=False,
1100
+ )
1101
+ deploy_progress.update(1)
1102
+
1103
+ # Show total available skills (deployed + already existing)
1104
+ # Include source indication (user_defined vs agent_referenced)
1105
+ # Note: total_skill_count is from cache, total_available is what's deployed/needed
1106
+ source_label = (
1107
+ "user override" if skill_source == "user_defined" else "from agents"
1108
+ )
1109
+
1110
+ if deployed > 0:
1111
+ if filtered > 0:
1112
+ deploy_progress.finish(
1113
+ f"Complete: {deployed} new, {skipped} unchanged "
1114
+ f"({total_available} {source_label}, {filtered} files in cache)"
1115
+ )
1116
+ else:
1117
+ deploy_progress.finish(
1118
+ f"Complete: {deployed} new, {skipped} unchanged "
1119
+ f"({total_available} skills {source_label} from {total_skill_count} files in cache)"
1120
+ )
1121
+ elif filtered > 0:
1122
+ # Skills filtered means agents require fewer skills than available
1123
+ deploy_progress.finish(
1124
+ f"No skills needed ({source_label}, {total_skill_count} files in cache)"
1125
+ )
1126
+ else:
1127
+ deploy_progress.finish(
1128
+ f"Complete: {total_available} skills {source_label} "
1129
+ f"({total_skill_count} files in cache)"
1130
+ )
1131
+
1132
+ # Log deployment errors if any
1133
+ from ..core.logger import get_logger
1134
+
1135
+ logger = get_logger("cli")
1136
+
1137
+ errors = deployment_result.get("errors", [])
1138
+ if errors:
1139
+ logger.warning(
1140
+ f"Skill deployment completed with {len(errors)} errors: {errors}"
1141
+ )
1142
+
1143
+ # Log sync errors if any
1144
+ if results["failed_count"] > 0:
1145
+ logger.warning(
1146
+ f"Skill sync completed with {results['failed_count']} failures"
1147
+ )
1148
+
1149
+ except Exception as e:
1150
+ # Non-critical - log but don't fail startup
1151
+ from ..core.logger import get_logger
1152
+
1153
+ logger = get_logger("cli")
1154
+ logger.debug(f"Failed to sync remote skills: {e}")
1155
+ # Continue execution - skill sync failure shouldn't block startup
1156
+
1157
+
1158
+ def show_agent_summary():
1159
+ """
1160
+ Display agent availability summary on startup.
1161
+
1162
+ WHY: Users should see at a glance how many agents are available and installed
1163
+ without having to run /mpm-agents list.
1164
+
1165
+ DESIGN DECISION: Fast, non-blocking check that counts agents from the deployment
1166
+ directory. Shows simple "X installed / Y available" format. Failures are silent
1167
+ to avoid blocking startup.
1168
+ """
1169
+ try:
1170
+ from pathlib import Path
1171
+
1172
+ # Count deployed agents (installed)
1173
+ deploy_target = Path.cwd() / ".claude" / "agents"
1174
+ installed_count = 0
1175
+ if deploy_target.exists():
1176
+ # Count .md files, excluding README and other docs
1177
+ agent_files = [
1178
+ f
1179
+ for f in deploy_target.glob("*.md")
1180
+ if not f.name.startswith(("README", "INSTRUCTIONS", "."))
1181
+ ]
1182
+ installed_count = len(agent_files)
1183
+
1184
+ # Count available agents in cache (from remote sources)
1185
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "agents"
1186
+ available_count = 0
1187
+ if cache_dir.exists():
1188
+ # Use same filtering logic as agent deployment (lines 486-533 in startup.py)
1189
+ pm_templates = {
1190
+ "base-agent.md",
1191
+ "circuit_breakers.md",
1192
+ "pm_examples.md",
1193
+ "pm_red_flags.md",
1194
+ "research_gate_examples.md",
1195
+ "response_format.md",
1196
+ "ticket_completeness_examples.md",
1197
+ "validation_templates.md",
1198
+ "git_file_tracking.md",
1199
+ }
1200
+ doc_files = {
1201
+ "readme.md",
1202
+ "changelog.md",
1203
+ "contributing.md",
1204
+ "implementation-summary.md",
1205
+ "reorganization-plan.md",
1206
+ "auto-deploy-index.md",
1207
+ }
1208
+
1209
+ # Find all markdown files in agents/ directories
1210
+ all_md_files = list(cache_dir.rglob("*.md"))
1211
+ agent_files = [
1212
+ f
1213
+ for f in all_md_files
1214
+ if (
1215
+ "/agents/" in str(f)
1216
+ and f.name.lower() not in pm_templates
1217
+ and f.name.lower() not in doc_files
1218
+ and f.name.lower() != "base-agent.md"
1219
+ and not any(
1220
+ part in str(f).split("/")
1221
+ for part in ["dist", "build", ".cache"]
1222
+ )
1223
+ )
1224
+ ]
1225
+ available_count = len(agent_files)
1226
+
1227
+ # Display summary if we have agents
1228
+ if installed_count > 0 or available_count > 0:
1229
+ print(
1230
+ f"✓ Agents: {installed_count} deployed / {max(0, available_count - installed_count)} cached",
1231
+ flush=True,
1232
+ )
1233
+
1234
+ except Exception as e:
1235
+ # Silent failure - agent summary is informational only
1236
+ from ..core.logger import get_logger
1237
+
1238
+ logger = get_logger("cli")
1239
+ logger.debug(f"Failed to generate agent summary: {e}")
1240
+
1241
+
1242
+ def show_skill_summary():
1243
+ """
1244
+ Display skill availability summary on startup.
1245
+
1246
+ WHY: Users should see at a glance how many skills are deployed and available
1247
+ from collections, similar to the agent summary.
1248
+
1249
+ DESIGN DECISION: Fast, non-blocking check that counts skills from deployment
1250
+ directory and collection repos. Shows "X installed (Y available)" format.
1251
+ Failures are silent to avoid blocking startup.
1252
+ """
1253
+ try:
1254
+ from pathlib import Path
1255
+
1256
+ # Count deployed skills (installed)
1257
+ skills_dir = Path.home() / ".claude" / "skills"
1258
+ installed_count = 0
1259
+ if skills_dir.exists():
1260
+ # Count directories with SKILL.md (excludes collection repos)
1261
+ # Exclude collection directories (obra-superpowers, etc.)
1262
+ skill_dirs = [
1263
+ d
1264
+ for d in skills_dir.iterdir()
1265
+ if d.is_dir()
1266
+ and (d / "SKILL.md").exists()
1267
+ and not (d / ".git").exists() # Exclude collection repos
1268
+ ]
1269
+ installed_count = len(skill_dirs)
1270
+
1271
+ # Count available skills in collections
1272
+ available_count = 0
1273
+ if skills_dir.exists():
1274
+ # Scan all collection directories (those with .git)
1275
+ for collection_dir in skills_dir.iterdir():
1276
+ if (
1277
+ not collection_dir.is_dir()
1278
+ or not (collection_dir / ".git").exists()
1279
+ ):
1280
+ continue
1281
+
1282
+ # Count skill directories in this collection
1283
+ # Skills can be nested in: skills/category/skill-name/SKILL.md
1284
+ # or in flat structure: skill-name/SKILL.md
1285
+ for root, dirs, files in os.walk(collection_dir):
1286
+ if "SKILL.md" in files:
1287
+ # Exclude build artifacts and hidden directories (within the collection)
1288
+ # Get relative path from collection_dir to avoid excluding based on .claude parent
1289
+ root_path = Path(root)
1290
+ relative_parts = root_path.relative_to(collection_dir).parts
1291
+ if not any(
1292
+ part.startswith(".")
1293
+ or part in ["dist", "build", "__pycache__"]
1294
+ for part in relative_parts
1295
+ ):
1296
+ available_count += 1
1297
+
1298
+ # Display summary if we have skills
1299
+ if installed_count > 0 or available_count > 0:
1300
+ print(
1301
+ f"✓ Skills: {installed_count} installed ({available_count} available)",
1302
+ flush=True,
1303
+ )
1304
+
1305
+ except Exception as e:
1306
+ # Silent failure - skill summary is informational only
1307
+ from ..core.logger import get_logger
1308
+
1309
+ logger = get_logger("cli")
1310
+ logger.debug(f"Failed to generate skill summary: {e}")
1311
+
1312
+
1313
+ def verify_and_show_pm_skills():
1314
+ """Verify PM skills and display status.
1315
+
1316
+ WHY: PM skills are essential for PM agent operation.
1317
+ Shows deployment status and auto-deploys if missing.
1318
+ """
1319
+ try:
1320
+ from pathlib import Path
1321
+
1322
+ from ..services.pm_skills_deployer import PMSkillsDeployerService
1323
+
1324
+ deployer = PMSkillsDeployerService()
1325
+ project_dir = Path.cwd()
1326
+
1327
+ result = deployer.verify_pm_skills(project_dir)
1328
+
1329
+ if result.verified:
1330
+ # Show verified status
1331
+ print(f"✓ PM skills: {result.skill_count} verified", flush=True)
1332
+ else:
1333
+ # Auto-deploy if missing
1334
+ print("Deploying PM skills...", end="", flush=True)
1335
+ deploy_result = deployer.deploy_pm_skills(project_dir)
1336
+ if deploy_result.success:
1337
+ total = len(deploy_result.deployed) + len(deploy_result.skipped)
1338
+ print(f"\r✓ PM skills: {total} deployed" + " " * 20, flush=True)
1339
+ else:
1340
+ print("\r⚠ PM skills: deployment failed" + " " * 20, flush=True)
1341
+
1342
+ except ImportError:
1343
+ # PM skills deployer not available - skip silently
1344
+ pass
1345
+ except Exception as e:
1346
+ from ..core.logger import get_logger
1347
+
1348
+ logger = get_logger("cli")
1349
+ logger.debug(f"PM skills verification failed: {e}")
1350
+
1351
+
1352
+ def auto_install_chrome_devtools_on_startup():
1353
+ """
1354
+ Automatically install chrome-devtools-mcp on startup if enabled.
1355
+
1356
+ WHY: Browser automation capabilities should be available out-of-the-box without
1357
+ manual MCP server configuration. chrome-devtools-mcp provides powerful browser
1358
+ interaction tools for Claude Code.
1359
+
1360
+ DESIGN DECISION: Non-blocking installation that doesn't prevent startup if it fails.
1361
+ Respects user configuration setting (enabled by default). Only installs if not
1362
+ already configured in Claude.
1363
+ """
1364
+ try:
1365
+ # Check if auto-install is disabled in config
1366
+ from ..config.config_loader import ConfigLoader
1367
+
1368
+ config_loader = ConfigLoader()
1369
+ try:
1370
+ config = config_loader.load_main_config()
1371
+ chrome_devtools_config = config.get("chrome_devtools", {})
1372
+ if not chrome_devtools_config.get("auto_install", True):
1373
+ # Auto-install disabled, skip silently
1374
+ return
1375
+ except Exception:
1376
+ # If config loading fails, assume auto-install is enabled (default)
1377
+ pass
1378
+
1379
+ # Import and run chrome-devtools installation
1380
+ from ..cli.chrome_devtools_installer import auto_install_chrome_devtools
1381
+
1382
+ auto_install_chrome_devtools(quiet=False)
1383
+
1384
+ except Exception as e:
1385
+ # Import logger here to avoid circular imports
1386
+ from ..core.logger import get_logger
1387
+
1388
+ logger = get_logger("cli")
1389
+ logger.debug(f"Failed to auto-install chrome-devtools-mcp: {e}")
1390
+ # Continue execution - chrome-devtools installation failure shouldn't block startup
1391
+
1392
+
1393
+ def run_background_services():
1394
+ """
1395
+ Initialize all background services on startup.
1396
+
1397
+ WHY: Centralizes all startup service initialization for cleaner main().
1398
+
1399
+ NOTE: System instructions (PM_INSTRUCTIONS.md, WORKFLOW.md, MEMORY.md) and
1400
+ templates do NOT deploy automatically on startup. They only deploy when user
1401
+ explicitly requests them via agent-manager commands. This prevents unwanted
1402
+ file creation in project .claude/ directories.
1403
+ See: SystemInstructionsDeployer and agent_deployment.py line 504-509
1404
+ """
1405
+ # Sync hooks early to ensure up-to-date configuration
1406
+ # RATIONALE: Hooks should be synced before other services to fix stale configs
1407
+ # This is fast (<100ms) and non-blocking, so it doesn't delay startup
1408
+ sync_hooks_on_startup() # Shows "Syncing Claude Code hooks... ✓"
1409
+
1410
+ initialize_project_registry()
1411
+ check_mcp_auto_configuration()
1412
+ verify_mcp_gateway_startup()
1413
+ check_for_updates_async()
1414
+ sync_remote_agents_on_startup() # Sync agents from remote sources
1415
+ show_agent_summary() # Display agent counts after deployment
1416
+
1417
+ # Skills deployment order (precedence: remote > bundled)
1418
+ # 1. Deploy bundled skills first (base layer from package)
1419
+ # 2. Sync and deploy remote skills (Git sources, can override bundled)
1420
+ # 3. Discover and link runtime skills (user-added skills)
1421
+ # This ensures remote skills take precedence over bundled skills when names conflict
1422
+ deploy_bundled_skills() # Base layer: package-bundled skills
1423
+ sync_remote_skills_on_startup() # Override layer: Git-based skills (takes precedence)
1424
+ discover_and_link_runtime_skills() # Discovery: user-added skills
1425
+ show_skill_summary() # Display skill counts after deployment
1426
+ verify_and_show_pm_skills() # PM skills verification and status
1427
+
1428
+ deploy_output_style_on_startup()
1429
+
1430
+ # Auto-install chrome-devtools-mcp for browser automation
1431
+ auto_install_chrome_devtools_on_startup()
1432
+
1433
+
1434
+ def setup_mcp_server_logging(args):
1435
+ """
1436
+ Configure minimal logging for MCP server mode.
1437
+
1438
+ WHY: MCP server needs minimal stderr-only logging to avoid interfering
1439
+ with stdout protocol communication.
1440
+
1441
+ Args:
1442
+ args: Parsed arguments
1443
+
1444
+ Returns:
1445
+ Configured logger
1446
+ """
1447
+ import logging
1448
+
1449
+ from ..cli.utils import setup_logging
1450
+ from ..constants import CLICommands
1451
+
1452
+ if (
1453
+ args.command == CLICommands.MCP.value
1454
+ and getattr(args, "mcp_command", None) == "start"
1455
+ ):
1456
+ if not getattr(args, "test", False) and not getattr(
1457
+ args, "instructions", False
1458
+ ):
1459
+ # Production MCP mode - minimal logging
1460
+ logging.basicConfig(
1461
+ level=logging.ERROR,
1462
+ format="%(message)s",
1463
+ stream=sys.stderr,
1464
+ force=True,
1465
+ )
1466
+ return logging.getLogger("claude_mpm")
1467
+ # Test or instructions mode - normal logging
1468
+ return setup_logging(args)
1469
+ # Normal logging for all other commands
1470
+ return setup_logging(args)
1471
+
1472
+
1473
+ def initialize_project_registry():
1474
+ """
1475
+ Initialize or update the project registry for the current session.
1476
+
1477
+ WHY: The project registry tracks all claude-mpm projects and their metadata
1478
+ across sessions. This function ensures the current project is properly
1479
+ registered and updates session information.
1480
+
1481
+ DESIGN DECISION: Registry failures are logged but don't prevent startup
1482
+ to ensure claude-mpm remains functional even if registry operations fail.
1483
+ """
1484
+ try:
1485
+ from ..services.project.registry import ProjectRegistry
1486
+
1487
+ registry = ProjectRegistry()
1488
+ registry.get_or_create_project_entry()
1489
+ except Exception as e:
1490
+ # Import logger here to avoid circular imports
1491
+ from ..core.logger import get_logger
1492
+
1493
+ logger = get_logger("cli")
1494
+ logger.debug(f"Failed to initialize project registry: {e}")
1495
+ # Continue execution - registry failure shouldn't block startup
1496
+
1497
+
1498
+ def check_mcp_auto_configuration():
1499
+ """
1500
+ Check and potentially auto-configure MCP for pipx installations.
1501
+
1502
+ WHY: Users installing via pipx should have MCP work out-of-the-box with
1503
+ minimal friction. This function offers one-time auto-configuration with
1504
+ user consent.
1505
+
1506
+ DESIGN DECISION: This is blocking but quick - it only runs once and has
1507
+ a 10-second timeout. Shows progress feedback during checks to avoid
1508
+ appearing frozen.
1509
+
1510
+ OPTIMIZATION: Skip ALL MCP checks for doctor and configure commands to avoid
1511
+ duplicate checks (doctor performs its own comprehensive check, configure
1512
+ allows users to select services).
1513
+ """
1514
+ # Skip MCP service checks for the doctor and configure commands
1515
+ # The doctor command performs its own comprehensive MCP service check
1516
+ # The configure command allows users to configure which services to enable
1517
+ # Running both would cause duplicate checks and log messages (9 seconds apart)
1518
+ if len(sys.argv) > 1 and sys.argv[1] in ("doctor", "configure"):
1519
+ return
1520
+
1521
+ try:
1522
+ from ..services.mcp_gateway.auto_configure import check_and_configure_mcp
1523
+
1524
+ # Show progress feedback - this operation can take 10+ seconds
1525
+ print("Checking MCP configuration...", end="", flush=True)
1526
+
1527
+ # This function handles all the logic:
1528
+ # - Checks if already configured
1529
+ # - Checks if pipx installation
1530
+ # - Checks if already asked before
1531
+ # - Prompts user if needed
1532
+ # - Configures if user agrees
1533
+ check_and_configure_mcp()
1534
+
1535
+ # Clear the "Checking..." message by overwriting with spaces
1536
+ print("\r" + " " * 30 + "\r", end="", flush=True)
1537
+
1538
+ except Exception as e:
1539
+ # Clear progress message on error
1540
+ print("\r" + " " * 30 + "\r", end="", flush=True)
1541
+
1542
+ # Non-critical - log but don't fail
1543
+ from ..core.logger import get_logger
1544
+
1545
+ logger = get_logger("cli")
1546
+ logger.debug(f"MCP auto-configuration check failed: {e}")
1547
+
1548
+
1549
+ def verify_mcp_gateway_startup():
1550
+ """
1551
+ Verify MCP Gateway configuration on startup and pre-warm MCP services.
1552
+
1553
+ WHY: The MCP gateway should be automatically configured and verified on startup
1554
+ to provide a seamless experience with diagnostic tools, file summarizer, and
1555
+ ticket service. Pre-warming MCP services eliminates the 11.9s delay on first use.
1556
+
1557
+ DESIGN DECISION: This is non-blocking - failures are logged but don't prevent
1558
+ startup to ensure claude-mpm remains functional even if MCP gateway has issues.
1559
+ """
1560
+ # DISABLED: MCP service verification removed - Claude Code handles MCP natively
1561
+ # The previous check warned about missing MCP services, but users should configure
1562
+ # MCP servers through Claude Code's native MCP management, not through claude-mpm.
1563
+ # See: https://docs.anthropic.com/en/docs/claude-code/mcp
1564
+
1565
+ try:
1566
+ import asyncio
1567
+
1568
+ from ..core.logger import get_logger
1569
+ from ..services.mcp_gateway.core.startup_verification import (
1570
+ is_mcp_gateway_configured,
1571
+ verify_mcp_gateway_on_startup,
1572
+ )
1573
+
1574
+ logger = get_logger("mcp_prewarm")
1575
+
1576
+ # Quick check first - if already configured, skip detailed verification
1577
+ gateway_configured = is_mcp_gateway_configured()
1578
+
1579
+ # DISABLED: Pre-warming MCP servers can interfere with Claude Code's MCP management
1580
+ # This was causing issues with MCP server initialization and stderr handling
1581
+ # Pre-warming functionality has been removed. Gateway verification only runs
1582
+ # if MCP gateway is not already configured.
1583
+
1584
+ # Run gateway verification in background if not configured
1585
+ if not gateway_configured:
1586
+
1587
+ def run_verification():
1588
+ """Background thread to verify MCP gateway configuration."""
1589
+ loop = None
1590
+ try:
1591
+ loop = asyncio.new_event_loop()
1592
+ asyncio.set_event_loop(loop)
1593
+ results = loop.run_until_complete(verify_mcp_gateway_on_startup())
1594
+
1595
+ # Log results but don't block
1596
+ from ..core.logger import get_logger
1597
+
1598
+ logger = get_logger("cli")
1599
+
1600
+ if results.get("gateway_configured"):
1601
+ logger.debug("MCP Gateway verification completed successfully")
1602
+ else:
1603
+ logger.debug("MCP Gateway verification completed with warnings")
1604
+
1605
+ except Exception as e:
1606
+ from ..core.logger import get_logger
1607
+
1608
+ logger = get_logger("cli")
1609
+ logger.debug(f"MCP Gateway verification failed: {e}")
1610
+ finally:
1611
+ # Properly clean up event loop to prevent kqueue warnings
1612
+ if loop is not None:
1613
+ try:
1614
+ # Cancel all running tasks
1615
+ pending = asyncio.all_tasks(loop)
1616
+ for task in pending:
1617
+ task.cancel()
1618
+ # Wait for tasks to complete cancellation
1619
+ if pending:
1620
+ loop.run_until_complete(
1621
+ asyncio.gather(*pending, return_exceptions=True)
1622
+ )
1623
+ except Exception:
1624
+ pass # Ignore cleanup errors
1625
+ finally:
1626
+ loop.close()
1627
+ # Clear the event loop reference to help with cleanup
1628
+ asyncio.set_event_loop(None)
1629
+
1630
+ # Run in background thread to avoid blocking startup
1631
+ import threading
1632
+
1633
+ verification_thread = threading.Thread(target=run_verification, daemon=True)
1634
+ verification_thread.start()
1635
+
1636
+ except Exception as e:
1637
+ # Import logger here to avoid circular imports
1638
+ from ..core.logger import get_logger
1639
+
1640
+ logger = get_logger("cli")
1641
+ logger.debug(f"Failed to start MCP Gateway verification: {e}")
1642
+ # Continue execution - MCP gateway issues shouldn't block startup
1643
+
1644
+
1645
+ def check_for_updates_async():
1646
+ """
1647
+ Check for updates in background thread (non-blocking).
1648
+
1649
+ WHY: Users should be notified of new versions and have an easy way to upgrade
1650
+ without manually checking PyPI/npm. This runs asynchronously on startup to avoid
1651
+ blocking the CLI.
1652
+
1653
+ DESIGN DECISION: This is non-blocking and non-critical - failures are logged
1654
+ but don't prevent startup. Only runs for pip/pipx/npm installations, skips
1655
+ editable/development installations. Respects user configuration settings.
1656
+ """
1657
+
1658
+ def run_update_check():
1659
+ """Inner function to run in background thread."""
1660
+ loop = None
1661
+ try:
1662
+ import asyncio
1663
+
1664
+ from ..core.config import Config
1665
+ from ..core.logger import get_logger
1666
+ from ..services.self_upgrade_service import SelfUpgradeService
1667
+
1668
+ logger = get_logger("upgrade_check")
1669
+
1670
+ # Load configuration
1671
+ config = Config()
1672
+ updates_config = config.get("updates", {})
1673
+
1674
+ # Check if update checking is enabled
1675
+ if not updates_config.get("check_enabled", True):
1676
+ logger.debug("Update checking disabled in configuration")
1677
+ return
1678
+
1679
+ # Check frequency setting
1680
+ frequency = updates_config.get("check_frequency", "daily")
1681
+ if frequency == "never":
1682
+ logger.debug("Update checking frequency set to 'never'")
1683
+ return
1684
+
1685
+ # Create new event loop for this thread
1686
+ loop = asyncio.new_event_loop()
1687
+ asyncio.set_event_loop(loop)
1688
+
1689
+ # Create upgrade service and check for updates
1690
+ upgrade_service = SelfUpgradeService()
1691
+
1692
+ # Skip for editable installs (development mode)
1693
+ from ..services.self_upgrade_service import InstallationMethod
1694
+
1695
+ if upgrade_service.installation_method == InstallationMethod.EDITABLE:
1696
+ logger.debug("Skipping version check for editable installation")
1697
+ return
1698
+
1699
+ # Get configuration values
1700
+ check_claude_code = updates_config.get("check_claude_code", True)
1701
+ auto_upgrade = updates_config.get("auto_upgrade", False)
1702
+
1703
+ # Check and prompt for upgrade if available (non-blocking)
1704
+ loop.run_until_complete(
1705
+ upgrade_service.check_and_prompt_on_startup(
1706
+ auto_upgrade=auto_upgrade, check_claude_code=check_claude_code
1707
+ )
1708
+ )
1709
+
1710
+ except Exception as e:
1711
+ # Non-critical - log but don't fail startup
1712
+ try:
1713
+ from ..core.logger import get_logger
1714
+
1715
+ logger = get_logger("upgrade_check")
1716
+ logger.debug(f"Update check failed (non-critical): {e}")
1717
+ except Exception:
1718
+ pass # Avoid any errors in error handling
1719
+ finally:
1720
+ # Properly clean up event loop
1721
+ if loop is not None:
1722
+ try:
1723
+ # Cancel all running tasks
1724
+ pending = asyncio.all_tasks(loop)
1725
+ for task in pending:
1726
+ task.cancel()
1727
+ # Wait for tasks to complete cancellation
1728
+ if pending:
1729
+ loop.run_until_complete(
1730
+ asyncio.gather(*pending, return_exceptions=True)
1731
+ )
1732
+ except Exception:
1733
+ pass # Ignore cleanup errors
1734
+ finally:
1735
+ loop.close()
1736
+ # Clear the event loop reference to help with cleanup
1737
+ asyncio.set_event_loop(None)
1738
+
1739
+ # Run update check in background thread to avoid blocking startup
1740
+ import threading
1741
+
1742
+ update_check_thread = threading.Thread(target=run_update_check, daemon=True)
1743
+ update_check_thread.start()