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
@@ -1,119 +1,152 @@
1
+ from pathlib import Path
2
+
1
3
  """
2
4
  Run command implementation for claude-mpm.
3
5
 
4
6
  WHY: This module handles the main 'run' command which starts Claude sessions.
5
7
  It's the most commonly used command and handles both interactive and non-interactive modes.
8
+
9
+ DESIGN DECISIONS:
10
+ - Use BaseCommand for consistent CLI patterns
11
+ - Leverage shared utilities for argument parsing and output formatting
12
+ - Maintain backward compatibility with existing functionality
13
+ - Support multiple output formats (json, yaml, table, text)
6
14
  """
7
15
 
8
- import os
9
16
  import subprocess
10
17
  import sys
11
- import time
12
- import webbrowser
13
- from pathlib import Path
14
- from datetime import datetime
18
+ from datetime import datetime, timezone
19
+ from typing import Optional
15
20
 
16
- from ...core.logger import get_logger
17
21
  from ...constants import LogLevel
18
- from ..utils import get_user_input, list_agent_versions_at_startup
19
- from ...utils.dependency_manager import ensure_socketio_dependencies
20
- from ...deployment_paths import get_scripts_dir, get_package_root
22
+ from ...core.logger import get_logger
23
+ from ...core.unified_paths import get_scripts_dir
24
+ from ...services.cli.session_manager import SessionManager
25
+
26
+ # SocketIOManager functionality now provided by UnifiedDashboardManager
27
+ from ...services.cli.startup_checker import StartupCheckerService
28
+ from ...services.cli.unified_dashboard_manager import UnifiedDashboardManager
29
+ from ..shared import BaseCommand, CommandResult
30
+ from ..startup_logging import (
31
+ cleanup_old_startup_logs,
32
+ log_startup_status,
33
+ setup_startup_logging,
34
+ )
35
+ from ..utils import get_user_input
21
36
 
22
37
 
23
38
  def filter_claude_mpm_args(claude_args):
24
39
  """
25
40
  Filter out claude-mpm specific arguments from claude_args before passing to Claude CLI.
26
-
41
+
27
42
  WHY: The argparse.REMAINDER captures ALL remaining arguments, including claude-mpm
28
43
  specific flags like --monitor, etc. Claude CLI doesn't understand these
29
44
  flags and will error if they're passed through.
30
-
45
+
31
46
  DESIGN DECISION: We maintain a list of known claude-mpm flags to filter out,
32
- ensuring only genuine Claude CLI arguments are passed through.
33
-
47
+ ensuring only genuine Claude CLI arguments are passed through. We also remove
48
+ the '--' separator that argparse uses, as it's not needed by Claude CLI.
49
+
34
50
  Args:
35
51
  claude_args: List of arguments captured by argparse.REMAINDER
36
-
52
+
37
53
  Returns:
38
54
  Filtered list of arguments safe to pass to Claude CLI
39
55
  """
40
56
  if not claude_args:
41
57
  return []
42
-
58
+
43
59
  # Known claude-mpm specific flags that should NOT be passed to Claude CLI
44
60
  # This includes all MPM-specific arguments from the parser
45
61
  mpm_flags = {
46
62
  # Run-specific flags
47
- '--monitor',
48
- '--websocket-port',
49
- '--no-hooks',
50
- '--no-tickets',
51
- '--intercept-commands',
52
- '--no-native-agents',
53
- '--launch-method',
54
- '--resume',
63
+ "--monitor",
64
+ "--websocket-port",
65
+ "--no-hooks",
66
+ "--no-tickets",
67
+ "--intercept-commands",
68
+ "--no-native-agents",
69
+ "--launch-method",
70
+ "--mpm-resume",
71
+ "--reload-agents", # New flag to force rebuild system agents
72
+ # Dependency checking flags (MPM-specific)
73
+ "--no-check-dependencies",
74
+ "--force-check-dependencies",
75
+ "--no-prompt",
76
+ "--force-prompt",
55
77
  # Input/output flags (these are MPM-specific, not Claude CLI flags)
56
- '--input',
57
- '--non-interactive',
78
+ "--input",
79
+ "--non-interactive",
58
80
  # Common logging flags (these are MPM-specific, not Claude CLI flags)
59
- '--debug',
60
- '--logging',
61
- '--log-dir',
81
+ "--debug",
82
+ "--logging",
83
+ "--log-dir",
62
84
  # Framework flags (these are MPM-specific)
63
- '--framework-path',
64
- '--agents-dir',
85
+ "--framework-path",
86
+ "--agents-dir",
65
87
  # Version flag (handled by MPM)
66
- '--version',
88
+ "--version",
67
89
  # Short flags (MPM-specific equivalents)
68
- '-i', # --input (MPM-specific, not Claude CLI)
69
- '-d' # --debug (MPM-specific, not Claude CLI)
90
+ "-i", # --input (MPM-specific, not Claude CLI)
91
+ "-d", # --debug (MPM-specific, not Claude CLI)
70
92
  }
71
-
93
+
72
94
  filtered_args = []
73
95
  i = 0
74
96
  while i < len(claude_args):
75
97
  arg = claude_args[i]
76
-
98
+
99
+ # Skip the '--' separator used by argparse - Claude doesn't need it
100
+ if arg == "--":
101
+ i += 1
102
+ continue
103
+
77
104
  # Check if this is a claude-mpm flag
78
105
  if arg in mpm_flags:
79
106
  # Skip this flag
80
107
  i += 1
81
108
  # Also skip the next argument if this flag expects a value
82
109
  value_expecting_flags = {
83
- '--websocket-port', '--launch-method', '--logging', '--log-dir',
84
- '--framework-path', '--agents-dir', '-i', '--input'
110
+ "--websocket-port",
111
+ "--launch-method",
112
+ "--logging",
113
+ "--log-dir",
114
+ "--framework-path",
115
+ "--agents-dir",
116
+ "-i",
117
+ "--input",
85
118
  }
86
119
  optional_value_flags = {
87
- '--resume' # These flags can have optional values (nargs="?")
88
- }
89
-
120
+ "--mpm-resume"
121
+ } # These flags can have optional values (nargs="?")
122
+
90
123
  if arg in value_expecting_flags and i < len(claude_args):
91
124
  i += 1 # Skip the value too
92
125
  elif arg in optional_value_flags and i < len(claude_args):
93
126
  # For optional value flags, only skip next arg if it doesn't start with --
94
127
  next_arg = claude_args[i]
95
- if not next_arg.startswith('--'):
128
+ if not next_arg.startswith("--"):
96
129
  i += 1 # Skip the value
97
130
  else:
98
131
  # This is not a claude-mpm flag, keep it
99
132
  filtered_args.append(arg)
100
133
  i += 1
101
-
134
+
102
135
  return filtered_args
103
136
 
104
137
 
105
138
  def create_session_context(session_id, session_manager):
106
139
  """
107
140
  Create enhanced context for resumed sessions.
108
-
141
+
109
142
  WHY: When resuming a session, we want to provide Claude with context about
110
143
  the previous session including what agents were used and when it was created.
111
144
  This helps maintain continuity across session boundaries.
112
-
145
+
113
146
  Args:
114
147
  session_id: Session ID being resumed
115
148
  session_manager: SessionManager instance
116
-
149
+
117
150
  Returns:
118
151
  Enhanced context string with session information
119
152
  """
@@ -121,193 +154,884 @@ def create_session_context(session_id, session_manager):
121
154
  from ...core.claude_runner import create_simple_context
122
155
  except ImportError:
123
156
  from claude_mpm.core.claude_runner import create_simple_context
124
-
157
+
125
158
  base_context = create_simple_context()
126
-
127
- session_data = session_manager.get_session_by_id(session_id)
159
+
160
+ session_data = session_manager.get_session_info(session_id)
128
161
  if not session_data:
129
162
  return base_context
130
-
163
+
131
164
  # Add session resumption information
132
165
  session_info = f"""
133
166
 
134
167
  # Session Resumption
135
168
 
136
169
  You are resuming session {session_id[:8]}... which was:
137
- - Created: {session_data.get('created_at', 'unknown')}
138
- - Last used: {session_data.get('last_used', 'unknown')}
139
- - Context: {session_data.get('context', 'default')}
140
- - Use count: {session_data.get('use_count', 0)}
170
+ - Created: {session_data.get("created_at", "unknown")}
171
+ - Last used: {session_data.get("last_used", "unknown")}
172
+ - Context: {session_data.get("context", "default")}
173
+ - Use count: {session_data.get("use_count", 0)}
141
174
  """
142
-
175
+
143
176
  # Add information about agents previously run in this session
144
- agents_run = session_data.get('agents_run', [])
177
+ agents_run = session_data.get("agents_run", [])
145
178
  if agents_run:
146
179
  session_info += "\n- Previous agent activity:\n"
147
180
  for agent_info in agents_run[-5:]: # Show last 5 agents
148
181
  session_info += f" • {agent_info.get('agent', 'unknown')}: {agent_info.get('task', 'no description')[:50]}...\n"
149
182
  if len(agents_run) > 5:
150
183
  session_info += f" (and {len(agents_run) - 5} other agent interactions)\n"
151
-
184
+
152
185
  session_info += "\nContinue from where you left off in this session."
153
-
186
+
154
187
  return base_context + session_info
155
188
 
156
189
 
190
+ class RunCommand(BaseCommand):
191
+ """Run command using shared utilities."""
192
+
193
+ def __init__(self):
194
+ super().__init__("run")
195
+
196
+ def validate_args(self, args) -> Optional[str]:
197
+ """Validate command arguments."""
198
+ # Run command has minimal validation requirements
199
+ # Most validation is handled by the ClaudeRunner and related services
200
+ return None
201
+
202
+ def run(self, args) -> CommandResult:
203
+ """Execute the run command."""
204
+ try:
205
+ # Execute the main run logic
206
+ success = self._execute_run_session(args)
207
+
208
+ # Log memory stats at session completion
209
+ from ..startup_logging import log_memory_stats
210
+
211
+ log_memory_stats(self.logger, "Session End Memory")
212
+
213
+ if success:
214
+ return CommandResult.success_result(
215
+ "Claude session completed successfully"
216
+ )
217
+ return CommandResult.error_result("Claude session failed", exit_code=1)
218
+
219
+ except KeyboardInterrupt:
220
+ self.logger.info("Session interrupted by user")
221
+ return CommandResult.error_result(
222
+ "Session cancelled by user", exit_code=130
223
+ )
224
+ except Exception as e:
225
+ self.logger.error(f"Error running Claude session: {e}", exc_info=True)
226
+ return CommandResult.error_result(f"Error running Claude session: {e}")
227
+
228
+ def _execute_run_session(self, args) -> bool:
229
+ """Execute the main run session logic."""
230
+ # For now, delegate to the legacy function to maintain compatibility
231
+ # TODO: Gradually migrate logic into the individual helper methods
232
+ try:
233
+ run_session_legacy(args)
234
+ return True
235
+ except Exception as e:
236
+ self.logger.error(f"Run session failed: {e}")
237
+ return False
238
+
239
+ def _execute_run_session_new(self, args) -> bool:
240
+ """Execute the main run session logic using new pattern."""
241
+ try:
242
+ # Log session start
243
+ if args.logging != LogLevel.OFF.value:
244
+ self.logger.info("Starting Claude MPM session")
245
+
246
+ # Log MCP and monitor startup status
247
+ if args.logging != LogLevel.OFF.value:
248
+ monitor_mode = getattr(args, "monitor", False)
249
+ websocket_port = getattr(args, "websocket_port", 8765)
250
+ log_startup_status(monitor_mode, websocket_port)
251
+
252
+ # Perform startup checks
253
+ self._check_configuration_health()
254
+ self._check_claude_json_memory(args)
255
+
256
+ # Handle session management
257
+ session_manager, resume_session_id, resume_context = (
258
+ self._setup_session_management(args)
259
+ )
260
+
261
+ # Handle dependency checking
262
+ self._handle_dependency_checking(args)
263
+
264
+ # Setup monitoring if requested
265
+ monitor_mode, websocket_port = self._setup_monitoring(args)
266
+
267
+ # Configure Claude runner
268
+ runner = self._setup_claude_runner(args, monitor_mode, websocket_port)
269
+
270
+ # Create context and run session
271
+ context = self._create_session_context(
272
+ args, session_manager, resume_session_id, resume_context
273
+ )
274
+
275
+ # Execute the session
276
+ return self._execute_session(args, runner, context)
277
+
278
+ except Exception as e:
279
+ self.logger.error(f"Run session failed: {e}")
280
+ return False
281
+
282
+ def _check_configuration_health(self):
283
+ """Check configuration health at startup."""
284
+ # Use new StartupCheckerService
285
+ from ...core.config import Config
286
+
287
+ config_service = Config()
288
+ checker = StartupCheckerService(config_service)
289
+ warnings = checker.check_configuration()
290
+ checker.display_warnings(warnings)
291
+
292
+ def _check_claude_json_memory(self, args):
293
+ """Check .claude.json file size and warn about memory issues."""
294
+ # Use new StartupCheckerService
295
+ from ...core.config import Config
296
+
297
+ config_service = Config()
298
+ checker = StartupCheckerService(config_service)
299
+ resume_enabled = getattr(args, "mpm_resume", False)
300
+ warning = checker.check_memory(resume_enabled)
301
+ if warning:
302
+ checker.display_warnings([warning])
303
+
304
+ def _setup_session_management(self, args):
305
+ """Setup session management and handle resumption."""
306
+ # Use the new SessionManager service from the CLI services layer
307
+ session_manager = SessionManager()
308
+ resume_session_id = None
309
+ resume_context = None
310
+
311
+ if hasattr(args, "mpm_resume") and args.mpm_resume:
312
+ if args.mpm_resume == "last":
313
+ # Resume the last interactive session
314
+ resume_session_id = session_manager.get_last_interactive_session()
315
+ if resume_session_id:
316
+ session_data = session_manager.get_session_info(resume_session_id)
317
+ if session_data:
318
+ resume_context = session_data.get("context", "default")
319
+ self.logger.info(
320
+ f"Resuming session {resume_session_id} (context: {resume_context})"
321
+ )
322
+ print(
323
+ f"🔄 Resuming session {resume_session_id[:8]}... (created: {session_data.get('created_at', 'unknown')})"
324
+ )
325
+ else:
326
+ self.logger.warning(f"Session {resume_session_id} not found")
327
+ else:
328
+ self.logger.info("No recent interactive sessions found")
329
+ print("[INFO]️ No recent interactive sessions found to resume")
330
+ else:
331
+ # Resume specific session by ID
332
+ resume_session_id = args.mpm_resume
333
+ session_data = session_manager.get_session_info(resume_session_id)
334
+ if session_data:
335
+ resume_context = session_data.get("context", "default")
336
+ self.logger.info(
337
+ f"Resuming session {resume_session_id} (context: {resume_context})"
338
+ )
339
+ print(
340
+ f"🔄 Resuming session {resume_session_id[:8]}... (context: {resume_context})"
341
+ )
342
+ else:
343
+ self.logger.error(f"Session {resume_session_id} not found")
344
+ print(f"❌ Session {resume_session_id} not found")
345
+ print("💡 Use 'claude-mpm sessions' to list available sessions")
346
+ raise RuntimeError(f"Session {resume_session_id} not found")
347
+
348
+ return session_manager, resume_session_id, resume_context
349
+
350
+ def _handle_dependency_checking(self, args):
351
+ """Handle smart dependency checking."""
352
+ # Smart dependency checking - only when needed
353
+ if getattr(args, "check_dependencies", True): # Default to checking
354
+ try:
355
+ from ...utils.agent_dependency_loader import AgentDependencyLoader
356
+ from ...utils.dependency_cache import SmartDependencyChecker
357
+ from ...utils.environment_context import should_prompt_for_dependencies
358
+
359
+ # Initialize smart checker
360
+ smart_checker = SmartDependencyChecker()
361
+ loader = AgentDependencyLoader(auto_install=False)
362
+
363
+ # Check if agents have changed
364
+ _has_changed, deployment_hash = loader.has_agents_changed()
365
+
366
+ # Determine if we should check dependencies
367
+ should_check, check_reason = smart_checker.should_check_dependencies(
368
+ force_check=getattr(args, "force_check_dependencies", False),
369
+ deployment_hash=deployment_hash,
370
+ )
371
+
372
+ if should_check:
373
+ self.logger.info(f"Checking dependencies: {check_reason}")
374
+
375
+ # Check if we should prompt for dependencies
376
+ should_prompt = should_prompt_for_dependencies()
377
+
378
+ if should_prompt:
379
+ # Check dependencies and prompt for installation if needed
380
+ missing_deps = loader.check_dependencies()
381
+ if missing_deps:
382
+ self.logger.info(
383
+ f"Found {len(missing_deps)} missing dependencies"
384
+ )
385
+
386
+ # Prompt user for installation
387
+ print(
388
+ f"\n📦 Found {len(missing_deps)} missing dependencies:"
389
+ )
390
+ for dep in missing_deps[:5]: # Show first 5
391
+ print(f" • {dep}")
392
+ if len(missing_deps) > 5:
393
+ print(f" ... and {len(missing_deps) - 5} more")
394
+
395
+ response = (
396
+ input("\nInstall missing dependencies? (y/N): ")
397
+ .strip()
398
+ .lower()
399
+ )
400
+ if response in ["y", "yes"]:
401
+ loader.auto_install = True
402
+ loader.install_dependencies(missing_deps)
403
+ print("✅ Dependencies installed successfully")
404
+ else:
405
+ print("⚠️ Continuing without installing dependencies")
406
+ else:
407
+ # Just check without prompting
408
+ missing_deps = loader.check_dependencies()
409
+ if missing_deps:
410
+ self.logger.warning(
411
+ f"Found {len(missing_deps)} missing dependencies"
412
+ )
413
+ print(
414
+ f"⚠️ Found {len(missing_deps)} missing dependencies. Use --force-check-dependencies to install."
415
+ )
416
+
417
+ # Update cache
418
+ smart_checker.update_cache(deployment_hash)
419
+ else:
420
+ self.logger.debug(f"Skipping dependency check: {check_reason}")
421
+
422
+ except ImportError as e:
423
+ self.logger.warning(f"Dependency checking not available: {e}")
424
+ except Exception as e:
425
+ self.logger.warning(f"Dependency check failed: {e}")
426
+
427
+ def _setup_monitoring(self, args):
428
+ """Setup monitoring configuration using UnifiedDashboardManager."""
429
+ monitor_mode = getattr(args, "monitor", False)
430
+ websocket_port = 8765 # Default port
431
+
432
+ if monitor_mode:
433
+ # Use UnifiedDashboardManager for server management
434
+ dashboard_manager = UnifiedDashboardManager(self.logger)
435
+
436
+ # Check dependencies
437
+ deps_ok, error_msg = dashboard_manager.ensure_dependencies()
438
+ if not deps_ok:
439
+ self.logger.warning(
440
+ f"Socket.IO dependencies not available: {error_msg}, disabling monitor mode"
441
+ )
442
+ monitor_mode = False
443
+ else:
444
+ # Find available port and start server
445
+ websocket_port = dashboard_manager.find_available_port(8765)
446
+ success, _server_info = dashboard_manager.start_server(
447
+ port=websocket_port
448
+ )
449
+
450
+ if not success:
451
+ self.logger.warning(
452
+ "Failed to start Socket.IO server, disabling monitor mode"
453
+ )
454
+ monitor_mode = False
455
+ else:
456
+ # Use UnifiedDashboardManager for browser opening only
457
+ dashboard_manager = UnifiedDashboardManager(self.logger)
458
+ monitor_url = dashboard_manager.get_dashboard_url(websocket_port)
459
+
460
+ # Try to open browser
461
+ browser_opened = dashboard_manager.open_browser(monitor_url)
462
+ args._browser_opened_by_cli = browser_opened
463
+
464
+ if not browser_opened:
465
+ print(f"💡 Monitor interface available at: {monitor_url}")
466
+
467
+ return monitor_mode, websocket_port
468
+
469
+ def _setup_claude_runner(self, args, monitor_mode: bool, websocket_port: int):
470
+ """Setup and configure the Claude runner."""
471
+ try:
472
+ from ...core.claude_runner import ClaudeRunner
473
+ except ImportError:
474
+ from claude_mpm.core.claude_runner import ClaudeRunner
475
+
476
+ # Configure tickets
477
+ enable_tickets = not getattr(args, "no_tickets", False)
478
+
479
+ # Configure launch method
480
+ launch_method = "exec" # Default
481
+ if getattr(args, "subprocess", False):
482
+ launch_method = "subprocess"
483
+
484
+ # Configure WebSocket
485
+ enable_websocket = monitor_mode
486
+
487
+ # Build Claude arguments
488
+ claude_args = []
489
+ if hasattr(args, "claude_args") and args.claude_args:
490
+ claude_args.extend(args.claude_args)
491
+
492
+ # Create runner
493
+ runner = ClaudeRunner(
494
+ enable_tickets=enable_tickets,
495
+ log_level=args.logging,
496
+ claude_args=claude_args,
497
+ launch_method=launch_method,
498
+ enable_websocket=enable_websocket,
499
+ websocket_port=websocket_port,
500
+ )
501
+
502
+ # Set browser opening flag for monitor mode
503
+ if monitor_mode:
504
+ runner._should_open_monitor_browser = True
505
+ runner._browser_opened_by_cli = getattr(
506
+ args, "_browser_opened_by_cli", False
507
+ )
508
+
509
+ return runner
510
+
511
+ def _create_session_context(
512
+ self, args, session_manager, resume_session_id, resume_context
513
+ ):
514
+ """Create session context."""
515
+ try:
516
+ from ...core.claude_runner import create_simple_context
517
+ except ImportError:
518
+ from claude_mpm.core.claude_runner import create_simple_context
519
+
520
+ if resume_session_id and resume_context:
521
+ # For resumed sessions, create enhanced context with session information
522
+ context = create_session_context(resume_session_id, session_manager)
523
+ # Update session usage
524
+ session = session_manager.load_session(resume_session_id)
525
+ if session:
526
+ session.last_used = datetime.now(timezone.utc).isoformat()
527
+ session.use_count += 1
528
+ session_manager.save_session(session)
529
+ else:
530
+ # Create a new session for tracking
531
+ new_session = session_manager.create_session("default")
532
+ context = create_simple_context()
533
+ self.logger.info(f"Created new session {new_session.id}")
534
+
535
+ return context
536
+
537
+ def _execute_session(self, args, runner, context) -> bool:
538
+ """Execute the Claude session."""
539
+ try:
540
+ # Run session based on mode
541
+ non_interactive = getattr(args, "non_interactive", False)
542
+ input_arg = getattr(args, "input", None)
543
+
544
+ if non_interactive or input_arg:
545
+ # Non-interactive mode
546
+ user_input = get_user_input(input_arg, self.logger)
547
+ success = runner.run_oneshot(user_input, context)
548
+ if not success:
549
+ self.logger.error("Session failed")
550
+ return False
551
+ # Interactive mode
552
+ elif getattr(args, "intercept_commands", False):
553
+ wrapper_path = get_scripts_dir() / "interactive_wrapper.py"
554
+ if wrapper_path.exists():
555
+ print("Starting interactive session with command interception...")
556
+ subprocess.run([sys.executable, str(wrapper_path)], check=False)
557
+ else:
558
+ self.logger.warning(
559
+ "Interactive wrapper not found, falling back to normal mode"
560
+ )
561
+ runner.run_interactive(context)
562
+ else:
563
+ runner.run_interactive(context)
564
+
565
+ return True
566
+
567
+ except Exception as e:
568
+ self.logger.error(f"Session execution failed: {e}")
569
+ return False
570
+
571
+
572
+ def _handle_reload_agents(logger):
573
+ """
574
+ Handle the --reload-agents flag by deleting all local claude-mpm system agents.
575
+
576
+ This forces a fresh rebuild of system agents on the next deployment,
577
+ while preserving user-created agents.
578
+
579
+ Args:
580
+ logger: Logger instance for output
581
+ """
582
+ try:
583
+ logger.info("Reloading system agents - cleaning existing deployments...")
584
+
585
+ # Import the cleanup service
586
+ from ...services.agents.deployment.agent_deployment import (
587
+ AgentDeploymentService,
588
+ )
589
+ from ...services.cli.agent_cleanup_service import AgentCleanupService
590
+
591
+ # Create services
592
+ deployment_service = AgentDeploymentService()
593
+ cleanup_service = AgentCleanupService(deployment_service)
594
+
595
+ # Determine the agents directory
596
+ agents_dir = None # Will auto-detect project or user directory
597
+
598
+ # Clean deployed agents (preserves user agents)
599
+ result = cleanup_service.clean_deployed_agents(agents_dir)
600
+
601
+ # Check if cleanup was successful based on the result structure
602
+ # The service returns a dict with 'removed', 'preserved', and possibly 'errors' keys
603
+ # If it has 'success' key, use it; otherwise infer from the result
604
+ success = (
605
+ result.get("success", True)
606
+ if "success" in result
607
+ else not result.get("errors")
608
+ )
609
+
610
+ if success:
611
+ removed_count = result.get("cleaned_count", len(result.get("removed", [])))
612
+ removed_agents = result.get("removed", [])
613
+ preserved_agents = result.get("preserved", [])
614
+
615
+ if removed_count > 0:
616
+ logger.info(f"✅ Successfully removed {removed_count} system agents")
617
+ if removed_agents:
618
+ logger.debug(f"Removed agents: {', '.join(removed_agents)}")
619
+ print(f"🔄 Cleaned {removed_count} claude-mpm system agents")
620
+ else:
621
+ logger.info("No system agents found to clean")
622
+ print("[INFO]️ No system agents found - already clean")
623
+
624
+ if preserved_agents:
625
+ logger.info(f"Preserved {len(preserved_agents)} user-created agents")
626
+ print(f"✅ Preserved {len(preserved_agents)} user-created agents")
627
+
628
+ print("🚀 System agents will be rebuilt on next use")
629
+ else:
630
+ error = result.get("error", "Cleanup failed")
631
+ if result.get("errors"):
632
+ error = f"Cleanup errors: {', '.join(result['errors'])}"
633
+ logger.error(f"Failed to clean system agents: {error}")
634
+ print(f"❌ Error cleaning agents: {error}")
635
+
636
+ except Exception as e:
637
+ logger.error(f"Error handling --reload-agents: {e}", exc_info=True)
638
+ print(f"❌ Failed to reload agents: {e}")
639
+ # Don't fail the entire session, just log the error
640
+ print("⚠️ Continuing with existing agents...")
641
+
642
+
157
643
  def run_session(args):
158
644
  """
159
- Run a simplified Claude session.
160
-
161
- WHY: This is the primary command that users interact with. It sets up the
162
- environment, optionally deploys agents, and launches Claude with the MPM framework.
163
-
645
+ Main entry point for run command.
646
+
647
+ This function maintains backward compatibility while using the new BaseCommand pattern.
648
+ """
649
+ command = RunCommand()
650
+ result = command.execute(args)
651
+
652
+ # For run command, we don't typically need structured output
653
+ # but we should respect the exit code
654
+ return result.exit_code
655
+
656
+
657
+ def run_session_legacy(args):
658
+ """
659
+ Legacy run session implementation.
660
+
661
+ WHY: This contains the original run_session logic, preserved during migration
662
+ to BaseCommand pattern. Will be gradually refactored into the RunCommand class.
663
+
164
664
  DESIGN DECISION: We use ClaudeRunner to handle the complexity of
165
665
  subprocess management and hook integration, keeping this function focused
166
666
  on high-level orchestration.
167
-
667
+
168
668
  Args:
169
669
  args: Parsed command line arguments
170
670
  """
671
+ # Only setup startup logging if user wants logging
672
+ if args.logging != LogLevel.OFF.value:
673
+ # Set up startup logging to file early in the process
674
+ setup_startup_logging(Path.cwd())
675
+
171
676
  logger = get_logger("cli")
172
677
  if args.logging != LogLevel.OFF.value:
173
678
  logger.info("Starting Claude MPM session")
174
-
679
+ # Log file already announced in startup_logging.py when created
680
+
681
+ # Clean up old startup logs (using configured retention count)
682
+ if args.logging != LogLevel.OFF.value:
683
+ try:
684
+ deleted_count = cleanup_old_startup_logs(Path.cwd())
685
+ if deleted_count > 0:
686
+ logger.debug(f"Cleaned up {deleted_count} old startup log files")
687
+ except Exception as e:
688
+ logger.debug(f"Failed to clean up old logs: {e}")
689
+
690
+ # Log MCP and monitor startup status
691
+ if args.logging != LogLevel.OFF.value:
692
+ monitor_mode = getattr(args, "monitor", False)
693
+ websocket_port = getattr(args, "websocket_port", 8765)
694
+ log_startup_status(monitor_mode, websocket_port)
695
+
696
+ # Perform startup configuration check
697
+ _check_configuration_health(logger)
698
+
699
+ # Check for memory usage issues with .claude.json
700
+ _check_claude_json_memory(args, logger)
701
+
702
+ # Handle --reload-agents flag if specified
703
+ if getattr(args, "reload_agents", False):
704
+ _handle_reload_agents(logger)
705
+
706
+ # Trigger vector search indexing
707
+ try:
708
+ from ...cli.startup_logging import start_vector_search_indexing
709
+
710
+ start_vector_search_indexing()
711
+ except Exception as e:
712
+ logger.debug(f"Failed to start vector search indexing: {e}")
713
+
175
714
  try:
176
715
  from ...core.claude_runner import ClaudeRunner, create_simple_context
177
- from ...core.session_manager import SessionManager
178
716
  except ImportError:
179
717
  from claude_mpm.core.claude_runner import ClaudeRunner, create_simple_context
180
- from claude_mpm.core.session_manager import SessionManager
181
-
182
- # Handle session resumption
718
+
719
+ # Handle session resumption using the new SessionManager service
183
720
  session_manager = SessionManager()
184
721
  resume_session_id = None
185
722
  resume_context = None
186
-
187
- if hasattr(args, 'resume') and args.resume:
188
- if args.resume == "last":
723
+
724
+ if hasattr(args, "mpm_resume") and args.mpm_resume:
725
+ if args.mpm_resume == "last":
189
726
  # Resume the last interactive session
190
727
  resume_session_id = session_manager.get_last_interactive_session()
191
728
  if resume_session_id:
192
- session_data = session_manager.get_session_by_id(resume_session_id)
729
+ session_data = session_manager.get_session_info(resume_session_id)
193
730
  if session_data:
194
731
  resume_context = session_data.get("context", "default")
195
- logger.info(f"Resuming session {resume_session_id} (context: {resume_context})")
196
- print(f"🔄 Resuming session {resume_session_id[:8]}... (created: {session_data.get('created_at', 'unknown')})")
732
+ logger.info(
733
+ f"Resuming session {resume_session_id} (context: {resume_context})"
734
+ )
735
+ print(
736
+ f"🔄 Resuming session {resume_session_id[:8]}... (created: {session_data.get('created_at', 'unknown')})"
737
+ )
197
738
  else:
198
739
  logger.warning(f"Session {resume_session_id} not found")
199
740
  else:
200
741
  logger.info("No recent interactive sessions found")
201
- print("ℹ️ No recent interactive sessions found to resume")
742
+ print("[INFO]️ No recent interactive sessions found to resume")
202
743
  else:
203
744
  # Resume specific session by ID
204
- resume_session_id = args.resume
205
- session_data = session_manager.get_session_by_id(resume_session_id)
745
+ resume_session_id = args.mpm_resume
746
+ session_data = session_manager.get_session_info(resume_session_id)
206
747
  if session_data:
207
748
  resume_context = session_data.get("context", "default")
208
- logger.info(f"Resuming session {resume_session_id} (context: {resume_context})")
209
- print(f"🔄 Resuming session {resume_session_id[:8]}... (context: {resume_context})")
749
+ logger.info(
750
+ f"Resuming session {resume_session_id} (context: {resume_context})"
751
+ )
752
+ print(
753
+ f"🔄 Resuming session {resume_session_id[:8]}... (context: {resume_context})"
754
+ )
210
755
  else:
211
756
  logger.error(f"Session {resume_session_id} not found")
212
757
  print(f"❌ Session {resume_session_id} not found")
213
758
  print("💡 Use 'claude-mpm sessions' to list available sessions")
214
759
  return
215
-
760
+
761
+ # Deploy MPM slash commands to user's Claude configuration
762
+ try:
763
+ from ...services.command_deployment_service import deploy_commands_on_startup
764
+
765
+ deploy_commands_on_startup(force=False)
766
+ except Exception as e:
767
+ logger.debug(f"Failed to deploy MPM commands (non-critical): {e}")
768
+
216
769
  # Skip native agents if disabled
217
- if getattr(args, 'no_native_agents', False):
770
+ if getattr(args, "no_native_agents", False):
218
771
  print("Native agents disabled")
219
772
  else:
220
- # List deployed agent versions at startup
221
- list_agent_versions_at_startup()
222
-
773
+ # Agent versions removed from startup display - use /mpm-agents to view
774
+ # list_agent_versions_at_startup()
775
+ pass
776
+
777
+ # Smart dependency checking - only when needed
778
+ if getattr(args, "check_dependencies", True): # Default to checking
779
+ try:
780
+ from ...utils.agent_dependency_loader import AgentDependencyLoader
781
+ from ...utils.dependency_cache import SmartDependencyChecker
782
+ from ...utils.environment_context import should_prompt_for_dependencies
783
+
784
+ # Initialize smart checker
785
+ smart_checker = SmartDependencyChecker()
786
+ loader = AgentDependencyLoader(auto_install=False)
787
+
788
+ # Check if agents have changed
789
+ _has_changed, deployment_hash = loader.has_agents_changed()
790
+
791
+ # Determine if we should check dependencies
792
+ should_check, check_reason = smart_checker.should_check_dependencies(
793
+ force_check=getattr(args, "force_check_dependencies", False),
794
+ deployment_hash=deployment_hash,
795
+ )
796
+
797
+ if should_check:
798
+ # Check if we're in an environment where prompting makes sense
799
+ can_prompt, prompt_reason = should_prompt_for_dependencies(
800
+ force_prompt=getattr(args, "force_prompt", False),
801
+ force_skip=getattr(args, "no_prompt", False),
802
+ )
803
+
804
+ logger.debug(f"Dependency check needed: {check_reason}")
805
+ logger.debug(f"Interactive prompting: {can_prompt} ({prompt_reason})")
806
+
807
+ # Get or check dependencies
808
+ results, was_cached = smart_checker.get_or_check_dependencies(
809
+ loader=loader,
810
+ force_check=getattr(args, "force_check_dependencies", False),
811
+ )
812
+
813
+ # Show summary if there are missing dependencies
814
+ if results["summary"]["missing_python"]:
815
+ missing_count = len(results["summary"]["missing_python"])
816
+ print(f"⚠️ {missing_count} agent dependencies missing")
817
+
818
+ if can_prompt and missing_count > 0:
819
+ # Interactive prompt for installation
820
+ print("\n📦 Missing dependencies detected:")
821
+ for dep in results["summary"]["missing_python"][:5]:
822
+ print(f" - {dep}")
823
+ if missing_count > 5:
824
+ print(f" ... and {missing_count - 5} more")
825
+
826
+ print("\nWould you like to install them now?")
827
+ print(" [y] Yes, install missing dependencies")
828
+ print(" [n] No, continue without installing")
829
+ print(" [q] Quit")
830
+
831
+ sys.stdout.flush() # Ensure prompt is displayed before input
832
+
833
+ # Check if we're in a TTY environment for proper input handling
834
+ if not sys.stdin.isatty():
835
+ # In non-TTY environment (like pipes), use readline
836
+ print("\nChoice [y/n/q]: ", end="", flush=True)
837
+ try:
838
+ response = sys.stdin.readline().strip().lower()
839
+ # Handle various line endings and control characters
840
+ response = (
841
+ response.replace("\r", "").replace("\n", "").strip()
842
+ )
843
+ except (EOFError, KeyboardInterrupt):
844
+ response = "q"
845
+ else:
846
+ # In TTY environment, use normal input()
847
+ try:
848
+ response = input("\nChoice [y/n/q]: ").strip().lower()
849
+ except (EOFError, KeyboardInterrupt):
850
+ response = "q"
851
+
852
+ try:
853
+ if response == "y":
854
+ print("\n🔧 Installing missing dependencies...")
855
+ loader.auto_install = True
856
+ (
857
+ success,
858
+ error,
859
+ ) = loader.install_missing_dependencies(
860
+ results["summary"]["missing_python"]
861
+ )
862
+ if success:
863
+ print("✅ Dependencies installed successfully")
864
+ # Invalidate cache after installation
865
+ smart_checker.cache.invalidate(deployment_hash)
866
+ else:
867
+ print(f"❌ Installation failed: {error}")
868
+ elif response == "q":
869
+ print("👋 Exiting...")
870
+ return
871
+ else:
872
+ print("⏩ Continuing without installing dependencies")
873
+ except (EOFError, KeyboardInterrupt):
874
+ print("\n⏩ Continuing without installing dependencies")
875
+ else:
876
+ # Non-interactive environment or prompting disabled
877
+ print(
878
+ " Run 'pip install \"claude-mpm[agents]\"' to install all agent dependencies"
879
+ )
880
+ if not can_prompt:
881
+ logger.debug(
882
+ f"Not prompting for installation: {prompt_reason}"
883
+ )
884
+ elif was_cached:
885
+ logger.debug("Dependencies satisfied (cached result)")
886
+ else:
887
+ logger.debug("All dependencies satisfied")
888
+ else:
889
+ logger.debug(f"Skipping dependency check: {check_reason}")
890
+
891
+ except Exception as e:
892
+ if args.logging != LogLevel.OFF.value:
893
+ logger.debug(f"Could not check agent dependencies: {e}")
894
+ # Continue anyway - don't block execution
895
+
223
896
  # Create simple runner
224
897
  enable_tickets = not args.no_tickets
225
- raw_claude_args = getattr(args, 'claude_args', []) or []
898
+ raw_claude_args = getattr(args, "claude_args", []) or []
899
+
900
+ # Add --resume to claude_args if the flag is set
901
+ resume_flag_present = getattr(args, "resume", False)
902
+ if resume_flag_present:
903
+ logger.info("📌 --resume flag detected in args")
904
+ if "--resume" not in raw_claude_args:
905
+ raw_claude_args = ["--resume", *raw_claude_args]
906
+ logger.info("✅ Added --resume to claude_args")
907
+ else:
908
+ logger.info("[INFO]️ --resume already in claude_args")
909
+
226
910
  # Filter out claude-mpm specific flags before passing to Claude CLI
911
+ logger.debug(f"Pre-filter claude_args: {raw_claude_args}")
227
912
  claude_args = filter_claude_mpm_args(raw_claude_args)
228
- monitor_mode = getattr(args, 'monitor', False)
229
-
230
- # Debug logging for argument filtering
913
+ monitor_mode = getattr(args, "monitor", False)
914
+
915
+ # Enhanced debug logging for argument filtering
231
916
  if raw_claude_args != claude_args:
232
- logger.debug(f"Filtered claude-mpm args: {set(raw_claude_args) - set(claude_args)}")
233
- logger.debug(f"Passing to Claude CLI: {claude_args}")
234
-
917
+ filtered_out = list(set(raw_claude_args) - set(claude_args))
918
+ logger.debug(f"Filtered out MPM-specific args: {filtered_out}")
919
+
920
+ logger.info(f"Final claude_args being passed: {claude_args}")
921
+
922
+ # Explicit verification of --resume flag
923
+ if resume_flag_present:
924
+ if "--resume" in claude_args:
925
+ logger.info("✅ CONFIRMED: --resume flag will be passed to Claude CLI")
926
+ else:
927
+ logger.error("❌ WARNING: --resume flag was filtered out! This is a bug!")
928
+ logger.error(f" Original args: {raw_claude_args}")
929
+ logger.error(f" Filtered args: {claude_args}")
930
+
235
931
  # Use the specified launch method (default: exec)
236
- launch_method = getattr(args, 'launch_method', 'exec')
237
-
238
- enable_websocket = getattr(args, 'monitor', False) or monitor_mode
239
- websocket_port = getattr(args, 'websocket_port', 8765)
240
-
932
+ launch_method = getattr(args, "launch_method", "exec")
933
+
934
+ enable_websocket = getattr(args, "monitor", False) or monitor_mode
935
+ websocket_port = getattr(args, "websocket_port", 8765)
936
+
241
937
  # Display Socket.IO server info if enabled
242
938
  if enable_websocket:
243
- # Auto-install Socket.IO dependencies if needed
939
+ # Use UnifiedDashboardManager for server management
940
+ dashboard_manager = UnifiedDashboardManager(logger)
941
+
942
+ # Check dependencies
244
943
  print("🔧 Checking Socket.IO dependencies...")
245
- dependencies_ok, error_msg = ensure_socketio_dependencies(logger)
246
-
247
- if not dependencies_ok:
944
+ deps_ok, error_msg = dashboard_manager.ensure_dependencies()
945
+
946
+ if not deps_ok:
248
947
  print(f"❌ Failed to install Socket.IO dependencies: {error_msg}")
249
- print(" Please install manually: pip install python-socketio aiohttp python-engineio")
948
+ print(
949
+ " Please install manually: pip install python-socketio aiohttp python-engineio"
950
+ )
250
951
  print(" Or install with extras: pip install claude-mpm[monitor]")
251
952
  # Continue anyway - some functionality might still work
252
953
  else:
253
954
  print("✓ Socket.IO dependencies ready")
254
-
255
- try:
256
- import socketio
257
- print(f"✓ Socket.IO server enabled at http://localhost:{websocket_port}")
258
- if launch_method == "exec":
259
- print(" Note: Socket.IO monitoring using exec mode with Claude Code hooks")
260
-
261
- # Launch Socket.IO dashboard if in monitor mode
955
+
956
+ # Find available port and start server if in monitor mode
262
957
  if monitor_mode:
263
- success, browser_opened = launch_socketio_monitor(websocket_port, logger)
264
- if not success:
265
- print(f"⚠️ Failed to launch Socket.IO monitor")
266
- print(f" You can manually run: python scripts/launch_socketio_dashboard.py --port {websocket_port}")
267
- # Store whether browser was opened by CLI for coordination with ClaudeRunner
268
- args._browser_opened_by_cli = browser_opened
269
- except ImportError as e:
270
- print(f"⚠️ Socket.IO still not available after installation attempt: {e}")
271
- print(" This might be a virtual environment issue.")
272
- print(" Try: pip install python-socketio aiohttp python-engineio")
273
- print(" Or: pip install claude-mpm[monitor]")
274
-
958
+ websocket_port = dashboard_manager.find_available_port(websocket_port)
959
+ success, server_info = dashboard_manager.start_server(
960
+ port=websocket_port
961
+ )
962
+
963
+ if success:
964
+ print(f"✓ Socket.IO server enabled at {server_info.url}")
965
+ if launch_method == "exec":
966
+ print(
967
+ " Note: Socket.IO monitoring using exec mode with Claude Code hooks"
968
+ )
969
+
970
+ # Use UnifiedDashboardManager for browser opening
971
+ dashboard_manager = UnifiedDashboardManager(logger)
972
+ monitor_url = dashboard_manager.get_dashboard_url(websocket_port)
973
+ browser_opened = dashboard_manager.open_browser(monitor_url)
974
+ args._browser_opened_by_cli = browser_opened
975
+
976
+ if not browser_opened:
977
+ print(f"💡 Monitor interface available at: {monitor_url}")
978
+ else:
979
+ print("⚠️ Failed to launch Socket.IO monitor")
980
+ print("Dashboard is not running. To enable monitoring:")
981
+ print(" 1. Use the --monitor flag: claude-mpm run --monitor")
982
+ print(
983
+ " 2. Or start dashboard separately: claude-mpm dashboard start"
984
+ )
985
+ print(
986
+ f" 3. Dashboard will be available at: http://localhost:{websocket_port}"
987
+ )
988
+ args._browser_opened_by_cli = False
989
+ else:
990
+ print(f"✓ Socket.IO ready (port: {websocket_port})")
991
+
275
992
  runner = ClaudeRunner(
276
993
  enable_tickets=enable_tickets,
277
994
  log_level=args.logging,
278
995
  claude_args=claude_args,
279
996
  launch_method=launch_method,
280
997
  enable_websocket=enable_websocket,
281
- websocket_port=websocket_port
998
+ websocket_port=websocket_port,
282
999
  )
283
-
1000
+
1001
+ # Agent deployment is handled by ClaudeRunner.setup_agents() and
1002
+ # ClaudeRunner.deploy_project_agents_to_claude() which are called
1003
+ # in both run_interactive() and run_oneshot() methods.
1004
+ # No need for redundant deployment here.
1005
+
284
1006
  # Set browser opening flag for monitor mode
285
1007
  if monitor_mode:
286
1008
  runner._should_open_monitor_browser = True
287
1009
  # Pass information about whether we already opened the browser in run.py
288
- runner._browser_opened_by_cli = getattr(args, '_browser_opened_by_cli', False)
289
-
1010
+ runner._browser_opened_by_cli = getattr(args, "_browser_opened_by_cli", False)
1011
+
290
1012
  # Create context - use resumed session context if available
291
1013
  if resume_session_id and resume_context:
292
1014
  # For resumed sessions, create enhanced context with session information
293
1015
  context = create_session_context(resume_session_id, session_manager)
294
1016
  # Update session usage
295
- session_manager.active_sessions[resume_session_id]["last_used"] = datetime.now().isoformat()
296
- session_manager.active_sessions[resume_session_id]["use_count"] += 1
297
- session_manager._save_sessions()
1017
+ session = session_manager.load_session(resume_session_id)
1018
+ if session:
1019
+ session.last_used = datetime.now(timezone.utc).isoformat()
1020
+ session.use_count += 1
1021
+ session_manager.save_session(session)
298
1022
  else:
299
1023
  # Create a new session for tracking
300
- new_session_id = session_manager.create_session("default")
1024
+ new_session = session_manager.create_session("default")
301
1025
  context = create_simple_context()
302
- logger.info(f"Created new session {new_session_id}")
303
-
1026
+ logger.info(f"Created new session {new_session.id}")
1027
+
304
1028
  # For monitor mode, we handled everything in launch_socketio_monitor
305
1029
  # No need for ClaudeRunner browser delegation
306
1030
  if monitor_mode:
307
1031
  # Clear any browser opening flags since we handled it completely
308
1032
  runner._should_open_monitor_browser = False
309
1033
  runner._browser_opened_by_cli = True # Prevent duplicate opening
310
-
1034
+
311
1035
  # Run session based on mode
312
1036
  if args.non_interactive or args.input:
313
1037
  # Non-interactive mode
@@ -315,373 +1039,71 @@ def run_session(args):
315
1039
  success = runner.run_oneshot(user_input, context)
316
1040
  if not success:
317
1041
  logger.error("Session failed")
318
- else:
319
- # Interactive mode
320
- if getattr(args, 'intercept_commands', False):
321
- # Use the interactive wrapper for command interception
322
- # WHY: Command interception requires special handling of stdin/stdout
323
- # which is better done in a separate Python script
324
- wrapper_path = get_scripts_dir() / "interactive_wrapper.py"
325
- if wrapper_path.exists():
326
- print("Starting interactive session with command interception...")
327
- subprocess.run([sys.executable, str(wrapper_path)])
328
- else:
329
- logger.warning("Interactive wrapper not found, falling back to normal mode")
330
- runner.run_interactive(context)
1042
+ # Interactive mode
1043
+ elif getattr(args, "intercept_commands", False):
1044
+ wrapper_path = get_scripts_dir() / "interactive_wrapper.py"
1045
+ if wrapper_path.exists():
1046
+ print("Starting interactive session with command interception...")
1047
+ subprocess.run([sys.executable, str(wrapper_path)], check=False)
331
1048
  else:
1049
+ logger.warning("Interactive wrapper not found, falling back to normal mode")
332
1050
  runner.run_interactive(context)
1051
+ else:
1052
+ runner.run_interactive(context)
333
1053
 
334
1054
 
1055
+ # Legacy helper functions - now delegating to UnifiedDashboardManager
335
1056
  def launch_socketio_monitor(port, logger):
336
- """
337
- Launch the Socket.IO monitoring dashboard using static HTML file.
338
-
339
- WHY: This function opens a static HTML file that connects to the Socket.IO server.
340
- This approach is simpler and more reliable than serving the dashboard from the server.
341
- The HTML file connects to whatever Socket.IO server is running on the specified port.
342
-
343
- DESIGN DECISION: Use file:// protocol to open static HTML file directly from filesystem.
344
- Pass the server port as a URL parameter so the dashboard knows which port to connect to.
345
- This decouples the dashboard from the server serving and makes it more robust.
346
-
347
- Args:
348
- port: Port number for the Socket.IO server
349
- logger: Logger instance for output
350
-
351
- Returns:
352
- tuple: (success: bool, browser_opened: bool) - success status and whether browser was opened
353
- """
354
- try:
355
- # Verify Socket.IO dependencies are available
356
- try:
357
- import socketio
358
- import aiohttp
359
- import engineio
360
- logger.debug("Socket.IO dependencies verified")
361
- except ImportError as e:
362
- logger.error(f"Socket.IO dependencies not available: {e}")
363
- print(f"❌ Socket.IO dependencies missing: {e}")
364
- print(" This is unexpected - dependency installation may have failed.")
365
- return False, False
366
-
367
- print(f"🚀 Setting up Socket.IO monitor on port {port}...")
368
- logger.info(f"Launching Socket.IO monitor on port {port}")
369
-
370
- socketio_port = port
371
-
372
- # Use HTTP URL to access dashboard from Socket.IO server
373
- dashboard_url = f'http://localhost:{socketio_port}'
374
-
375
- # Check if Socket.IO server is already running
376
- server_running = _check_socketio_server_running(socketio_port, logger)
377
-
378
- if server_running:
379
- print(f"✅ Socket.IO server already running on port {socketio_port}")
380
-
381
- # Check if it's managed by our daemon
382
- daemon_script = get_package_root() / "scripts" / "socketio_daemon.py"
383
- if daemon_script.exists():
384
- status_result = subprocess.run(
385
- [sys.executable, str(daemon_script), "status"],
386
- capture_output=True,
387
- text=True
388
- )
389
- if "is running" in status_result.stdout:
390
- print(f" (Managed by Python daemon)")
391
-
392
- print(f"📊 Dashboard: {dashboard_url}")
393
-
394
- # Open browser with static HTML file
395
- try:
396
- # Check if we should suppress browser opening (for tests)
397
- if os.environ.get('CLAUDE_MPM_NO_BROWSER') != '1':
398
- print(f"🌐 Opening dashboard in browser...")
399
- open_in_browser_tab(dashboard_url, logger)
400
- logger.info(f"Socket.IO dashboard opened: {dashboard_url}")
401
- else:
402
- print(f"🌐 Browser opening suppressed (CLAUDE_MPM_NO_BROWSER=1)")
403
- logger.info(f"Browser opening suppressed by environment variable")
404
- return True, True
405
- except Exception as e:
406
- logger.warning(f"Failed to open browser: {e}")
407
- print(f"⚠️ Could not open browser automatically")
408
- print(f"📊 Please open manually: {dashboard_url}")
409
- return True, False
410
- else:
411
- # Start standalone Socket.IO server
412
- print(f"🔧 Starting Socket.IO server on port {socketio_port}...")
413
- server_started = _start_standalone_socketio_server(socketio_port, logger)
414
-
415
- if server_started:
416
- print(f"✅ Socket.IO server started successfully")
417
- print(f"📊 Dashboard: {dashboard_url}")
418
-
419
- # Final verification that server is responsive
420
- final_check_passed = False
421
- for i in range(3):
422
- if _check_socketio_server_running(socketio_port, logger):
423
- final_check_passed = True
424
- break
425
- time.sleep(1)
426
-
427
- if not final_check_passed:
428
- logger.warning("Server started but final connectivity check failed")
429
- print(f"⚠️ Server may still be initializing. Dashboard should work once fully ready.")
430
-
431
- # Open browser with static HTML file
432
- try:
433
- # Check if we should suppress browser opening (for tests)
434
- if os.environ.get('CLAUDE_MPM_NO_BROWSER') != '1':
435
- print(f"🌐 Opening dashboard in browser...")
436
- open_in_browser_tab(dashboard_url, logger)
437
- logger.info(f"Socket.IO dashboard opened: {dashboard_url}")
438
- else:
439
- print(f"🌐 Browser opening suppressed (CLAUDE_MPM_NO_BROWSER=1)")
440
- logger.info(f"Browser opening suppressed by environment variable")
441
- return True, True
442
- except Exception as e:
443
- logger.warning(f"Failed to open browser: {e}")
444
- print(f"⚠️ Could not open browser automatically")
445
- print(f"📊 Please open manually: {dashboard_url}")
446
- return True, False
447
- else:
448
- print(f"❌ Failed to start Socket.IO server")
449
- print(f"💡 Troubleshooting tips:")
450
- print(f" - Check if port {socketio_port} is already in use")
451
- print(f" - Verify Socket.IO dependencies: pip install python-socketio aiohttp")
452
- print(f" - Try a different port with --websocket-port")
453
- return False, False
454
-
455
- except Exception as e:
456
- logger.error(f"Failed to launch Socket.IO monitor: {e}")
457
- print(f"❌ Failed to launch Socket.IO monitor: {e}")
458
- return False, False
1057
+ """Launch the Socket.IO monitoring dashboard (legacy compatibility)."""
1058
+ dashboard_manager = UnifiedDashboardManager(logger)
1059
+ success, server_info = dashboard_manager.start_server(port=port)
1060
+
1061
+ if success:
1062
+ # Open browser using UnifiedDashboardManager
1063
+ browser_opened = dashboard_manager.open_browser(server_info.url)
1064
+ return success, browser_opened
1065
+
1066
+ return False, False
459
1067
 
460
1068
 
461
1069
  def _check_socketio_server_running(port, logger):
462
- """
463
- Check if a Socket.IO server is running on the specified port.
464
-
465
- WHY: We need to detect existing servers to avoid conflicts and provide
466
- seamless experience regardless of whether server is already running.
467
-
468
- DESIGN DECISION: We try multiple endpoints and connection methods to ensure
469
- robust detection. Some servers may be starting up and only partially ready.
470
- Added retry logic to handle race conditions during server initialization.
471
-
472
- Args:
473
- port: Port number to check
474
- logger: Logger instance for output
475
-
476
- Returns:
477
- bool: True if server is running and responding, False otherwise
478
- """
479
- try:
480
- import urllib.request
481
- import urllib.error
482
- import socket
483
-
484
- # First, do a basic TCP connection check
485
- try:
486
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
487
- s.settimeout(2.0) # Increased from 1.0s for slower connections
488
- result = s.connect_ex(('127.0.0.1', port))
489
- if result != 0:
490
- logger.debug(f"TCP connection to port {port} failed (server not started yet)")
491
- return False
492
- except Exception as e:
493
- logger.debug(f"TCP socket check failed for port {port}: {e}")
494
- return False
495
-
496
- # If TCP connection succeeds, try HTTP health check with retries
497
- # WHY: Even when TCP is accepting connections, the HTTP handler may not be ready
498
- max_retries = 3
499
- for retry in range(max_retries):
500
- try:
501
- response = urllib.request.urlopen(f'http://localhost:{port}/status', timeout=10) # Increased from 5s to 10s
502
-
503
- if response.getcode() == 200:
504
- content = response.read().decode()
505
- logger.debug(f"✅ Socket.IO server health check passed on port {port} (attempt {retry + 1})")
506
- logger.debug(f"📄 Server response: {content[:100]}...")
507
- return True
508
- else:
509
- logger.debug(f"⚠️ HTTP response code {response.getcode()} from port {port} (attempt {retry + 1})")
510
- if retry < max_retries - 1:
511
- time.sleep(0.5) # Brief pause before retry
512
-
513
- except urllib.error.HTTPError as e:
514
- logger.debug(f"⚠️ HTTP error {e.code} from server on port {port} (attempt {retry + 1})")
515
- if retry < max_retries - 1 and e.code in [404, 503]: # Server starting but not ready
516
- logger.debug("Server appears to be starting, retrying...")
517
- time.sleep(0.5)
518
- continue
519
- return False
520
- except urllib.error.URLError as e:
521
- logger.debug(f"⚠️ URL error connecting to port {port} (attempt {retry + 1}): {e.reason}")
522
- if retry < max_retries - 1:
523
- logger.debug("Connection refused - server may still be initializing, retrying...")
524
- time.sleep(0.5)
525
- continue
526
- return False
527
-
528
- # All retries exhausted
529
- logger.debug(f"Health check failed after {max_retries} attempts - server not fully ready")
530
- return False
531
-
532
- except (ConnectionError, OSError) as e:
533
- logger.debug(f"🔌 Connection error checking port {port}: {e}")
534
- except Exception as e:
535
- logger.debug(f"❌ Unexpected error checking Socket.IO server on port {port}: {e}")
536
-
537
- return False
1070
+ """Check if a Socket.IO server is running on the specified port (legacy compatibility)."""
1071
+ dashboard_manager = UnifiedDashboardManager(logger)
1072
+ return dashboard_manager.is_server_running(port)
538
1073
 
539
1074
 
540
1075
  def _start_standalone_socketio_server(port, logger):
541
- """
542
- Start a standalone Socket.IO server using the Python daemon.
543
-
544
- WHY: For monitor mode, we want a persistent server that runs independently
545
- of the Claude session. This allows users to monitor multiple sessions and
546
- keeps the dashboard available even when Claude isn't running.
547
-
548
- DESIGN DECISION: We use a pure Python daemon script to manage the server
549
- process. This avoids Node.js dependencies (like PM2) and provides proper
550
- process management with PID tracking.
551
-
552
- Args:
553
- port: Port number for the server
554
- logger: Logger instance for output
555
-
556
- Returns:
557
- bool: True if server started successfully, False otherwise
558
- """
559
- try:
560
- from ...deployment_paths import get_scripts_dir
561
- import subprocess
562
-
563
- # Get path to daemon script in package
564
- daemon_script = get_package_root() / "scripts" / "socketio_daemon.py"
565
-
566
- if not daemon_script.exists():
567
- logger.error(f"Socket.IO daemon script not found: {daemon_script}")
568
- return False
569
-
570
- logger.info(f"Starting Socket.IO server daemon on port {port}")
571
-
572
- # Start the daemon
573
- result = subprocess.run(
574
- [sys.executable, str(daemon_script), "start"],
575
- capture_output=True,
576
- text=True
577
- )
578
-
579
- if result.returncode != 0:
580
- logger.error(f"Failed to start Socket.IO daemon: {result.stderr}")
581
- return False
582
-
583
- # Wait for server to be ready with longer timeouts and progressive delays
584
- # WHY: Socket.IO server startup involves complex async initialization:
585
- # 1. Thread creation (~0.1s)
586
- # 2. Event loop setup (~1s)
587
- # 3. aiohttp server binding (~2-5s)
588
- # 4. Socket.IO service initialization (~1-3s)
589
- # Total: up to 15+ seconds for full readiness (especially on Python 3.13)
590
- max_attempts = 30 # Increased from 20 to handle Python 3.13 slower initialization
591
- initial_delay = 1.0 # Increased from 0.5s to give daemon more time to fork
592
- max_delay = 3.0 # Increased from 2.0s for slower systems
593
-
594
- logger.info(f"Waiting up to {max_attempts * max_delay} seconds for server to be fully ready...")
595
-
596
- # Give the daemon initial time to fork and start before checking
597
- logger.debug("Allowing initial daemon startup time...")
598
- time.sleep(0.5)
599
-
600
- for attempt in range(max_attempts):
601
- # Progressive delay - start fast, then slow down for socket binding
602
- if attempt < 5:
603
- delay = initial_delay
604
- else:
605
- delay = min(max_delay, initial_delay + (attempt - 5) * 0.2)
606
-
607
- logger.debug(f"Checking server readiness (attempt {attempt + 1}/{max_attempts}, waiting {delay}s)")
608
-
609
- # Give the daemon process time to initialize and bind to the socket
610
- time.sleep(delay)
611
-
612
- # Check if the daemon server is accepting connections
613
- if _check_socketio_server_running(port, logger):
614
- logger.info(f"✅ Standalone Socket.IO server started successfully on port {port}")
615
- logger.info(f"🕐 Server ready after {attempt + 1} attempts ({(attempt + 1) * delay:.1f}s)")
616
- return True
617
- else:
618
- logger.debug(f"Server not yet accepting connections on attempt {attempt + 1}")
619
-
620
- logger.error(f"❌ Socket.IO server health check failed after {max_attempts} attempts ({max_attempts * max_delay:.1f}s)")
621
- logger.warning(f"⏱️ Server may still be starting - initialization can take 15+ seconds on some systems")
622
- logger.warning(f"💡 The daemon process might be running but not yet accepting HTTP connections")
623
- logger.error(f"🔧 Troubleshooting steps:")
624
- logger.error(f" - Wait a few more seconds and try again")
625
- logger.error(f" - Check for port conflicts: lsof -i :{port}")
626
- logger.error(f" - Try a different port with --websocket-port")
627
- logger.error(f" - Verify dependencies: pip install python-socketio aiohttp")
628
- return False
629
-
630
- except Exception as e:
631
- logger.error(f"❌ Failed to start standalone Socket.IO server: {e}")
632
- import traceback
633
- logger.error(f"📋 Stack trace: {traceback.format_exc()}")
634
- logger.error(f"💡 This may be a dependency issue - try: pip install python-socketio aiohttp")
635
- return False
636
-
1076
+ """Start a standalone Socket.IO server (legacy compatibility)."""
1077
+ dashboard_manager = UnifiedDashboardManager(logger)
1078
+ success, _ = dashboard_manager.start_server(port=port)
1079
+ return success
637
1080
 
638
1081
 
639
1082
  def open_in_browser_tab(url, logger):
640
- """
641
- Open URL in browser, attempting to reuse existing tabs when possible.
642
-
643
- WHY: Users prefer reusing browser tabs instead of opening new ones constantly.
644
- This function attempts platform-specific solutions for tab reuse.
645
-
646
- DESIGN DECISION: We try different methods based on platform capabilities,
647
- falling back to standard webbrowser.open() if needed.
648
-
649
- Args:
650
- url: URL to open
651
- logger: Logger instance for output
652
- """
653
- try:
654
- # Platform-specific optimizations for tab reuse
655
- import platform
656
- system = platform.system().lower()
657
-
658
- if system == "darwin": # macOS
659
- # Just use the standard webbrowser module on macOS
660
- # The AppleScript approach is too unreliable
661
- webbrowser.open(url, new=0, autoraise=True) # new=0 tries to reuse window
662
- logger.info("Opened browser on macOS")
663
-
664
- elif system == "linux":
665
- # On Linux, try to use existing browser session
666
- try:
667
- # This is a best-effort approach for common browsers
668
- webbrowser.get().open(url, new=0) # new=0 tries to reuse existing window
669
- logger.info("Attempted Linux browser tab reuse")
670
- except Exception:
671
- webbrowser.open(url, autoraise=True)
672
-
673
- elif system == "windows":
674
- # On Windows, try to use existing browser
675
- try:
676
- webbrowser.get().open(url, new=0) # new=0 tries to reuse existing window
677
- logger.info("Attempted Windows browser tab reuse")
678
- except Exception:
679
- webbrowser.open(url, autoraise=True)
680
- else:
681
- # Unknown platform, use standard opening
682
- webbrowser.open(url, autoraise=True)
683
-
684
- except Exception as e:
685
- logger.warning(f"Browser opening failed: {e}")
686
- # Final fallback
687
- webbrowser.open(url)
1083
+ """Open URL in browser, attempting to reuse existing tabs when possible."""
1084
+ manager = UnifiedDashboardManager(logger)
1085
+ return manager.open_browser(url)
1086
+
1087
+
1088
+ def _check_claude_json_memory(args, logger):
1089
+ """Check .claude.json file size and warn about memory issues."""
1090
+ # Use new StartupCheckerService
1091
+ from ...core.config import Config
1092
+
1093
+ config_service = Config()
1094
+ checker = StartupCheckerService(config_service)
1095
+ resume_enabled = getattr(args, "mpm_resume", False)
1096
+ warning = checker.check_memory(resume_enabled)
1097
+ if warning:
1098
+ checker.display_warnings([warning])
1099
+
1100
+
1101
+ def _check_configuration_health(logger):
1102
+ """Check configuration health at startup and warn about issues."""
1103
+ # Use new StartupCheckerService
1104
+ from ...core.config import Config
1105
+
1106
+ config_service = Config()
1107
+ checker = StartupCheckerService(config_service)
1108
+ warnings = checker.check_configuration()
1109
+ checker.display_warnings(warnings)