claude-mpm 4.1.0__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 (358) 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 +133 -58
  21. claude_mpm/agents/templates/web_ui.json +3 -3
  22. claude_mpm/cli/__init__.py +51 -46
  23. claude_mpm/cli/__main__.py +1 -1
  24. claude_mpm/cli/commands/__init__.py +10 -12
  25. claude_mpm/cli/commands/agent_manager.py +186 -181
  26. claude_mpm/cli/commands/agents.py +271 -268
  27. claude_mpm/cli/commands/aggregate.py +30 -29
  28. claude_mpm/cli/commands/cleanup.py +50 -44
  29. claude_mpm/cli/commands/cleanup_orphaned_agents.py +25 -25
  30. claude_mpm/cli/commands/config.py +162 -127
  31. claude_mpm/cli/commands/doctor.py +52 -62
  32. claude_mpm/cli/commands/info.py +37 -25
  33. claude_mpm/cli/commands/mcp.py +3 -7
  34. claude_mpm/cli/commands/mcp_command_router.py +14 -18
  35. claude_mpm/cli/commands/mcp_install_commands.py +28 -23
  36. claude_mpm/cli/commands/mcp_pipx_config.py +58 -49
  37. claude_mpm/cli/commands/mcp_server_commands.py +23 -17
  38. claude_mpm/cli/commands/memory.py +192 -141
  39. claude_mpm/cli/commands/monitor.py +117 -88
  40. claude_mpm/cli/commands/run.py +120 -84
  41. claude_mpm/cli/commands/run_config_checker.py +4 -5
  42. claude_mpm/cli/commands/socketio_monitor.py +17 -19
  43. claude_mpm/cli/commands/tickets.py +92 -92
  44. claude_mpm/cli/parser.py +1 -5
  45. claude_mpm/cli/parsers/__init__.py +1 -1
  46. claude_mpm/cli/parsers/agent_manager_parser.py +50 -98
  47. claude_mpm/cli/parsers/agents_parser.py +2 -3
  48. claude_mpm/cli/parsers/base_parser.py +7 -5
  49. claude_mpm/cli/parsers/mcp_parser.py +4 -2
  50. claude_mpm/cli/parsers/monitor_parser.py +26 -18
  51. claude_mpm/cli/shared/__init__.py +10 -10
  52. claude_mpm/cli/shared/argument_patterns.py +57 -71
  53. claude_mpm/cli/shared/base_command.py +61 -53
  54. claude_mpm/cli/shared/error_handling.py +62 -58
  55. claude_mpm/cli/shared/output_formatters.py +78 -77
  56. claude_mpm/cli/startup_logging.py +204 -172
  57. claude_mpm/cli/utils.py +10 -11
  58. claude_mpm/cli_module/__init__.py +1 -1
  59. claude_mpm/cli_module/args.py +1 -1
  60. claude_mpm/cli_module/migration_example.py +5 -5
  61. claude_mpm/config/__init__.py +9 -9
  62. claude_mpm/config/agent_config.py +15 -14
  63. claude_mpm/config/experimental_features.py +4 -4
  64. claude_mpm/config/paths.py +0 -1
  65. claude_mpm/config/socketio_config.py +5 -6
  66. claude_mpm/constants.py +1 -2
  67. claude_mpm/core/__init__.py +8 -8
  68. claude_mpm/core/agent_name_normalizer.py +1 -1
  69. claude_mpm/core/agent_registry.py +20 -23
  70. claude_mpm/core/agent_session_manager.py +3 -3
  71. claude_mpm/core/base_service.py +7 -15
  72. claude_mpm/core/cache.py +4 -6
  73. claude_mpm/core/claude_runner.py +85 -113
  74. claude_mpm/core/config.py +43 -28
  75. claude_mpm/core/config_aliases.py +0 -9
  76. claude_mpm/core/config_constants.py +52 -30
  77. claude_mpm/core/constants.py +0 -1
  78. claude_mpm/core/container.py +18 -27
  79. claude_mpm/core/exceptions.py +2 -2
  80. claude_mpm/core/factories.py +10 -12
  81. claude_mpm/core/framework_loader.py +581 -280
  82. claude_mpm/core/hook_manager.py +26 -22
  83. claude_mpm/core/hook_performance_config.py +58 -47
  84. claude_mpm/core/injectable_service.py +1 -1
  85. claude_mpm/core/interactive_session.py +61 -152
  86. claude_mpm/core/interfaces.py +1 -100
  87. claude_mpm/core/lazy.py +5 -5
  88. claude_mpm/core/log_manager.py +587 -0
  89. claude_mpm/core/logger.py +125 -8
  90. claude_mpm/core/logging_config.py +15 -15
  91. claude_mpm/core/minimal_framework_loader.py +5 -8
  92. claude_mpm/core/oneshot_session.py +15 -33
  93. claude_mpm/core/optimized_agent_loader.py +4 -6
  94. claude_mpm/core/optimized_startup.py +2 -1
  95. claude_mpm/core/output_style_manager.py +147 -106
  96. claude_mpm/core/pm_hook_interceptor.py +0 -1
  97. claude_mpm/core/service_registry.py +11 -8
  98. claude_mpm/core/session_manager.py +1 -2
  99. claude_mpm/core/shared/__init__.py +1 -1
  100. claude_mpm/core/shared/config_loader.py +101 -97
  101. claude_mpm/core/shared/path_resolver.py +72 -68
  102. claude_mpm/core/shared/singleton_manager.py +56 -50
  103. claude_mpm/core/socketio_pool.py +26 -6
  104. claude_mpm/core/tool_access_control.py +4 -5
  105. claude_mpm/core/typing_utils.py +50 -59
  106. claude_mpm/core/unified_agent_registry.py +14 -19
  107. claude_mpm/core/unified_config.py +4 -6
  108. claude_mpm/core/unified_paths.py +197 -109
  109. claude_mpm/dashboard/open_dashboard.py +2 -4
  110. claude_mpm/experimental/cli_enhancements.py +51 -36
  111. claude_mpm/generators/agent_profile_generator.py +2 -4
  112. claude_mpm/hooks/base_hook.py +1 -2
  113. claude_mpm/hooks/claude_hooks/connection_pool.py +72 -26
  114. claude_mpm/hooks/claude_hooks/event_handlers.py +93 -38
  115. claude_mpm/hooks/claude_hooks/hook_handler.py +130 -76
  116. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
  117. claude_mpm/hooks/claude_hooks/memory_integration.py +2 -4
  118. claude_mpm/hooks/claude_hooks/response_tracking.py +15 -11
  119. claude_mpm/hooks/claude_hooks/tool_analysis.py +12 -18
  120. claude_mpm/hooks/memory_integration_hook.py +5 -5
  121. claude_mpm/hooks/tool_call_interceptor.py +1 -1
  122. claude_mpm/hooks/validation_hooks.py +4 -4
  123. claude_mpm/init.py +4 -9
  124. claude_mpm/models/__init__.py +2 -2
  125. claude_mpm/models/agent_session.py +11 -14
  126. claude_mpm/scripts/mcp_server.py +20 -11
  127. claude_mpm/scripts/mcp_wrapper.py +5 -5
  128. claude_mpm/scripts/mpm_doctor.py +321 -0
  129. claude_mpm/scripts/socketio_daemon.py +28 -25
  130. claude_mpm/scripts/socketio_daemon_hardened.py +298 -258
  131. claude_mpm/scripts/socketio_server_manager.py +116 -95
  132. claude_mpm/services/__init__.py +49 -49
  133. claude_mpm/services/agent_capabilities_service.py +12 -18
  134. claude_mpm/services/agents/__init__.py +22 -22
  135. claude_mpm/services/agents/agent_builder.py +140 -119
  136. claude_mpm/services/agents/deployment/__init__.py +3 -3
  137. claude_mpm/services/agents/deployment/agent_config_provider.py +9 -9
  138. claude_mpm/services/agents/deployment/agent_configuration_manager.py +19 -20
  139. claude_mpm/services/agents/deployment/agent_definition_factory.py +1 -5
  140. claude_mpm/services/agents/deployment/agent_deployment.py +136 -106
  141. claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -8
  142. claude_mpm/services/agents/deployment/agent_environment_manager.py +2 -7
  143. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +6 -10
  144. claude_mpm/services/agents/deployment/agent_format_converter.py +11 -15
  145. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +2 -3
  146. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -5
  147. claude_mpm/services/agents/deployment/agent_metrics_collector.py +13 -19
  148. claude_mpm/services/agents/deployment/agent_restore_handler.py +0 -1
  149. claude_mpm/services/agents/deployment/agent_template_builder.py +26 -35
  150. claude_mpm/services/agents/deployment/agent_validator.py +0 -1
  151. claude_mpm/services/agents/deployment/agent_version_manager.py +7 -9
  152. claude_mpm/services/agents/deployment/agent_versioning.py +3 -3
  153. claude_mpm/services/agents/deployment/agents_directory_resolver.py +6 -7
  154. claude_mpm/services/agents/deployment/async_agent_deployment.py +51 -38
  155. claude_mpm/services/agents/deployment/config/__init__.py +1 -1
  156. claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
  157. claude_mpm/services/agents/deployment/deployment_type_detector.py +1 -1
  158. claude_mpm/services/agents/deployment/deployment_wrapper.py +18 -18
  159. claude_mpm/services/agents/deployment/facade/__init__.py +1 -1
  160. claude_mpm/services/agents/deployment/facade/deployment_executor.py +0 -3
  161. claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -4
  162. claude_mpm/services/agents/deployment/interface_adapter.py +5 -7
  163. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +345 -276
  164. claude_mpm/services/agents/deployment/pipeline/__init__.py +2 -2
  165. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +1 -1
  166. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +6 -4
  167. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +3 -3
  168. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +2 -2
  169. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +14 -13
  170. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +0 -1
  171. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +1 -1
  172. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +8 -9
  173. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +1 -1
  174. claude_mpm/services/agents/deployment/processors/__init__.py +1 -1
  175. claude_mpm/services/agents/deployment/processors/agent_processor.py +20 -16
  176. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +5 -12
  177. claude_mpm/services/agents/deployment/results/__init__.py +1 -1
  178. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +1 -1
  179. claude_mpm/services/agents/deployment/strategies/__init__.py +2 -2
  180. claude_mpm/services/agents/deployment/strategies/base_strategy.py +1 -7
  181. claude_mpm/services/agents/deployment/strategies/project_strategy.py +1 -4
  182. claude_mpm/services/agents/deployment/strategies/system_strategy.py +2 -3
  183. claude_mpm/services/agents/deployment/strategies/user_strategy.py +3 -7
  184. claude_mpm/services/agents/deployment/validation/__init__.py +1 -1
  185. claude_mpm/services/agents/deployment/validation/agent_validator.py +1 -1
  186. claude_mpm/services/agents/deployment/validation/template_validator.py +2 -2
  187. claude_mpm/services/agents/deployment/validation/validation_result.py +2 -6
  188. claude_mpm/services/agents/loading/__init__.py +1 -1
  189. claude_mpm/services/agents/loading/agent_profile_loader.py +6 -12
  190. claude_mpm/services/agents/loading/base_agent_manager.py +5 -5
  191. claude_mpm/services/agents/loading/framework_agent_loader.py +2 -4
  192. claude_mpm/services/agents/management/__init__.py +1 -1
  193. claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -3
  194. claude_mpm/services/agents/management/agent_management_service.py +5 -9
  195. claude_mpm/services/agents/memory/__init__.py +4 -4
  196. claude_mpm/services/agents/memory/agent_memory_manager.py +280 -160
  197. claude_mpm/services/agents/memory/agent_persistence_service.py +0 -2
  198. claude_mpm/services/agents/memory/content_manager.py +44 -38
  199. claude_mpm/services/agents/memory/template_generator.py +4 -6
  200. claude_mpm/services/agents/registry/__init__.py +10 -6
  201. claude_mpm/services/agents/registry/deployed_agent_discovery.py +30 -27
  202. claude_mpm/services/agents/registry/modification_tracker.py +3 -6
  203. claude_mpm/services/async_session_logger.py +1 -2
  204. claude_mpm/services/claude_session_logger.py +1 -2
  205. claude_mpm/services/command_deployment_service.py +173 -0
  206. claude_mpm/services/command_handler_service.py +20 -22
  207. claude_mpm/services/core/__init__.py +25 -25
  208. claude_mpm/services/core/base.py +0 -5
  209. claude_mpm/services/core/interfaces/__init__.py +32 -32
  210. claude_mpm/services/core/interfaces/agent.py +0 -21
  211. claude_mpm/services/core/interfaces/communication.py +0 -27
  212. claude_mpm/services/core/interfaces/infrastructure.py +0 -56
  213. claude_mpm/services/core/interfaces/service.py +0 -29
  214. claude_mpm/services/diagnostics/__init__.py +1 -1
  215. claude_mpm/services/diagnostics/checks/__init__.py +6 -6
  216. claude_mpm/services/diagnostics/checks/agent_check.py +89 -80
  217. claude_mpm/services/diagnostics/checks/base_check.py +12 -16
  218. claude_mpm/services/diagnostics/checks/claude_desktop_check.py +84 -81
  219. claude_mpm/services/diagnostics/checks/common_issues_check.py +99 -91
  220. claude_mpm/services/diagnostics/checks/configuration_check.py +82 -77
  221. claude_mpm/services/diagnostics/checks/filesystem_check.py +67 -68
  222. claude_mpm/services/diagnostics/checks/installation_check.py +254 -94
  223. claude_mpm/services/diagnostics/checks/mcp_check.py +90 -88
  224. claude_mpm/services/diagnostics/checks/monitor_check.py +75 -76
  225. claude_mpm/services/diagnostics/checks/startup_log_check.py +67 -73
  226. claude_mpm/services/diagnostics/diagnostic_runner.py +67 -59
  227. claude_mpm/services/diagnostics/doctor_reporter.py +107 -70
  228. claude_mpm/services/diagnostics/models.py +21 -19
  229. claude_mpm/services/event_aggregator.py +10 -17
  230. claude_mpm/services/event_bus/__init__.py +1 -1
  231. claude_mpm/services/event_bus/config.py +54 -35
  232. claude_mpm/services/event_bus/event_bus.py +76 -71
  233. claude_mpm/services/event_bus/relay.py +74 -64
  234. claude_mpm/services/events/__init__.py +11 -11
  235. claude_mpm/services/events/consumers/__init__.py +3 -3
  236. claude_mpm/services/events/consumers/dead_letter.py +71 -63
  237. claude_mpm/services/events/consumers/logging.py +39 -37
  238. claude_mpm/services/events/consumers/metrics.py +56 -57
  239. claude_mpm/services/events/consumers/socketio.py +82 -81
  240. claude_mpm/services/events/core.py +110 -99
  241. claude_mpm/services/events/interfaces.py +56 -72
  242. claude_mpm/services/events/producers/__init__.py +1 -1
  243. claude_mpm/services/events/producers/hook.py +38 -38
  244. claude_mpm/services/events/producers/system.py +46 -44
  245. claude_mpm/services/exceptions.py +81 -80
  246. claude_mpm/services/framework_claude_md_generator/__init__.py +2 -4
  247. claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -5
  248. claude_mpm/services/framework_claude_md_generator/content_validator.py +1 -1
  249. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +4 -4
  250. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -1
  251. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -2
  252. claude_mpm/services/framework_claude_md_generator/version_manager.py +4 -5
  253. claude_mpm/services/hook_service.py +6 -9
  254. claude_mpm/services/infrastructure/__init__.py +1 -1
  255. claude_mpm/services/infrastructure/context_preservation.py +8 -12
  256. claude_mpm/services/infrastructure/monitoring.py +21 -23
  257. claude_mpm/services/mcp_gateway/__init__.py +37 -37
  258. claude_mpm/services/mcp_gateway/auto_configure.py +95 -103
  259. claude_mpm/services/mcp_gateway/config/__init__.py +1 -1
  260. claude_mpm/services/mcp_gateway/config/config_loader.py +23 -25
  261. claude_mpm/services/mcp_gateway/config/config_schema.py +5 -5
  262. claude_mpm/services/mcp_gateway/config/configuration.py +9 -6
  263. claude_mpm/services/mcp_gateway/core/__init__.py +10 -10
  264. claude_mpm/services/mcp_gateway/core/base.py +0 -3
  265. claude_mpm/services/mcp_gateway/core/interfaces.py +1 -38
  266. claude_mpm/services/mcp_gateway/core/process_pool.py +99 -93
  267. claude_mpm/services/mcp_gateway/core/singleton_manager.py +65 -62
  268. claude_mpm/services/mcp_gateway/core/startup_verification.py +75 -74
  269. claude_mpm/services/mcp_gateway/main.py +2 -1
  270. claude_mpm/services/mcp_gateway/registry/service_registry.py +5 -8
  271. claude_mpm/services/mcp_gateway/registry/tool_registry.py +1 -1
  272. claude_mpm/services/mcp_gateway/server/__init__.py +1 -1
  273. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +12 -19
  274. claude_mpm/services/mcp_gateway/server/stdio_handler.py +4 -3
  275. claude_mpm/services/mcp_gateway/server/stdio_server.py +79 -71
  276. claude_mpm/services/mcp_gateway/tools/__init__.py +2 -2
  277. claude_mpm/services/mcp_gateway/tools/base_adapter.py +5 -6
  278. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +13 -22
  279. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +79 -78
  280. claude_mpm/services/mcp_gateway/tools/hello_world.py +12 -14
  281. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +42 -49
  282. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +51 -55
  283. claude_mpm/services/memory/__init__.py +3 -3
  284. claude_mpm/services/memory/builder.py +3 -6
  285. claude_mpm/services/memory/cache/__init__.py +1 -1
  286. claude_mpm/services/memory/cache/shared_prompt_cache.py +3 -5
  287. claude_mpm/services/memory/cache/simple_cache.py +1 -1
  288. claude_mpm/services/memory/indexed_memory.py +5 -7
  289. claude_mpm/services/memory/optimizer.py +7 -10
  290. claude_mpm/services/memory/router.py +8 -9
  291. claude_mpm/services/memory_hook_service.py +48 -34
  292. claude_mpm/services/monitor_build_service.py +77 -73
  293. claude_mpm/services/port_manager.py +130 -108
  294. claude_mpm/services/project/analyzer.py +12 -10
  295. claude_mpm/services/project/registry.py +11 -11
  296. claude_mpm/services/recovery_manager.py +10 -19
  297. claude_mpm/services/response_tracker.py +0 -1
  298. claude_mpm/services/runner_configuration_service.py +19 -20
  299. claude_mpm/services/session_management_service.py +7 -11
  300. claude_mpm/services/shared/__init__.py +1 -1
  301. claude_mpm/services/shared/async_service_base.py +58 -50
  302. claude_mpm/services/shared/config_service_base.py +73 -67
  303. claude_mpm/services/shared/lifecycle_service_base.py +82 -78
  304. claude_mpm/services/shared/manager_base.py +94 -82
  305. claude_mpm/services/shared/service_factory.py +96 -98
  306. claude_mpm/services/socketio/__init__.py +3 -3
  307. claude_mpm/services/socketio/client_proxy.py +5 -5
  308. claude_mpm/services/socketio/event_normalizer.py +199 -181
  309. claude_mpm/services/socketio/handlers/__init__.py +3 -3
  310. claude_mpm/services/socketio/handlers/base.py +5 -4
  311. claude_mpm/services/socketio/handlers/connection.py +163 -136
  312. claude_mpm/services/socketio/handlers/file.py +13 -14
  313. claude_mpm/services/socketio/handlers/git.py +12 -7
  314. claude_mpm/services/socketio/handlers/hook.py +49 -44
  315. claude_mpm/services/socketio/handlers/memory.py +0 -1
  316. claude_mpm/services/socketio/handlers/project.py +0 -1
  317. claude_mpm/services/socketio/handlers/registry.py +37 -19
  318. claude_mpm/services/socketio/migration_utils.py +98 -84
  319. claude_mpm/services/socketio/server/__init__.py +1 -1
  320. claude_mpm/services/socketio/server/broadcaster.py +81 -87
  321. claude_mpm/services/socketio/server/core.py +65 -54
  322. claude_mpm/services/socketio/server/eventbus_integration.py +95 -56
  323. claude_mpm/services/socketio/server/main.py +64 -38
  324. claude_mpm/services/socketio_client_manager.py +10 -12
  325. claude_mpm/services/subprocess_launcher_service.py +4 -7
  326. claude_mpm/services/system_instructions_service.py +13 -14
  327. claude_mpm/services/ticket_manager.py +2 -2
  328. claude_mpm/services/utility_service.py +5 -13
  329. claude_mpm/services/version_control/__init__.py +16 -16
  330. claude_mpm/services/version_control/branch_strategy.py +5 -8
  331. claude_mpm/services/version_control/conflict_resolution.py +9 -23
  332. claude_mpm/services/version_control/git_operations.py +5 -7
  333. claude_mpm/services/version_control/semantic_versioning.py +16 -17
  334. claude_mpm/services/version_control/version_parser.py +13 -18
  335. claude_mpm/services/version_service.py +10 -11
  336. claude_mpm/storage/__init__.py +1 -1
  337. claude_mpm/storage/state_storage.py +22 -28
  338. claude_mpm/utils/__init__.py +6 -6
  339. claude_mpm/utils/agent_dependency_loader.py +47 -33
  340. claude_mpm/utils/config_manager.py +11 -14
  341. claude_mpm/utils/dependency_cache.py +1 -1
  342. claude_mpm/utils/dependency_manager.py +13 -17
  343. claude_mpm/utils/dependency_strategies.py +8 -10
  344. claude_mpm/utils/environment_context.py +3 -9
  345. claude_mpm/utils/error_handler.py +3 -13
  346. claude_mpm/utils/file_utils.py +1 -1
  347. claude_mpm/utils/path_operations.py +8 -12
  348. claude_mpm/utils/robust_installer.py +110 -33
  349. claude_mpm/utils/subprocess_utils.py +5 -6
  350. claude_mpm/validation/agent_validator.py +3 -6
  351. claude_mpm/validation/frontmatter_validator.py +1 -1
  352. {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/METADATA +1 -1
  353. claude_mpm-4.1.2.dist-info/RECORD +498 -0
  354. claude_mpm-4.1.0.dist-info/RECORD +0 -494
  355. {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/WHEEL +0 -0
  356. {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/entry_points.txt +0 -0
  357. {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/licenses/LICENSE +0 -0
  358. {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/top_level.txt +0 -0
@@ -18,7 +18,7 @@ from ..interfaces import ConsumerConfig, ConsumerPriority, IEventConsumer
18
18
  class MetricsConsumer(IEventConsumer):
19
19
  """
20
20
  Collects metrics and statistics from events.
21
-
21
+
22
22
  Features:
23
23
  - Event counting by topic and type
24
24
  - Rate calculation (events per second)
@@ -26,7 +26,7 @@ class MetricsConsumer(IEventConsumer):
26
26
  - Top event analysis
27
27
  - Time-windowed statistics
28
28
  """
29
-
29
+
30
30
  def __init__(
31
31
  self,
32
32
  window_size: int = 300, # 5 minutes
@@ -35,36 +35,36 @@ class MetricsConsumer(IEventConsumer):
35
35
  ):
36
36
  """
37
37
  Initialize metrics consumer.
38
-
38
+
39
39
  Args:
40
40
  window_size: Time window for statistics (seconds)
41
41
  top_n: Number of top events to track
42
42
  report_interval: How often to report metrics (seconds)
43
43
  """
44
44
  self.logger = get_logger("MetricsConsumer")
45
-
45
+
46
46
  # Configuration
47
47
  self.window_size = window_size
48
48
  self.top_n = top_n
49
49
  self.report_interval = report_interval
50
-
50
+
51
51
  # State
52
52
  self._initialized = False
53
53
  self._last_report_time = time.time()
54
-
54
+
55
55
  # Metrics storage
56
56
  self._event_counts: Dict[str, int] = defaultdict(int)
57
57
  self._topic_counts: Dict[str, int] = defaultdict(int)
58
58
  self._type_counts: Dict[str, int] = defaultdict(int)
59
59
  self._source_counts: Dict[str, int] = defaultdict(int)
60
-
60
+
61
61
  # Time-windowed metrics
62
62
  self._recent_events: Deque[tuple] = deque() # (timestamp, topic, type)
63
63
  self._latencies: Deque[float] = deque(maxlen=1000)
64
-
64
+
65
65
  # Error tracking
66
66
  self._error_counts: Dict[str, int] = defaultdict(int)
67
-
67
+
68
68
  # Performance metrics
69
69
  self._metrics = {
70
70
  "total_events": 0,
@@ -74,64 +74,64 @@ class MetricsConsumer(IEventConsumer):
74
74
  "unique_topics": 0,
75
75
  "unique_types": 0,
76
76
  }
77
-
77
+
78
78
  # Consumer configuration
79
79
  self._config = ConsumerConfig(
80
80
  name="MetricsConsumer",
81
81
  topics=["**"], # Monitor all events
82
82
  priority=ConsumerPriority.DEFERRED, # Process after other consumers
83
83
  )
84
-
84
+
85
85
  async def initialize(self) -> bool:
86
86
  """Initialize the metrics consumer."""
87
87
  self._initialized = True
88
88
  self.logger.info("Metrics consumer initialized")
89
89
  return True
90
-
90
+
91
91
  async def consume(self, event: Event) -> bool:
92
92
  """Process a single event for metrics."""
93
93
  if not self._initialized:
94
94
  return False
95
-
95
+
96
96
  try:
97
97
  current_time = time.time()
98
-
98
+
99
99
  # Update counts
100
100
  self._event_counts[f"{event.topic}:{event.type}"] += 1
101
101
  self._topic_counts[event.topic] += 1
102
102
  self._type_counts[event.type] += 1
103
103
  self._source_counts[event.source] += 1
104
104
  self._metrics["total_events"] += 1
105
-
105
+
106
106
  # Track errors
107
107
  if event.metadata and event.metadata.consumers_failed:
108
108
  for consumer in event.metadata.consumers_failed:
109
109
  self._error_counts[consumer] += 1
110
-
110
+
111
111
  # Add to recent events
112
112
  self._recent_events.append((current_time, event.topic, event.type))
113
-
113
+
114
114
  # Calculate latency if timestamp available
115
115
  if event.timestamp:
116
116
  latency = (current_time - event.timestamp.timestamp()) * 1000
117
117
  self._latencies.append(latency)
118
-
118
+
119
119
  # Clean old events from window
120
120
  cutoff_time = current_time - self.window_size
121
121
  while self._recent_events and self._recent_events[0][0] < cutoff_time:
122
122
  self._recent_events.popleft()
123
-
123
+
124
124
  # Report metrics periodically
125
125
  if current_time - self._last_report_time >= self.report_interval:
126
126
  await self._report_metrics()
127
127
  self._last_report_time = current_time
128
-
128
+
129
129
  return True
130
-
130
+
131
131
  except Exception as e:
132
132
  self.logger.error(f"Error processing event for metrics: {e}")
133
133
  return False
134
-
134
+
135
135
  async def consume_batch(self, events: List[Event]) -> int:
136
136
  """Process multiple events."""
137
137
  successful = 0
@@ -139,45 +139,41 @@ class MetricsConsumer(IEventConsumer):
139
139
  if await self.consume(event):
140
140
  successful += 1
141
141
  return successful
142
-
142
+
143
143
  async def shutdown(self) -> None:
144
144
  """Shutdown the consumer."""
145
145
  # Report final metrics
146
146
  await self._report_metrics()
147
-
147
+
148
148
  self.logger.info(
149
149
  f"Metrics consumer shutdown - processed {self._metrics['total_events']} events"
150
150
  )
151
151
  self._initialized = False
152
-
152
+
153
153
  @property
154
154
  def config(self) -> ConsumerConfig:
155
155
  """Get consumer configuration."""
156
156
  return self._config
157
-
157
+
158
158
  @property
159
159
  def is_healthy(self) -> bool:
160
160
  """Check if consumer is healthy."""
161
161
  return self._initialized
162
-
162
+
163
163
  def get_metrics(self) -> Dict[str, Any]:
164
164
  """Get consumer metrics."""
165
165
  # Calculate current metrics
166
166
  self._calculate_metrics()
167
-
167
+
168
168
  # Get top events
169
169
  top_events = sorted(
170
- self._event_counts.items(),
171
- key=lambda x: x[1],
172
- reverse=True
173
- )[:self.top_n]
174
-
170
+ self._event_counts.items(), key=lambda x: x[1], reverse=True
171
+ )[: self.top_n]
172
+
175
173
  top_topics = sorted(
176
- self._topic_counts.items(),
177
- key=lambda x: x[1],
178
- reverse=True
179
- )[:self.top_n]
180
-
174
+ self._topic_counts.items(), key=lambda x: x[1], reverse=True
175
+ )[: self.top_n]
176
+
181
177
  return {
182
178
  **self._metrics,
183
179
  "top_events": dict(top_events),
@@ -185,58 +181,61 @@ class MetricsConsumer(IEventConsumer):
185
181
  "error_counts": dict(self._error_counts),
186
182
  "window_size_seconds": self.window_size,
187
183
  }
188
-
184
+
189
185
  def _calculate_metrics(self) -> None:
190
186
  """Calculate current metrics."""
191
187
  # Events per second
192
188
  if self._recent_events:
193
189
  time_span = time.time() - self._recent_events[0][0]
194
190
  if time_span > 0:
195
- self._metrics["events_per_second"] = len(self._recent_events) / time_span
196
-
191
+ self._metrics["events_per_second"] = (
192
+ len(self._recent_events) / time_span
193
+ )
194
+
197
195
  # Average latency
198
196
  if self._latencies:
199
- self._metrics["average_latency_ms"] = sum(self._latencies) / len(self._latencies)
200
-
197
+ self._metrics["average_latency_ms"] = sum(self._latencies) / len(
198
+ self._latencies
199
+ )
200
+
201
201
  # Unique counts
202
202
  self._metrics["unique_topics"] = len(self._topic_counts)
203
203
  self._metrics["unique_types"] = len(self._type_counts)
204
-
204
+
205
205
  # Peak rate
206
- if self._metrics["events_per_second"] > self._metrics["peak_rate"]:
207
- self._metrics["peak_rate"] = self._metrics["events_per_second"]
208
-
206
+ self._metrics["peak_rate"] = max(
207
+ self._metrics["peak_rate"], self._metrics["events_per_second"]
208
+ )
209
+
209
210
  async def _report_metrics(self) -> None:
210
211
  """Report current metrics to log."""
211
212
  self._calculate_metrics()
212
-
213
+
213
214
  # Build report
214
215
  report = [
215
- f"=== Event Metrics Report ===",
216
+ "=== Event Metrics Report ===",
216
217
  f"Total Events: {self._metrics['total_events']}",
217
218
  f"Rate: {self._metrics['events_per_second']:.2f} events/sec",
218
219
  f"Avg Latency: {self._metrics['average_latency_ms']:.1f}ms",
219
220
  f"Unique Topics: {self._metrics['unique_topics']}",
220
221
  f"Unique Types: {self._metrics['unique_types']}",
221
222
  ]
222
-
223
+
223
224
  # Add top events
224
225
  top_events = sorted(
225
- self._event_counts.items(),
226
- key=lambda x: x[1],
227
- reverse=True
226
+ self._event_counts.items(), key=lambda x: x[1], reverse=True
228
227
  )[:5]
229
-
228
+
230
229
  if top_events:
231
230
  report.append("\nTop Events:")
232
231
  for event_key, count in top_events:
233
232
  report.append(f" {event_key}: {count}")
234
-
233
+
235
234
  # Add error summary
236
235
  if self._error_counts:
237
236
  report.append("\nErrors by Consumer:")
238
237
  for consumer, count in self._error_counts.items():
239
238
  report.append(f" {consumer}: {count}")
240
-
239
+
241
240
  # Log report
242
- self.logger.info("\n".join(report))
241
+ self.logger.info("\n".join(report))
@@ -8,6 +8,7 @@ the rest of the system from the transport layer.
8
8
  """
9
9
 
10
10
  import asyncio
11
+ import contextlib
11
12
  import time
12
13
  from typing import Any, Dict, List, Optional
13
14
 
@@ -20,7 +21,7 @@ from ..interfaces import ConsumerConfig, ConsumerPriority, IEventConsumer
20
21
  class SocketIOConsumer(IEventConsumer):
21
22
  """
22
23
  Consumes events and emits them via Socket.IO.
23
-
24
+
24
25
  Features:
25
26
  - Single Socket.IO connection management
26
27
  - Automatic reconnection with backoff
@@ -28,7 +29,7 @@ class SocketIOConsumer(IEventConsumer):
28
29
  - Connection health monitoring
29
30
  - Graceful degradation when Socket.IO unavailable
30
31
  """
31
-
32
+
32
33
  def __init__(
33
34
  self,
34
35
  socketio_server=None,
@@ -40,7 +41,7 @@ class SocketIOConsumer(IEventConsumer):
40
41
  ):
41
42
  """
42
43
  Initialize Socket.IO consumer.
43
-
44
+
44
45
  Args:
45
46
  socketio_server: Socket.IO server instance (optional)
46
47
  port_range: Port range to try for connection
@@ -50,25 +51,25 @@ class SocketIOConsumer(IEventConsumer):
50
51
  batch_timeout: Max time to wait for batch
51
52
  """
52
53
  self.logger = get_logger("SocketIOConsumer")
53
-
54
+
54
55
  # Socket.IO configuration
55
56
  self.socketio_server = socketio_server
56
57
  self.port_range = port_range
57
58
  self.reconnect_delay = reconnect_delay
58
59
  self.max_reconnect_delay = max_reconnect_delay
59
60
  self.current_reconnect_delay = reconnect_delay
60
-
61
+
61
62
  # Batching configuration
62
63
  self.batch_size = batch_size
63
64
  self.batch_timeout = batch_timeout
64
-
65
+
65
66
  # State
66
67
  self._initialized = False
67
68
  self._connected = False
68
69
  self._reconnect_task: Optional[asyncio.Task] = None
69
70
  self._event_batch: List[Event] = []
70
71
  self._batch_timer: Optional[asyncio.Task] = None
71
-
72
+
72
73
  # Metrics
73
74
  self._metrics = {
74
75
  "events_received": 0,
@@ -79,7 +80,7 @@ class SocketIOConsumer(IEventConsumer):
79
80
  "last_emit_time": None,
80
81
  "average_emit_time_ms": 0,
81
82
  }
82
-
83
+
83
84
  # Consumer configuration
84
85
  self._config = ConsumerConfig(
85
86
  name="SocketIOConsumer",
@@ -90,114 +91,113 @@ class SocketIOConsumer(IEventConsumer):
90
91
  max_retries=3,
91
92
  retry_backoff=2.0,
92
93
  )
93
-
94
+
94
95
  async def initialize(self) -> bool:
95
96
  """Initialize the Socket.IO consumer."""
96
97
  if self._initialized:
97
98
  return True
98
-
99
+
99
100
  self.logger.info("Initializing Socket.IO consumer")
100
-
101
+
101
102
  # Try to import socketio if not provided
102
103
  if self.socketio_server is None:
103
104
  try:
104
105
  # Try to get existing server instance
105
106
  from claude_mpm.services.socketio.server import get_socketio_server
107
+
106
108
  self.socketio_server = get_socketio_server()
107
-
109
+
108
110
  if self.socketio_server:
109
111
  self._connected = True
110
112
  self.logger.info("Connected to existing Socket.IO server")
111
-
113
+
112
114
  except ImportError:
113
115
  self.logger.warning("Socket.IO server not available")
114
116
  # Continue without Socket.IO - events will be dropped
115
-
117
+
116
118
  self._initialized = True
117
-
119
+
118
120
  # Start reconnection task if not connected
119
121
  if not self._connected and self.socketio_server:
120
122
  self._reconnect_task = asyncio.create_task(self._reconnect_loop())
121
-
123
+
122
124
  return True
123
-
125
+
124
126
  async def consume(self, event: Event) -> bool:
125
127
  """
126
128
  Process a single event.
127
-
129
+
128
130
  Events are batched for efficiency and emitted via Socket.IO.
129
131
  """
130
132
  if not self._initialized:
131
133
  self.logger.warning("Consumer not initialized")
132
134
  return False
133
-
135
+
134
136
  self._metrics["events_received"] += 1
135
-
137
+
136
138
  # Add to batch
137
139
  self._event_batch.append(event)
138
-
140
+
139
141
  # Process batch if full
140
142
  if len(self._event_batch) >= self.batch_size:
141
143
  return await self._flush_batch()
142
-
144
+
143
145
  # Start batch timer if not running
144
146
  if self._batch_timer is None or self._batch_timer.done():
145
147
  self._batch_timer = asyncio.create_task(self._batch_timeout_handler())
146
-
148
+
147
149
  return True
148
-
150
+
149
151
  async def consume_batch(self, events: List[Event]) -> int:
150
152
  """Process multiple events in a batch."""
151
153
  if not self._initialized:
152
154
  return 0
153
-
155
+
154
156
  successful = 0
155
157
  for event in events:
156
158
  if await self.consume(event):
157
159
  successful += 1
158
-
160
+
159
161
  return successful
160
-
162
+
161
163
  async def shutdown(self) -> None:
162
164
  """Shutdown the consumer gracefully."""
163
165
  self.logger.info("Shutting down Socket.IO consumer")
164
-
166
+
165
167
  # Cancel reconnection task
166
168
  if self._reconnect_task:
167
169
  self._reconnect_task.cancel()
168
- try:
170
+ with contextlib.suppress(asyncio.CancelledError):
169
171
  await self._reconnect_task
170
- except asyncio.CancelledError:
171
- pass
172
-
172
+
173
173
  # Cancel batch timer
174
174
  if self._batch_timer:
175
175
  self._batch_timer.cancel()
176
- try:
176
+ with contextlib.suppress(asyncio.CancelledError):
177
177
  await self._batch_timer
178
- except asyncio.CancelledError:
179
- pass
180
-
178
+
181
179
  # Flush remaining events
182
180
  if self._event_batch:
183
181
  await self._flush_batch()
184
-
182
+
185
183
  self._initialized = False
186
184
  self._connected = False
187
-
185
+
188
186
  self.logger.info("Socket.IO consumer shutdown complete")
189
-
187
+
190
188
  @property
191
189
  def config(self) -> ConsumerConfig:
192
190
  """Get consumer configuration."""
193
191
  return self._config
194
-
192
+
195
193
  @property
196
194
  def is_healthy(self) -> bool:
197
195
  """Check if consumer is healthy."""
198
196
  # Healthy if initialized and either connected or attempting to reconnect
199
- return self._initialized and (self._connected or self._reconnect_task is not None)
200
-
197
+ return self._initialized and (
198
+ self._connected or self._reconnect_task is not None
199
+ )
200
+
201
201
  def get_metrics(self) -> Dict[str, Any]:
202
202
  """Get consumer metrics."""
203
203
  return {
@@ -205,42 +205,42 @@ class SocketIOConsumer(IEventConsumer):
205
205
  "connected": self._connected,
206
206
  "batch_size": len(self._event_batch),
207
207
  }
208
-
208
+
209
209
  async def _flush_batch(self) -> bool:
210
210
  """
211
211
  Flush the current batch of events to Socket.IO.
212
-
212
+
213
213
  Returns:
214
214
  True if all events emitted successfully
215
215
  """
216
216
  if not self._event_batch:
217
217
  return True
218
-
218
+
219
219
  batch = self._event_batch
220
220
  self._event_batch = []
221
-
221
+
222
222
  # Cancel batch timer
223
223
  if self._batch_timer:
224
224
  self._batch_timer.cancel()
225
225
  self._batch_timer = None
226
-
226
+
227
227
  # Emit events
228
228
  success = await self._emit_events(batch)
229
-
229
+
230
230
  if not success:
231
231
  # Re-queue failed events
232
232
  self._event_batch = batch + self._event_batch
233
233
  return False
234
-
234
+
235
235
  return True
236
-
236
+
237
237
  async def _emit_events(self, events: List[Event]) -> bool:
238
238
  """
239
239
  Emit events via Socket.IO.
240
-
240
+
241
241
  Args:
242
242
  events: Events to emit
243
-
243
+
244
244
  Returns:
245
245
  True if all events emitted successfully
246
246
  """
@@ -248,57 +248,57 @@ class SocketIOConsumer(IEventConsumer):
248
248
  self.logger.debug(f"Cannot emit {len(events)} events - not connected")
249
249
  self._metrics["events_failed"] += len(events)
250
250
  return False
251
-
251
+
252
252
  try:
253
253
  start_time = time.time()
254
-
254
+
255
255
  for event in events:
256
256
  # Convert event to Socket.IO format
257
257
  socketio_event = self._convert_to_socketio(event)
258
-
258
+
259
259
  # Emit event
260
260
  await self.socketio_server.emit(
261
261
  socketio_event["event"],
262
262
  socketio_event["data"],
263
- namespace=socketio_event.get("namespace", "/")
263
+ namespace=socketio_event.get("namespace", "/"),
264
264
  )
265
-
265
+
266
266
  self._metrics["events_emitted"] += 1
267
-
267
+
268
268
  # Update metrics
269
269
  elapsed_ms = (time.time() - start_time) * 1000
270
270
  self._metrics["last_emit_time"] = time.time()
271
-
271
+
272
272
  # Update rolling average
273
273
  avg = self._metrics["average_emit_time_ms"]
274
274
  self._metrics["average_emit_time_ms"] = (avg * 0.9) + (elapsed_ms * 0.1)
275
-
275
+
276
276
  self.logger.debug(
277
277
  f"Emitted {len(events)} events in {elapsed_ms:.1f}ms "
278
278
  f"(avg: {self._metrics['average_emit_time_ms']:.1f}ms)"
279
279
  )
280
-
280
+
281
281
  # Reset reconnect delay on success
282
282
  self.current_reconnect_delay = self.reconnect_delay
283
-
283
+
284
284
  return True
285
-
285
+
286
286
  except Exception as e:
287
287
  self.logger.error(f"Error emitting events: {e}")
288
288
  self._metrics["events_failed"] += len(events)
289
289
  self._metrics["connection_failures"] += 1
290
290
  self._connected = False
291
-
291
+
292
292
  # Start reconnection
293
293
  if self._reconnect_task is None or self._reconnect_task.done():
294
294
  self._reconnect_task = asyncio.create_task(self._reconnect_loop())
295
-
295
+
296
296
  return False
297
-
297
+
298
298
  def _convert_to_socketio(self, event: Event) -> Dict[str, Any]:
299
299
  """
300
300
  Convert an Event to Socket.IO format.
301
-
301
+
302
302
  Maps our standard event format to Socket.IO's expected format.
303
303
  """
304
304
  # Determine Socket.IO event name based on topic
@@ -314,7 +314,7 @@ class SocketIOConsumer(IEventConsumer):
314
314
  socketio_event = "build_event"
315
315
  else:
316
316
  socketio_event = "claude_event"
317
-
317
+
318
318
  # Build Socket.IO data
319
319
  return {
320
320
  "event": socketio_event,
@@ -329,19 +329,21 @@ class SocketIOConsumer(IEventConsumer):
329
329
  },
330
330
  "namespace": "/",
331
331
  }
332
-
332
+
333
333
  async def _batch_timeout_handler(self) -> None:
334
334
  """Handle batch timeout - flush partial batch."""
335
335
  await asyncio.sleep(self.batch_timeout)
336
-
336
+
337
337
  if self._event_batch:
338
- self.logger.debug(f"Batch timeout - flushing {len(self._event_batch)} events")
338
+ self.logger.debug(
339
+ f"Batch timeout - flushing {len(self._event_batch)} events"
340
+ )
339
341
  await self._flush_batch()
340
-
342
+
341
343
  async def _reconnect_loop(self) -> None:
342
344
  """
343
345
  Reconnection loop with exponential backoff.
344
-
346
+
345
347
  Attempts to reconnect to Socket.IO server when connection is lost.
346
348
  """
347
349
  while not self._connected and self._initialized:
@@ -350,7 +352,7 @@ class SocketIOConsumer(IEventConsumer):
350
352
  f"Attempting to reconnect to Socket.IO "
351
353
  f"(delay: {self.current_reconnect_delay}s)"
352
354
  )
353
-
355
+
354
356
  # Try to reconnect
355
357
  if self.socketio_server:
356
358
  # Test connection
@@ -358,19 +360,18 @@ class SocketIOConsumer(IEventConsumer):
358
360
  self._connected = True
359
361
  self._metrics["reconnections"] += 1
360
362
  self.logger.info("Reconnected to Socket.IO server")
361
-
363
+
362
364
  # Reset delay
363
365
  self.current_reconnect_delay = self.reconnect_delay
364
366
  break
365
-
367
+
366
368
  except Exception as e:
367
369
  self.logger.error(f"Reconnection failed: {e}")
368
-
370
+
369
371
  # Wait before next attempt
370
372
  await asyncio.sleep(self.current_reconnect_delay)
371
-
373
+
372
374
  # Exponential backoff
373
375
  self.current_reconnect_delay = min(
374
- self.current_reconnect_delay * 2,
375
- self.max_reconnect_delay
376
- )
376
+ self.current_reconnect_delay * 2, self.max_reconnect_delay
377
+ )