claude-mpm 4.1.1__py3-none-any.whl → 4.1.2__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 (357) hide show
  1. claude_mpm/BUILD_NUMBER +1 -1
  2. claude_mpm/VERSION +1 -1
  3. claude_mpm/__main__.py +1 -1
  4. claude_mpm/agents/BASE_PM.md +74 -46
  5. claude_mpm/agents/INSTRUCTIONS.md +11 -153
  6. claude_mpm/agents/WORKFLOW.md +61 -321
  7. claude_mpm/agents/__init__.py +11 -11
  8. claude_mpm/agents/agent_loader.py +23 -20
  9. claude_mpm/agents/agent_loader_integration.py +1 -1
  10. claude_mpm/agents/agents_metadata.py +27 -0
  11. claude_mpm/agents/async_agent_loader.py +5 -8
  12. claude_mpm/agents/base_agent_loader.py +36 -25
  13. claude_mpm/agents/frontmatter_validator.py +6 -6
  14. claude_mpm/agents/schema/agent_schema.json +1 -1
  15. claude_mpm/agents/system_agent_config.py +9 -9
  16. claude_mpm/agents/templates/api_qa.json +47 -2
  17. claude_mpm/agents/templates/imagemagick.json +256 -0
  18. claude_mpm/agents/templates/qa.json +41 -2
  19. claude_mpm/agents/templates/ticketing.json +5 -5
  20. claude_mpm/agents/templates/web_qa.json +50 -2
  21. claude_mpm/cli/__init__.py +51 -46
  22. claude_mpm/cli/__main__.py +1 -1
  23. claude_mpm/cli/commands/__init__.py +10 -12
  24. claude_mpm/cli/commands/agent_manager.py +186 -181
  25. claude_mpm/cli/commands/agents.py +271 -268
  26. claude_mpm/cli/commands/aggregate.py +30 -29
  27. claude_mpm/cli/commands/cleanup.py +50 -44
  28. claude_mpm/cli/commands/cleanup_orphaned_agents.py +25 -25
  29. claude_mpm/cli/commands/config.py +162 -127
  30. claude_mpm/cli/commands/doctor.py +52 -62
  31. claude_mpm/cli/commands/info.py +37 -25
  32. claude_mpm/cli/commands/mcp.py +3 -7
  33. claude_mpm/cli/commands/mcp_command_router.py +14 -18
  34. claude_mpm/cli/commands/mcp_install_commands.py +28 -23
  35. claude_mpm/cli/commands/mcp_pipx_config.py +58 -49
  36. claude_mpm/cli/commands/mcp_server_commands.py +23 -17
  37. claude_mpm/cli/commands/memory.py +192 -141
  38. claude_mpm/cli/commands/monitor.py +117 -88
  39. claude_mpm/cli/commands/run.py +120 -84
  40. claude_mpm/cli/commands/run_config_checker.py +4 -5
  41. claude_mpm/cli/commands/socketio_monitor.py +17 -19
  42. claude_mpm/cli/commands/tickets.py +92 -92
  43. claude_mpm/cli/parser.py +1 -5
  44. claude_mpm/cli/parsers/__init__.py +1 -1
  45. claude_mpm/cli/parsers/agent_manager_parser.py +50 -98
  46. claude_mpm/cli/parsers/agents_parser.py +2 -3
  47. claude_mpm/cli/parsers/base_parser.py +7 -5
  48. claude_mpm/cli/parsers/mcp_parser.py +4 -2
  49. claude_mpm/cli/parsers/monitor_parser.py +26 -18
  50. claude_mpm/cli/shared/__init__.py +10 -10
  51. claude_mpm/cli/shared/argument_patterns.py +57 -71
  52. claude_mpm/cli/shared/base_command.py +61 -53
  53. claude_mpm/cli/shared/error_handling.py +62 -58
  54. claude_mpm/cli/shared/output_formatters.py +78 -77
  55. claude_mpm/cli/startup_logging.py +204 -172
  56. claude_mpm/cli/utils.py +10 -11
  57. claude_mpm/cli_module/__init__.py +1 -1
  58. claude_mpm/cli_module/args.py +1 -1
  59. claude_mpm/cli_module/migration_example.py +5 -5
  60. claude_mpm/config/__init__.py +9 -9
  61. claude_mpm/config/agent_config.py +15 -14
  62. claude_mpm/config/experimental_features.py +4 -4
  63. claude_mpm/config/paths.py +0 -1
  64. claude_mpm/config/socketio_config.py +5 -6
  65. claude_mpm/constants.py +1 -2
  66. claude_mpm/core/__init__.py +8 -8
  67. claude_mpm/core/agent_name_normalizer.py +1 -1
  68. claude_mpm/core/agent_registry.py +20 -23
  69. claude_mpm/core/agent_session_manager.py +3 -3
  70. claude_mpm/core/base_service.py +7 -15
  71. claude_mpm/core/cache.py +4 -6
  72. claude_mpm/core/claude_runner.py +85 -113
  73. claude_mpm/core/config.py +43 -28
  74. claude_mpm/core/config_aliases.py +0 -9
  75. claude_mpm/core/config_constants.py +52 -30
  76. claude_mpm/core/constants.py +0 -1
  77. claude_mpm/core/container.py +18 -27
  78. claude_mpm/core/exceptions.py +2 -2
  79. claude_mpm/core/factories.py +10 -12
  80. claude_mpm/core/framework_loader.py +581 -280
  81. claude_mpm/core/hook_manager.py +26 -22
  82. claude_mpm/core/hook_performance_config.py +58 -47
  83. claude_mpm/core/injectable_service.py +1 -1
  84. claude_mpm/core/interactive_session.py +61 -152
  85. claude_mpm/core/interfaces.py +1 -100
  86. claude_mpm/core/lazy.py +5 -5
  87. claude_mpm/core/log_manager.py +587 -0
  88. claude_mpm/core/logger.py +125 -8
  89. claude_mpm/core/logging_config.py +15 -15
  90. claude_mpm/core/minimal_framework_loader.py +5 -8
  91. claude_mpm/core/oneshot_session.py +15 -33
  92. claude_mpm/core/optimized_agent_loader.py +4 -6
  93. claude_mpm/core/optimized_startup.py +2 -1
  94. claude_mpm/core/output_style_manager.py +147 -106
  95. claude_mpm/core/pm_hook_interceptor.py +0 -1
  96. claude_mpm/core/service_registry.py +11 -8
  97. claude_mpm/core/session_manager.py +1 -2
  98. claude_mpm/core/shared/__init__.py +1 -1
  99. claude_mpm/core/shared/config_loader.py +101 -97
  100. claude_mpm/core/shared/path_resolver.py +72 -68
  101. claude_mpm/core/shared/singleton_manager.py +56 -50
  102. claude_mpm/core/socketio_pool.py +26 -6
  103. claude_mpm/core/tool_access_control.py +4 -5
  104. claude_mpm/core/typing_utils.py +50 -59
  105. claude_mpm/core/unified_agent_registry.py +14 -19
  106. claude_mpm/core/unified_config.py +4 -6
  107. claude_mpm/core/unified_paths.py +197 -109
  108. claude_mpm/dashboard/open_dashboard.py +2 -4
  109. claude_mpm/experimental/cli_enhancements.py +51 -36
  110. claude_mpm/generators/agent_profile_generator.py +2 -4
  111. claude_mpm/hooks/base_hook.py +1 -2
  112. claude_mpm/hooks/claude_hooks/connection_pool.py +72 -26
  113. claude_mpm/hooks/claude_hooks/event_handlers.py +93 -38
  114. claude_mpm/hooks/claude_hooks/hook_handler.py +130 -76
  115. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
  116. claude_mpm/hooks/claude_hooks/memory_integration.py +2 -4
  117. claude_mpm/hooks/claude_hooks/response_tracking.py +15 -11
  118. claude_mpm/hooks/claude_hooks/tool_analysis.py +12 -18
  119. claude_mpm/hooks/memory_integration_hook.py +5 -5
  120. claude_mpm/hooks/tool_call_interceptor.py +1 -1
  121. claude_mpm/hooks/validation_hooks.py +4 -4
  122. claude_mpm/init.py +4 -9
  123. claude_mpm/models/__init__.py +2 -2
  124. claude_mpm/models/agent_session.py +11 -14
  125. claude_mpm/scripts/mcp_server.py +20 -11
  126. claude_mpm/scripts/mcp_wrapper.py +5 -5
  127. claude_mpm/scripts/mpm_doctor.py +321 -0
  128. claude_mpm/scripts/socketio_daemon.py +28 -25
  129. claude_mpm/scripts/socketio_daemon_hardened.py +298 -258
  130. claude_mpm/scripts/socketio_server_manager.py +116 -95
  131. claude_mpm/services/__init__.py +49 -49
  132. claude_mpm/services/agent_capabilities_service.py +12 -18
  133. claude_mpm/services/agents/__init__.py +22 -22
  134. claude_mpm/services/agents/agent_builder.py +140 -119
  135. claude_mpm/services/agents/deployment/__init__.py +3 -3
  136. claude_mpm/services/agents/deployment/agent_config_provider.py +9 -9
  137. claude_mpm/services/agents/deployment/agent_configuration_manager.py +19 -20
  138. claude_mpm/services/agents/deployment/agent_definition_factory.py +1 -5
  139. claude_mpm/services/agents/deployment/agent_deployment.py +136 -106
  140. claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -8
  141. claude_mpm/services/agents/deployment/agent_environment_manager.py +2 -7
  142. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +6 -10
  143. claude_mpm/services/agents/deployment/agent_format_converter.py +11 -15
  144. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +2 -3
  145. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -5
  146. claude_mpm/services/agents/deployment/agent_metrics_collector.py +13 -19
  147. claude_mpm/services/agents/deployment/agent_restore_handler.py +0 -1
  148. claude_mpm/services/agents/deployment/agent_template_builder.py +26 -35
  149. claude_mpm/services/agents/deployment/agent_validator.py +0 -1
  150. claude_mpm/services/agents/deployment/agent_version_manager.py +7 -9
  151. claude_mpm/services/agents/deployment/agent_versioning.py +3 -3
  152. claude_mpm/services/agents/deployment/agents_directory_resolver.py +6 -7
  153. claude_mpm/services/agents/deployment/async_agent_deployment.py +51 -38
  154. claude_mpm/services/agents/deployment/config/__init__.py +1 -1
  155. claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
  156. claude_mpm/services/agents/deployment/deployment_type_detector.py +1 -1
  157. claude_mpm/services/agents/deployment/deployment_wrapper.py +18 -18
  158. claude_mpm/services/agents/deployment/facade/__init__.py +1 -1
  159. claude_mpm/services/agents/deployment/facade/deployment_executor.py +0 -3
  160. claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -4
  161. claude_mpm/services/agents/deployment/interface_adapter.py +5 -7
  162. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +345 -276
  163. claude_mpm/services/agents/deployment/pipeline/__init__.py +2 -2
  164. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +1 -1
  165. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +6 -4
  166. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +3 -3
  167. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +2 -2
  168. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +14 -13
  169. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +0 -1
  170. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +1 -1
  171. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +8 -9
  172. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +1 -1
  173. claude_mpm/services/agents/deployment/processors/__init__.py +1 -1
  174. claude_mpm/services/agents/deployment/processors/agent_processor.py +20 -16
  175. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +5 -12
  176. claude_mpm/services/agents/deployment/results/__init__.py +1 -1
  177. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +1 -1
  178. claude_mpm/services/agents/deployment/strategies/__init__.py +2 -2
  179. claude_mpm/services/agents/deployment/strategies/base_strategy.py +1 -7
  180. claude_mpm/services/agents/deployment/strategies/project_strategy.py +1 -4
  181. claude_mpm/services/agents/deployment/strategies/system_strategy.py +2 -3
  182. claude_mpm/services/agents/deployment/strategies/user_strategy.py +3 -7
  183. claude_mpm/services/agents/deployment/validation/__init__.py +1 -1
  184. claude_mpm/services/agents/deployment/validation/agent_validator.py +1 -1
  185. claude_mpm/services/agents/deployment/validation/template_validator.py +2 -2
  186. claude_mpm/services/agents/deployment/validation/validation_result.py +2 -6
  187. claude_mpm/services/agents/loading/__init__.py +1 -1
  188. claude_mpm/services/agents/loading/agent_profile_loader.py +6 -12
  189. claude_mpm/services/agents/loading/base_agent_manager.py +5 -5
  190. claude_mpm/services/agents/loading/framework_agent_loader.py +2 -4
  191. claude_mpm/services/agents/management/__init__.py +1 -1
  192. claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -3
  193. claude_mpm/services/agents/management/agent_management_service.py +5 -9
  194. claude_mpm/services/agents/memory/__init__.py +4 -4
  195. claude_mpm/services/agents/memory/agent_memory_manager.py +280 -160
  196. claude_mpm/services/agents/memory/agent_persistence_service.py +0 -2
  197. claude_mpm/services/agents/memory/content_manager.py +44 -38
  198. claude_mpm/services/agents/memory/template_generator.py +4 -6
  199. claude_mpm/services/agents/registry/__init__.py +10 -6
  200. claude_mpm/services/agents/registry/deployed_agent_discovery.py +30 -27
  201. claude_mpm/services/agents/registry/modification_tracker.py +3 -6
  202. claude_mpm/services/async_session_logger.py +1 -2
  203. claude_mpm/services/claude_session_logger.py +1 -2
  204. claude_mpm/services/command_deployment_service.py +173 -0
  205. claude_mpm/services/command_handler_service.py +20 -22
  206. claude_mpm/services/core/__init__.py +25 -25
  207. claude_mpm/services/core/base.py +0 -5
  208. claude_mpm/services/core/interfaces/__init__.py +32 -32
  209. claude_mpm/services/core/interfaces/agent.py +0 -21
  210. claude_mpm/services/core/interfaces/communication.py +0 -27
  211. claude_mpm/services/core/interfaces/infrastructure.py +0 -56
  212. claude_mpm/services/core/interfaces/service.py +0 -29
  213. claude_mpm/services/diagnostics/__init__.py +1 -1
  214. claude_mpm/services/diagnostics/checks/__init__.py +6 -6
  215. claude_mpm/services/diagnostics/checks/agent_check.py +89 -80
  216. claude_mpm/services/diagnostics/checks/base_check.py +12 -16
  217. claude_mpm/services/diagnostics/checks/claude_desktop_check.py +84 -81
  218. claude_mpm/services/diagnostics/checks/common_issues_check.py +99 -91
  219. claude_mpm/services/diagnostics/checks/configuration_check.py +82 -77
  220. claude_mpm/services/diagnostics/checks/filesystem_check.py +67 -68
  221. claude_mpm/services/diagnostics/checks/installation_check.py +254 -94
  222. claude_mpm/services/diagnostics/checks/mcp_check.py +90 -88
  223. claude_mpm/services/diagnostics/checks/monitor_check.py +75 -76
  224. claude_mpm/services/diagnostics/checks/startup_log_check.py +67 -73
  225. claude_mpm/services/diagnostics/diagnostic_runner.py +67 -59
  226. claude_mpm/services/diagnostics/doctor_reporter.py +107 -70
  227. claude_mpm/services/diagnostics/models.py +21 -19
  228. claude_mpm/services/event_aggregator.py +10 -17
  229. claude_mpm/services/event_bus/__init__.py +1 -1
  230. claude_mpm/services/event_bus/config.py +54 -35
  231. claude_mpm/services/event_bus/event_bus.py +76 -71
  232. claude_mpm/services/event_bus/relay.py +74 -64
  233. claude_mpm/services/events/__init__.py +11 -11
  234. claude_mpm/services/events/consumers/__init__.py +3 -3
  235. claude_mpm/services/events/consumers/dead_letter.py +71 -63
  236. claude_mpm/services/events/consumers/logging.py +39 -37
  237. claude_mpm/services/events/consumers/metrics.py +56 -57
  238. claude_mpm/services/events/consumers/socketio.py +82 -81
  239. claude_mpm/services/events/core.py +110 -99
  240. claude_mpm/services/events/interfaces.py +56 -72
  241. claude_mpm/services/events/producers/__init__.py +1 -1
  242. claude_mpm/services/events/producers/hook.py +38 -38
  243. claude_mpm/services/events/producers/system.py +46 -44
  244. claude_mpm/services/exceptions.py +81 -80
  245. claude_mpm/services/framework_claude_md_generator/__init__.py +2 -4
  246. claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -5
  247. claude_mpm/services/framework_claude_md_generator/content_validator.py +1 -1
  248. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +4 -4
  249. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -1
  250. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -2
  251. claude_mpm/services/framework_claude_md_generator/version_manager.py +4 -5
  252. claude_mpm/services/hook_service.py +6 -9
  253. claude_mpm/services/infrastructure/__init__.py +1 -1
  254. claude_mpm/services/infrastructure/context_preservation.py +8 -12
  255. claude_mpm/services/infrastructure/monitoring.py +21 -23
  256. claude_mpm/services/mcp_gateway/__init__.py +37 -37
  257. claude_mpm/services/mcp_gateway/auto_configure.py +95 -103
  258. claude_mpm/services/mcp_gateway/config/__init__.py +1 -1
  259. claude_mpm/services/mcp_gateway/config/config_loader.py +23 -25
  260. claude_mpm/services/mcp_gateway/config/config_schema.py +5 -5
  261. claude_mpm/services/mcp_gateway/config/configuration.py +9 -6
  262. claude_mpm/services/mcp_gateway/core/__init__.py +10 -10
  263. claude_mpm/services/mcp_gateway/core/base.py +0 -3
  264. claude_mpm/services/mcp_gateway/core/interfaces.py +1 -38
  265. claude_mpm/services/mcp_gateway/core/process_pool.py +99 -93
  266. claude_mpm/services/mcp_gateway/core/singleton_manager.py +65 -62
  267. claude_mpm/services/mcp_gateway/core/startup_verification.py +75 -74
  268. claude_mpm/services/mcp_gateway/main.py +2 -1
  269. claude_mpm/services/mcp_gateway/registry/service_registry.py +5 -8
  270. claude_mpm/services/mcp_gateway/registry/tool_registry.py +1 -1
  271. claude_mpm/services/mcp_gateway/server/__init__.py +1 -1
  272. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +12 -19
  273. claude_mpm/services/mcp_gateway/server/stdio_handler.py +4 -3
  274. claude_mpm/services/mcp_gateway/server/stdio_server.py +79 -71
  275. claude_mpm/services/mcp_gateway/tools/__init__.py +2 -2
  276. claude_mpm/services/mcp_gateway/tools/base_adapter.py +5 -6
  277. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +13 -22
  278. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +79 -78
  279. claude_mpm/services/mcp_gateway/tools/hello_world.py +12 -14
  280. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +42 -49
  281. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +51 -55
  282. claude_mpm/services/memory/__init__.py +3 -3
  283. claude_mpm/services/memory/builder.py +3 -6
  284. claude_mpm/services/memory/cache/__init__.py +1 -1
  285. claude_mpm/services/memory/cache/shared_prompt_cache.py +3 -5
  286. claude_mpm/services/memory/cache/simple_cache.py +1 -1
  287. claude_mpm/services/memory/indexed_memory.py +5 -7
  288. claude_mpm/services/memory/optimizer.py +7 -10
  289. claude_mpm/services/memory/router.py +8 -9
  290. claude_mpm/services/memory_hook_service.py +48 -34
  291. claude_mpm/services/monitor_build_service.py +77 -73
  292. claude_mpm/services/port_manager.py +130 -108
  293. claude_mpm/services/project/analyzer.py +12 -10
  294. claude_mpm/services/project/registry.py +11 -11
  295. claude_mpm/services/recovery_manager.py +10 -19
  296. claude_mpm/services/response_tracker.py +0 -1
  297. claude_mpm/services/runner_configuration_service.py +19 -20
  298. claude_mpm/services/session_management_service.py +7 -11
  299. claude_mpm/services/shared/__init__.py +1 -1
  300. claude_mpm/services/shared/async_service_base.py +58 -50
  301. claude_mpm/services/shared/config_service_base.py +73 -67
  302. claude_mpm/services/shared/lifecycle_service_base.py +82 -78
  303. claude_mpm/services/shared/manager_base.py +94 -82
  304. claude_mpm/services/shared/service_factory.py +96 -98
  305. claude_mpm/services/socketio/__init__.py +3 -3
  306. claude_mpm/services/socketio/client_proxy.py +5 -5
  307. claude_mpm/services/socketio/event_normalizer.py +199 -181
  308. claude_mpm/services/socketio/handlers/__init__.py +3 -3
  309. claude_mpm/services/socketio/handlers/base.py +5 -4
  310. claude_mpm/services/socketio/handlers/connection.py +163 -136
  311. claude_mpm/services/socketio/handlers/file.py +13 -14
  312. claude_mpm/services/socketio/handlers/git.py +12 -7
  313. claude_mpm/services/socketio/handlers/hook.py +49 -44
  314. claude_mpm/services/socketio/handlers/memory.py +0 -1
  315. claude_mpm/services/socketio/handlers/project.py +0 -1
  316. claude_mpm/services/socketio/handlers/registry.py +37 -19
  317. claude_mpm/services/socketio/migration_utils.py +98 -84
  318. claude_mpm/services/socketio/server/__init__.py +1 -1
  319. claude_mpm/services/socketio/server/broadcaster.py +81 -87
  320. claude_mpm/services/socketio/server/core.py +65 -54
  321. claude_mpm/services/socketio/server/eventbus_integration.py +95 -56
  322. claude_mpm/services/socketio/server/main.py +64 -38
  323. claude_mpm/services/socketio_client_manager.py +10 -12
  324. claude_mpm/services/subprocess_launcher_service.py +4 -7
  325. claude_mpm/services/system_instructions_service.py +13 -14
  326. claude_mpm/services/ticket_manager.py +2 -2
  327. claude_mpm/services/utility_service.py +5 -13
  328. claude_mpm/services/version_control/__init__.py +16 -16
  329. claude_mpm/services/version_control/branch_strategy.py +5 -8
  330. claude_mpm/services/version_control/conflict_resolution.py +9 -23
  331. claude_mpm/services/version_control/git_operations.py +5 -7
  332. claude_mpm/services/version_control/semantic_versioning.py +16 -17
  333. claude_mpm/services/version_control/version_parser.py +13 -18
  334. claude_mpm/services/version_service.py +10 -11
  335. claude_mpm/storage/__init__.py +1 -1
  336. claude_mpm/storage/state_storage.py +22 -28
  337. claude_mpm/utils/__init__.py +6 -6
  338. claude_mpm/utils/agent_dependency_loader.py +47 -33
  339. claude_mpm/utils/config_manager.py +11 -14
  340. claude_mpm/utils/dependency_cache.py +1 -1
  341. claude_mpm/utils/dependency_manager.py +13 -17
  342. claude_mpm/utils/dependency_strategies.py +8 -10
  343. claude_mpm/utils/environment_context.py +3 -9
  344. claude_mpm/utils/error_handler.py +3 -13
  345. claude_mpm/utils/file_utils.py +1 -1
  346. claude_mpm/utils/path_operations.py +8 -12
  347. claude_mpm/utils/robust_installer.py +110 -33
  348. claude_mpm/utils/subprocess_utils.py +5 -6
  349. claude_mpm/validation/agent_validator.py +3 -6
  350. claude_mpm/validation/frontmatter_validator.py +1 -1
  351. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/METADATA +1 -1
  352. claude_mpm-4.1.2.dist-info/RECORD +498 -0
  353. claude_mpm-4.1.1.dist-info/RECORD +0 -494
  354. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/WHEEL +0 -0
  355. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/entry_points.txt +0 -0
  356. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/licenses/LICENSE +0 -0
  357. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/top_level.txt +0 -0
@@ -15,28 +15,27 @@ DESIGN DECISIONS:
15
15
  """
16
16
 
17
17
  import logging
18
- import os
19
18
  import shutil
20
19
  import subprocess
21
20
  import sys
22
21
  from datetime import datetime
23
22
  from pathlib import Path
24
- from typing import Any, Dict, Optional, Tuple
23
+ from typing import Any, Dict, Optional
25
24
 
26
25
  from ..core.logger import get_logger
27
26
 
28
27
 
29
28
  class StartupStatusLogger:
30
29
  """Logs MCP server and monitor setup status during startup."""
31
-
30
+
32
31
  def __init__(self, logger_name: str = "startup_status"):
33
32
  """Initialize the startup status logger."""
34
33
  self.logger = get_logger(logger_name)
35
-
34
+
36
35
  def log_mcp_server_status(self) -> None:
37
36
  """
38
37
  Log MCP server installation and configuration status.
39
-
38
+
40
39
  Checks:
41
40
  - MCP server executable availability
42
41
  - MCP server version if available
@@ -48,7 +47,7 @@ class StartupStatusLogger:
48
47
  mcp_executable = self._find_mcp_executable()
49
48
  if mcp_executable:
50
49
  self.logger.info(f"MCP Server: Installed at {mcp_executable}")
51
-
50
+
52
51
  # Try to get version
53
52
  version = self._get_mcp_version(mcp_executable)
54
53
  if version:
@@ -57,20 +56,22 @@ class StartupStatusLogger:
57
56
  self.logger.info("MCP Server: Version unknown")
58
57
  else:
59
58
  self.logger.info("MCP Server: Not found in PATH")
60
-
59
+
61
60
  # Check MCP configuration in ~/.claude.json
62
61
  config_status = self._check_mcp_configuration()
63
62
  if config_status["found"]:
64
63
  self.logger.info("MCP Server: Configuration found in ~/.claude.json")
65
64
  if config_status["servers_count"] > 0:
66
- self.logger.info(f"MCP Server: {config_status['servers_count']} server(s) configured")
65
+ self.logger.info(
66
+ f"MCP Server: {config_status['servers_count']} server(s) configured"
67
+ )
67
68
  else:
68
69
  self.logger.info("MCP Server: No servers configured")
69
70
  self._log_mcp_setup_hint()
70
71
  else:
71
72
  self.logger.info("MCP Server: No configuration found in ~/.claude.json")
72
73
  self._log_mcp_setup_hint()
73
-
74
+
74
75
  # Check for claude-mpm MCP gateway status
75
76
  gateway_status = self._check_mcp_gateway_status()
76
77
  if gateway_status["configured"]:
@@ -78,20 +79,27 @@ class StartupStatusLogger:
78
79
  else:
79
80
  self.logger.info("MCP Gateway: Claude MPM gateway not configured")
80
81
  # Check if this is a pipx installation that could benefit from auto-config
81
- if self._is_pipx_installation() and not self._has_auto_config_preference():
82
- self.logger.info("MCP Gateway: Auto-configuration available for pipx users")
83
-
82
+ if (
83
+ self._is_pipx_installation()
84
+ and not self._has_auto_config_preference()
85
+ ):
86
+ self.logger.info(
87
+ "MCP Gateway: Auto-configuration available for pipx users"
88
+ )
89
+
84
90
  except Exception as e:
85
91
  self.logger.warning(f"MCP Server: Status check failed - {e}")
86
-
87
- def log_monitor_setup_status(self, monitor_mode: bool = False, websocket_port: int = 8765) -> None:
92
+
93
+ def log_monitor_setup_status(
94
+ self, monitor_mode: bool = False, websocket_port: int = 8765
95
+ ) -> None:
88
96
  """
89
97
  Log monitor service initialization status.
90
-
98
+
91
99
  Args:
92
100
  monitor_mode: Whether monitor mode is enabled
93
101
  websocket_port: WebSocket port for monitoring
94
-
102
+
95
103
  Checks:
96
104
  - Monitor service initialization status
97
105
  - Which monitors are enabled/disabled
@@ -101,235 +109,246 @@ class StartupStatusLogger:
101
109
  try:
102
110
  if monitor_mode:
103
111
  self.logger.info("Monitor: Mode enabled")
104
-
112
+
105
113
  # Check SocketIO dependencies
106
114
  socketio_status = self._check_socketio_dependencies()
107
115
  if socketio_status["available"]:
108
116
  self.logger.info("Monitor: Socket.IO dependencies available")
109
117
  else:
110
- self.logger.info(f"Monitor: Socket.IO dependencies missing - {socketio_status['error']}")
111
-
118
+ self.logger.info(
119
+ f"Monitor: Socket.IO dependencies missing - {socketio_status['error']}"
120
+ )
121
+
112
122
  # Check if server is running
113
123
  server_running = self._check_socketio_server_running(websocket_port)
114
124
  if server_running:
115
- self.logger.info(f"Monitor: Socket.IO server running on port {websocket_port}")
125
+ self.logger.info(
126
+ f"Monitor: Socket.IO server running on port {websocket_port}"
127
+ )
116
128
  else:
117
- self.logger.info(f"Monitor: Socket.IO server will start on port {websocket_port}")
118
-
129
+ self.logger.info(
130
+ f"Monitor: Socket.IO server will start on port {websocket_port}"
131
+ )
132
+
119
133
  # Check response logging configuration
120
134
  logging_config = self._check_response_logging_config()
121
135
  if logging_config["enabled"]:
122
- self.logger.info(f"Monitor: Response logging enabled to {logging_config['directory']}")
136
+ self.logger.info(
137
+ f"Monitor: Response logging enabled to {logging_config['directory']}"
138
+ )
123
139
  else:
124
140
  self.logger.info("Monitor: Response logging disabled")
125
-
141
+
126
142
  else:
127
143
  self.logger.info("Monitor: Mode disabled")
128
-
144
+
129
145
  # Still check if there's an existing server running
130
146
  server_running = self._check_socketio_server_running(websocket_port)
131
147
  if server_running:
132
- self.logger.info(f"Monitor: Background Socket.IO server detected on port {websocket_port}")
133
-
148
+ self.logger.info(
149
+ f"Monitor: Background Socket.IO server detected on port {websocket_port}"
150
+ )
151
+
134
152
  except Exception as e:
135
153
  self.logger.warning(f"Monitor: Status check failed - {e}")
136
-
154
+
137
155
  def _find_mcp_executable(self) -> Optional[str]:
138
156
  """Find MCP server executable in PATH."""
139
157
  # Common MCP executable names
140
158
  executables = ["claude-mpm-mcp", "mcp", "claude-mcp"]
141
-
159
+
142
160
  for exe_name in executables:
143
161
  exe_path = shutil.which(exe_name)
144
162
  if exe_path:
145
163
  return exe_path
146
-
164
+
147
165
  # Check if it's installed as a Python package
148
166
  try:
149
167
  result = subprocess.run(
150
168
  [sys.executable, "-m", "claude_mpm.scripts.mcp_server", "--version"],
151
169
  capture_output=True,
152
170
  text=True,
153
- timeout=5
171
+ timeout=5,
172
+ check=False,
154
173
  )
155
174
  if result.returncode == 0:
156
175
  return f"{sys.executable} -m claude_mpm.scripts.mcp_server"
157
176
  except Exception:
158
177
  pass
159
-
178
+
160
179
  return None
161
-
180
+
162
181
  def _get_mcp_version(self, executable: str) -> Optional[str]:
163
182
  """Get MCP server version."""
164
183
  try:
165
184
  # Try --version flag
166
185
  result = subprocess.run(
167
- executable.split() + ["--version"],
186
+ [*executable.split(), "--version"],
168
187
  capture_output=True,
169
188
  text=True,
170
- timeout=5
189
+ timeout=5,
190
+ check=False,
171
191
  )
172
192
  if result.returncode == 0:
173
193
  # Extract version from output
174
194
  output = result.stdout.strip()
175
195
  if output:
176
196
  return output
177
-
197
+
178
198
  # Try version command
179
199
  result = subprocess.run(
180
- executable.split() + ["version"],
200
+ [*executable.split(), "version"],
181
201
  capture_output=True,
182
202
  text=True,
183
- timeout=5
203
+ timeout=5,
204
+ check=False,
184
205
  )
185
206
  if result.returncode == 0:
186
207
  output = result.stdout.strip()
187
208
  if output:
188
209
  return output
189
-
210
+
190
211
  except Exception:
191
212
  pass
192
-
213
+
193
214
  return None
194
-
215
+
195
216
  def _check_mcp_configuration(self) -> Dict[str, Any]:
196
217
  """Check MCP configuration in ~/.claude.json."""
197
218
  claude_json_path = Path.home() / ".claude.json"
198
-
199
- result = {
200
- "found": False,
201
- "servers_count": 0,
202
- "error": None
203
- }
204
-
219
+
220
+ result = {"found": False, "servers_count": 0, "error": None}
221
+
205
222
  try:
206
223
  if not claude_json_path.exists():
207
224
  return result
208
-
225
+
209
226
  import json
210
- with open(claude_json_path, 'r') as f:
227
+
228
+ with open(claude_json_path) as f:
211
229
  config = json.load(f)
212
-
230
+
213
231
  result["found"] = True
214
-
232
+
215
233
  # Check for MCP servers configuration
216
234
  mcp_config = config.get("mcpServers", {})
217
235
  result["servers_count"] = len(mcp_config)
218
-
236
+
219
237
  except Exception as e:
220
238
  result["error"] = str(e)
221
-
239
+
222
240
  return result
223
-
241
+
224
242
  def _check_mcp_gateway_status(self) -> Dict[str, Any]:
225
243
  """Check Claude MPM MCP gateway configuration status."""
226
- result = {
227
- "configured": False,
228
- "error": None
229
- }
230
-
244
+ result = {"configured": False, "error": None}
245
+
231
246
  try:
232
247
  # Check if MCP gateway startup verification is available
233
- from ..services.mcp_gateway.core.startup_verification import is_mcp_gateway_configured
248
+ from ..services.mcp_gateway.core.startup_verification import (
249
+ is_mcp_gateway_configured,
250
+ )
251
+
234
252
  result["configured"] = is_mcp_gateway_configured()
235
253
  except ImportError:
236
254
  # MCP gateway not available
237
255
  pass
238
256
  except Exception as e:
239
257
  result["error"] = str(e)
240
-
258
+
241
259
  return result
242
-
260
+
243
261
  def _check_socketio_dependencies(self) -> Dict[str, Any]:
244
262
  """Check if Socket.IO dependencies are available."""
245
- result = {
246
- "available": False,
247
- "error": None
248
- }
249
-
263
+ result = {"available": False, "error": None}
264
+
250
265
  try:
251
- import socketio
252
266
  import aiohttp
253
267
  import engineio
268
+ import socketio
269
+
254
270
  result["available"] = True
255
271
  except ImportError as e:
256
272
  result["error"] = f"Missing dependencies: {e}"
257
273
  except Exception as e:
258
274
  result["error"] = str(e)
259
-
275
+
260
276
  return result
261
-
277
+
262
278
  def _check_socketio_server_running(self, port: int) -> bool:
263
279
  """Check if Socket.IO server is running on specified port."""
264
280
  try:
265
281
  import socket
282
+
266
283
  with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
267
284
  s.settimeout(1)
268
- result = s.connect_ex(('localhost', port))
285
+ result = s.connect_ex(("localhost", port))
269
286
  return result == 0
270
287
  except Exception:
271
288
  return False
272
-
289
+
273
290
  def _check_response_logging_config(self) -> Dict[str, Any]:
274
291
  """Check response logging configuration."""
275
- result = {
276
- "enabled": False,
277
- "directory": None,
278
- "error": None
279
- }
280
-
292
+ result = {"enabled": False, "directory": None, "error": None}
293
+
281
294
  try:
282
295
  from ..core.shared.config_loader import ConfigLoader
283
-
296
+
284
297
  config_loader = ConfigLoader()
285
298
  config = config_loader.load_main_config()
286
-
299
+
287
300
  # Check response logging configuration
288
301
  response_logging = config.get("response_logging", {})
289
302
  result["enabled"] = response_logging.get("enabled", False)
290
-
303
+
291
304
  if result["enabled"]:
292
- log_dir = response_logging.get("session_directory", ".claude-mpm/responses")
305
+ log_dir = response_logging.get(
306
+ "session_directory", ".claude-mpm/responses"
307
+ )
293
308
  if not Path(log_dir).is_absolute():
294
309
  log_dir = Path.cwd() / log_dir
295
310
  result["directory"] = str(log_dir)
296
-
311
+
297
312
  except Exception as e:
298
313
  result["error"] = str(e)
299
-
314
+
300
315
  return result
301
-
316
+
302
317
  def _is_pipx_installation(self) -> bool:
303
318
  """Check if this is a pipx installation."""
304
319
  try:
305
320
  # Check if running from pipx
306
321
  if "pipx" in sys.executable.lower():
307
322
  return True
308
-
323
+
309
324
  # Check module path
310
325
  import claude_mpm
326
+
311
327
  module_path = Path(claude_mpm.__file__).parent
312
328
  if "pipx" in str(module_path):
313
329
  return True
314
330
  except Exception:
315
331
  pass
316
-
332
+
317
333
  return False
318
-
334
+
319
335
  def _has_auto_config_preference(self) -> bool:
320
336
  """Check if user has already been asked about auto-configuration."""
321
337
  try:
322
338
  from ..config.paths import paths
323
- preference_file = paths.claude_mpm_dir_hidden / "mcp_auto_config_preference.json"
339
+
340
+ preference_file = (
341
+ paths.claude_mpm_dir_hidden / "mcp_auto_config_preference.json"
342
+ )
324
343
  return preference_file.exists()
325
344
  except Exception:
326
345
  return False
327
-
346
+
328
347
  def _log_mcp_setup_hint(self) -> None:
329
348
  """Log helpful hints for MCP setup."""
330
349
  # Check if installed via pipx
331
350
  is_pipx = self._check_pipx_installation()
332
-
351
+
333
352
  if is_pipx:
334
353
  self.logger.info("💡 TIP: It looks like you installed claude-mpm via pipx")
335
354
  self.logger.info(" To configure MCP for Claude Code with pipx:")
@@ -341,198 +360,211 @@ class StartupStatusLogger:
341
360
  self.logger.info(" 1. See docs/MCP_SETUP.md for setup instructions")
342
361
  self.logger.info(" 2. Run: claude-mpm doctor --check mcp to verify")
343
362
  self.logger.info(" 3. Restart Claude Code after configuration")
344
-
363
+
345
364
  def _check_pipx_installation(self) -> bool:
346
365
  """Check if claude-mpm was installed via pipx."""
347
366
  try:
348
367
  # Check if running from a pipx venv
349
368
  if "pipx" in sys.executable.lower():
350
369
  return True
351
-
370
+
352
371
  # Check if claude-mpm-mcp command exists and is from pipx
353
372
  mcp_cmd = shutil.which("claude-mpm-mcp")
354
373
  if mcp_cmd and "pipx" in mcp_cmd.lower():
355
374
  return True
356
-
375
+
357
376
  # Try to check pipx list
358
377
  result = subprocess.run(
359
- ["pipx", "list"],
360
- capture_output=True,
361
- text=True,
362
- timeout=2
378
+ ["pipx", "list"], capture_output=True, text=True, timeout=2, check=False
363
379
  )
364
380
  if result.returncode == 0 and "claude-mpm" in result.stdout:
365
381
  return True
366
-
382
+
367
383
  except Exception:
368
384
  pass
369
-
385
+
370
386
  return False
371
387
 
372
388
 
373
389
  def setup_startup_logging(project_root: Optional[Path] = None) -> Path:
374
390
  """
375
391
  Set up logging to both console and file for startup.
376
-
392
+
377
393
  WHY: Capture all startup logs (INFO, WARNING, ERROR, DEBUG) to timestamped
378
394
  files for later analysis by the doctor command. This helps diagnose
379
395
  startup issues that users may not notice in the console output.
380
-
396
+
381
397
  DESIGN DECISIONS:
382
398
  - Use ISO-like timestamp format for easy sorting and reading
383
399
  - Store in .claude-mpm/logs/startup/ directory
384
400
  - Keep all historical startup logs for pattern analysis
385
401
  - Add file handler to root logger to capture ALL module logs
386
-
402
+
387
403
  Args:
388
404
  project_root: Root directory for the project (defaults to cwd)
389
-
405
+
390
406
  Returns:
391
407
  Path to the created log file
392
408
  """
393
409
  if project_root is None:
394
410
  project_root = Path.cwd()
395
-
411
+
396
412
  # Create log directory
397
413
  log_dir = project_root / ".claude-mpm" / "logs" / "startup"
398
414
  log_dir.mkdir(parents=True, exist_ok=True)
399
-
415
+
400
416
  # Generate timestamp for log file
401
417
  timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
402
418
  log_file = log_dir / f"startup-{timestamp}.log"
403
-
419
+
404
420
  # Create file handler with detailed formatting
405
- file_handler = logging.FileHandler(log_file, encoding='utf-8')
421
+ file_handler = logging.FileHandler(log_file, encoding="utf-8")
406
422
  file_handler.setLevel(logging.DEBUG) # Capture all levels to file
407
-
423
+
408
424
  # Format with timestamp, logger name, level, and message
409
425
  formatter = logging.Formatter(
410
- '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
411
- datefmt='%Y-%m-%d %H:%M:%S'
426
+ "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
427
+ datefmt="%Y-%m-%d %H:%M:%S",
412
428
  )
413
429
  file_handler.setFormatter(formatter)
414
-
430
+
415
431
  # Add to claude_mpm logger to capture all our logs
416
432
  # (Don't add to root logger to avoid duplicates from propagation)
417
433
  claude_logger = logging.getLogger("claude_mpm")
418
434
  claude_logger.addHandler(file_handler)
419
435
  claude_logger.setLevel(logging.DEBUG) # Ensure all levels are captured
420
-
436
+
421
437
  # Log startup header
422
438
  logger = get_logger("startup")
423
- logger.info("="*60)
439
+ logger.info("=" * 60)
424
440
  logger.info(f"Claude MPM Startup - {datetime.now().isoformat()}")
425
441
  logger.info(f"Log file: {log_file}")
426
- logger.info("="*60)
427
-
442
+ logger.info("=" * 60)
443
+
428
444
  # Log system information
429
445
  logger.info(f"Python: {sys.version}")
430
446
  logger.info(f"Platform: {sys.platform}")
431
447
  logger.info(f"CWD: {Path.cwd()}")
432
448
  logger.info(f"Project root: {project_root}")
433
-
449
+
434
450
  return log_file
435
451
 
436
452
 
437
- def cleanup_old_startup_logs(project_root: Optional[Path] = None,
438
- keep_days: int = 7,
439
- keep_min_count: int = 10) -> int:
453
+ def cleanup_old_startup_logs(
454
+ project_root: Optional[Path] = None, keep_count: Optional[int] = None
455
+ ) -> int:
440
456
  """
441
- Clean up old startup log files.
442
-
443
- WHY: Prevent unbounded growth of startup logs while keeping enough
444
- history for debugging patterns.
445
-
457
+ Clean up old startup log files using time-based retention.
458
+
459
+ WHY: This function now delegates to LogManager for unified log management
460
+ with time-based retention instead of count-based.
461
+
446
462
  DESIGN DECISIONS:
447
- - Keep logs from last N days
448
- - Always keep minimum count regardless of age
449
- - Return count of deleted files for reporting
450
-
463
+ - Delegates to LogManager for consistency
464
+ - Converts count to hours (48 hours default)
465
+ - Maintains backward compatibility
466
+
451
467
  Args:
452
468
  project_root: Root directory for the project
453
- keep_days: Number of days to keep logs
454
- keep_min_count: Minimum number of logs to keep regardless of age
455
-
469
+ keep_count: Ignored (kept for backward compatibility)
470
+
456
471
  Returns:
457
472
  Number of log files deleted
458
473
  """
459
- if project_root is None:
460
- project_root = Path.cwd()
461
-
462
- log_dir = project_root / ".claude-mpm" / "logs" / "startup"
463
-
464
- if not log_dir.exists():
465
- return 0
466
-
467
- # Get all startup log files
468
- log_files = sorted(log_dir.glob("startup-*.log"),
469
- key=lambda p: p.stat().st_mtime,
470
- reverse=True) # Newest first
471
-
472
- if len(log_files) <= keep_min_count:
473
- return 0 # Keep minimum count
474
-
475
- # Calculate cutoff time
476
- cutoff_time = datetime.now().timestamp() - (keep_days * 24 * 60 * 60)
477
-
478
- deleted_count = 0
479
- for log_file in log_files[keep_min_count:]: # Skip minimum count
480
- if log_file.stat().st_mtime < cutoff_time:
474
+ try:
475
+ from ..core.log_manager import get_log_manager
476
+
477
+ log_manager = get_log_manager()
478
+
479
+ # Use LogManager's time-based cleanup (48 hours default)
480
+ return log_manager.cleanup_old_startup_logs(project_root)
481
+ except ImportError:
482
+ # Fallback to old implementation if LogManager not available
483
+ # Get retention count from configuration if not specified
484
+ if keep_count is None:
485
+ from claude_mpm.core.config_constants import ConfigConstants
486
+
487
+ keep_count = (
488
+ ConfigConstants.get_logging_setting("startup_logs_retention_count")
489
+ or 10
490
+ )
491
+
492
+ if project_root is None:
493
+ project_root = Path.cwd()
494
+
495
+ log_dir = project_root / ".claude-mpm" / "logs" / "startup"
496
+
497
+ if not log_dir.exists():
498
+ return 0
499
+
500
+ # Get all startup log files
501
+ log_files = sorted(
502
+ log_dir.glob("startup-*.log"), key=lambda p: p.stat().st_mtime, reverse=True
503
+ ) # Newest first
504
+
505
+ if len(log_files) <= keep_count:
506
+ return 0 # Already within limit
507
+
508
+ # Delete older files beyond keep_count
509
+ deleted_count = 0
510
+ for log_file in log_files[
511
+ keep_count:
512
+ ]: # Keep only the most recent keep_count files
481
513
  try:
482
514
  log_file.unlink()
483
515
  deleted_count += 1
484
516
  except Exception:
485
517
  pass # Ignore deletion errors
486
-
487
- return deleted_count
518
+
519
+ return deleted_count
488
520
 
489
521
 
490
522
  def get_latest_startup_log(project_root: Optional[Path] = None) -> Optional[Path]:
491
523
  """
492
524
  Get the path to the most recent startup log file.
493
-
525
+
494
526
  Args:
495
527
  project_root: Root directory for the project
496
-
528
+
497
529
  Returns:
498
530
  Path to latest log file or None if no logs exist
499
531
  """
500
532
  if project_root is None:
501
533
  project_root = Path.cwd()
502
-
534
+
503
535
  log_dir = project_root / ".claude-mpm" / "logs" / "startup"
504
-
536
+
505
537
  if not log_dir.exists():
506
538
  return None
507
-
508
- log_files = sorted(log_dir.glob("startup-*.log"),
509
- key=lambda p: p.stat().st_mtime,
510
- reverse=True)
511
-
539
+
540
+ log_files = sorted(
541
+ log_dir.glob("startup-*.log"), key=lambda p: p.stat().st_mtime, reverse=True
542
+ )
543
+
512
544
  return log_files[0] if log_files else None
513
545
 
514
546
 
515
547
  def log_startup_status(monitor_mode: bool = False, websocket_port: int = 8765) -> None:
516
548
  """
517
549
  Log comprehensive startup status for MCP server and monitor setup.
518
-
550
+
519
551
  This function should be called during application startup to provide
520
552
  detailed information about MCP and monitor setup status.
521
-
553
+
522
554
  Args:
523
555
  monitor_mode: Whether monitor mode is enabled
524
556
  websocket_port: WebSocket port for monitoring
525
557
  """
526
558
  try:
527
559
  status_logger = StartupStatusLogger("cli")
528
-
560
+
529
561
  # Log MCP server status
530
562
  status_logger.log_mcp_server_status()
531
-
563
+
532
564
  # Log monitor setup status
533
565
  status_logger.log_monitor_setup_status(monitor_mode, websocket_port)
534
-
566
+
535
567
  except Exception as e:
536
568
  # Don't let logging failures prevent startup
537
569
  logger = get_logger("cli")
538
- logger.debug(f"Startup status logging failed: {e}")
570
+ logger.debug(f"Startup status logging failed: {e}")