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
@@ -16,18 +16,18 @@ from dataclasses import dataclass
16
16
  from datetime import datetime
17
17
  from typing import Any, Deque, Dict, List, Optional, Set
18
18
 
19
- from ....core.logging_config import get_logger
20
19
  from ..event_normalizer import EventNormalizer
21
20
 
22
21
 
23
22
  @dataclass
24
23
  class RetryableEvent:
25
24
  """Represents an event that can be retried on failure.
26
-
25
+
27
26
  WHY: Network failures are common and transient. By tracking retry
28
27
  attempts, we can recover from temporary issues while avoiding
29
28
  infinite retry loops.
30
29
  """
30
+
31
31
  event_type: str
32
32
  data: Dict[str, Any]
33
33
  attempt_count: int = 0
@@ -35,82 +35,73 @@ class RetryableEvent:
35
35
  created_at: float = None
36
36
  last_attempt: float = None
37
37
  skip_sid: Optional[str] = None
38
-
38
+
39
39
  def __post_init__(self):
40
40
  if self.created_at is None:
41
41
  self.created_at = time.time()
42
42
  if self.last_attempt is None:
43
43
  self.last_attempt = time.time()
44
-
44
+
45
45
  def should_retry(self) -> bool:
46
46
  """Check if this event should be retried.
47
-
47
+
48
48
  WHY: We need to balance reliability with resource usage.
49
49
  Events older than 30 seconds or with too many attempts
50
50
  should be abandoned.
51
51
  """
52
52
  if self.attempt_count >= self.max_retries:
53
53
  return False
54
-
54
+
55
55
  # Don't retry events older than 30 seconds
56
- if time.time() - self.created_at > 30:
57
- return False
58
-
59
- return True
60
-
56
+ return not time.time() - self.created_at > 30
57
+
61
58
  def get_backoff_delay(self) -> float:
62
59
  """Calculate exponential backoff delay.
63
-
60
+
64
61
  WHY: Exponential backoff prevents overwhelming the system
65
62
  during recovery from failures.
66
63
  """
67
64
  base_delay = 1.0 # 1 second
68
- max_delay = 8.0 # 8 seconds max
69
-
70
- delay = min(base_delay * (2 ** self.attempt_count), max_delay)
71
- return delay
65
+ max_delay = 8.0 # 8 seconds max
66
+
67
+ return min(base_delay * (2**self.attempt_count), max_delay)
72
68
 
73
69
 
74
70
  class RetryQueue:
75
71
  """Manages retry queue for failed event broadcasts.
76
-
72
+
77
73
  WHY: Transient network issues shouldn't cause event loss.
78
74
  This queue provides resilient event delivery with backoff.
79
75
  """
80
-
76
+
81
77
  def __init__(self, max_size: int = 1000):
82
78
  self.queue: Deque[RetryableEvent] = deque(maxlen=max_size)
83
79
  self.lock = asyncio.Lock()
84
- self.stats = {
85
- 'queued': 0,
86
- 'retried': 0,
87
- 'succeeded': 0,
88
- 'abandoned': 0
89
- }
90
-
80
+ self.stats = {"queued": 0, "retried": 0, "succeeded": 0, "abandoned": 0}
81
+
91
82
  async def add(self, event: RetryableEvent) -> None:
92
83
  """Add an event to the retry queue."""
93
84
  async with self.lock:
94
85
  self.queue.append(event)
95
- self.stats['queued'] += 1
96
-
86
+ self.stats["queued"] += 1
87
+
97
88
  async def get_ready_events(self) -> List[RetryableEvent]:
98
89
  """Get events that are ready for retry.
99
-
90
+
100
91
  WHY: We need to respect backoff delays to avoid
101
92
  overwhelming the system during recovery.
102
93
  """
103
94
  async with self.lock:
104
95
  current_time = time.time()
105
96
  ready = []
106
-
97
+
107
98
  # Check each event in queue
108
99
  remaining = []
109
100
  for event in self.queue:
110
101
  if not event.should_retry():
111
- self.stats['abandoned'] += 1
102
+ self.stats["abandoned"] += 1
112
103
  continue
113
-
104
+
114
105
  # First attempt (attempt_count == 0) should be immediate
115
106
  if event.attempt_count == 0:
116
107
  ready.append(event)
@@ -121,32 +112,29 @@ class RetryQueue:
121
112
  ready.append(event)
122
113
  else:
123
114
  remaining.append(event)
124
-
115
+
125
116
  # Update queue with events not ready yet
126
117
  self.queue.clear()
127
118
  self.queue.extend(remaining)
128
-
119
+
129
120
  return ready
130
-
121
+
131
122
  async def mark_success(self, event: RetryableEvent) -> None:
132
123
  """Mark an event as successfully sent."""
133
- self.stats['succeeded'] += 1
134
-
124
+ self.stats["succeeded"] += 1
125
+
135
126
  async def mark_retry(self, event: RetryableEvent) -> None:
136
127
  """Mark an event for retry."""
137
128
  event.attempt_count += 1
138
129
  event.last_attempt = time.time()
139
- self.stats['retried'] += 1
140
-
130
+ self.stats["retried"] += 1
131
+
141
132
  if event.should_retry():
142
133
  await self.add(event)
143
-
134
+
144
135
  def get_stats(self) -> Dict[str, int]:
145
136
  """Get retry queue statistics."""
146
- return {
147
- **self.stats,
148
- 'queue_size': len(self.queue)
149
- }
137
+ return {**self.stats, "queue_size": len(self.queue)}
150
138
 
151
139
 
152
140
  class SocketIOEventBroadcaster:
@@ -174,21 +162,21 @@ class SocketIOEventBroadcaster:
174
162
  self.logger = logger
175
163
  self.loop = None # Will be set by main server
176
164
  self.server = server # Reference to main server for event history
177
-
165
+
178
166
  # Initialize retry queue for resilient delivery
179
167
  self.retry_queue = RetryQueue(max_size=1000)
180
168
  self.retry_task = None
181
169
  self.retry_interval = 2.0 # Process retry queue every 2 seconds
182
-
170
+
183
171
  # Initialize event normalizer for consistent schema
184
172
  self.normalizer = EventNormalizer()
185
-
173
+
186
174
  def start_retry_processor(self):
187
175
  """Start the background retry processor.
188
-
176
+
189
177
  WHY: Failed broadcasts need to be retried automatically
190
178
  to ensure reliable event delivery.
191
-
179
+
192
180
  IMPORTANT: This method must handle being called from a different thread
193
181
  than the one running the event loop.
194
182
  """
@@ -199,8 +187,12 @@ class SocketIOEventBroadcaster:
199
187
  running_loop = asyncio.get_running_loop()
200
188
  if running_loop == self.loop:
201
189
  # Same thread, can use create_task directly
202
- self.retry_task = asyncio.create_task(self._process_retry_queue())
203
- self.logger.info("🔄 Started retry queue processor (same thread)")
190
+ self.retry_task = asyncio.create_task(
191
+ self._process_retry_queue()
192
+ )
193
+ self.logger.info(
194
+ "🔄 Started retry queue processor (same thread)"
195
+ )
204
196
  else:
205
197
  # Different thread, need to schedule in the target loop
206
198
  self._start_retry_in_loop()
@@ -209,13 +201,14 @@ class SocketIOEventBroadcaster:
209
201
  self._start_retry_in_loop()
210
202
  except Exception as e:
211
203
  self.logger.error(f"Failed to start retry processor: {e}")
212
-
204
+
213
205
  def _start_retry_in_loop(self):
214
206
  """Helper to start retry processor from a different thread."""
207
+
215
208
  async def _create_retry_task():
216
209
  self.retry_task = asyncio.create_task(self._process_retry_queue())
217
210
  self.logger.info("🔄 Started retry queue processor (cross-thread)")
218
-
211
+
219
212
  # Schedule the task creation in the target loop
220
213
  future = asyncio.run_coroutine_threadsafe(_create_retry_task(), self.loop)
221
214
  try:
@@ -223,43 +216,43 @@ class SocketIOEventBroadcaster:
223
216
  future.result(timeout=1.0)
224
217
  except Exception as e:
225
218
  self.logger.error(f"Failed to schedule retry processor: {e}")
226
-
219
+
227
220
  def stop_retry_processor(self):
228
221
  """Stop the background retry processor."""
229
222
  if self.retry_task:
230
223
  self.retry_task.cancel()
231
224
  self.retry_task = None
232
225
  self.logger.info("🚫 Stopped retry queue processor")
233
-
226
+
234
227
  async def _process_retry_queue(self):
235
228
  """Process the retry queue periodically.
236
-
229
+
237
230
  WHY: Regular processing ensures failed events are retried
238
231
  with appropriate backoff delays.
239
232
  """
240
233
  while True:
241
234
  try:
242
235
  await asyncio.sleep(self.retry_interval)
243
-
236
+
244
237
  # Get events ready for retry
245
238
  ready_events = await self.retry_queue.get_ready_events()
246
-
239
+
247
240
  if ready_events:
248
241
  self.logger.debug(
249
242
  f"🔄 Processing {len(ready_events)} events from retry queue"
250
243
  )
251
-
244
+
252
245
  for event in ready_events:
253
246
  success = await self._retry_broadcast(event)
254
-
247
+
255
248
  if success:
256
249
  await self.retry_queue.mark_success(event)
257
250
  else:
258
251
  await self.retry_queue.mark_retry(event)
259
-
252
+
260
253
  # Log stats periodically
261
254
  stats = self.retry_queue.get_stats()
262
- if stats['retried'] > 0 or stats['abandoned'] > 0:
255
+ if stats["retried"] > 0 or stats["abandoned"] > 0:
263
256
  self.logger.info(
264
257
  f"📊 Retry queue stats - "
265
258
  f"queued: {stats['queued']}, "
@@ -268,15 +261,15 @@ class SocketIOEventBroadcaster:
268
261
  f"abandoned: {stats['abandoned']}, "
269
262
  f"current size: {stats['queue_size']}"
270
263
  )
271
-
264
+
272
265
  except asyncio.CancelledError:
273
266
  break
274
267
  except Exception as e:
275
268
  self.logger.error(f"Error processing retry queue: {e}")
276
-
269
+
277
270
  async def _retry_broadcast(self, event: RetryableEvent) -> bool:
278
271
  """Retry broadcasting a failed event.
279
-
272
+
280
273
  WHY: Isolated retry logic allows for special handling
281
274
  and metrics tracking of retry attempts. Uses normalizer
282
275
  to ensure consistent schema.
@@ -285,27 +278,27 @@ class SocketIOEventBroadcaster:
285
278
  self.logger.debug(
286
279
  f"🔄 Retrying {event.event_type} (attempt {event.attempt_count + 1}/{event.max_retries})"
287
280
  )
288
-
281
+
289
282
  # Reconstruct the raw event
290
283
  raw_event = {
291
284
  "type": event.event_type,
292
285
  "timestamp": datetime.now().isoformat(),
293
286
  "data": {**event.data, "retry_attempt": event.attempt_count + 1},
294
287
  }
295
-
288
+
296
289
  # Normalize the event
297
290
  normalized = self.normalizer.normalize(raw_event)
298
291
  full_event = normalized.to_dict()
299
-
292
+
300
293
  # Attempt broadcast
301
294
  if event.skip_sid:
302
295
  await self.sio.emit("claude_event", full_event, skip_sid=event.skip_sid)
303
296
  else:
304
297
  await self.sio.emit("claude_event", full_event)
305
-
298
+
306
299
  self.logger.debug(f"✅ Successfully retried {event.event_type}")
307
300
  return True
308
-
301
+
309
302
  except Exception as e:
310
303
  self.logger.warning(
311
304
  f"⚠️ Retry failed for {event.event_type} "
@@ -313,9 +306,11 @@ class SocketIOEventBroadcaster:
313
306
  )
314
307
  return False
315
308
 
316
- def broadcast_event(self, event_type: str, data: Dict[str, Any], skip_sid: Optional[str] = None):
309
+ def broadcast_event(
310
+ self, event_type: str, data: Dict[str, Any], skip_sid: Optional[str] = None
311
+ ):
317
312
  """Broadcast an event to all connected clients with retry support.
318
-
313
+
319
314
  WHY: Enhanced with retry queue to ensure reliable delivery
320
315
  even during transient network issues. Now uses EventNormalizer
321
316
  to ensure consistent event schema.
@@ -329,7 +324,7 @@ class SocketIOEventBroadcaster:
329
324
  "timestamp": datetime.now().isoformat(),
330
325
  "data": data,
331
326
  }
332
-
327
+
333
328
  # Normalize the event to consistent schema
334
329
  normalized = self.normalizer.normalize(raw_event)
335
330
  event = normalized.to_dict()
@@ -338,12 +333,14 @@ class SocketIOEventBroadcaster:
338
333
  with self.buffer_lock:
339
334
  self.event_buffer.append(event)
340
335
  self.stats["events_buffered"] += 1
341
-
336
+
342
337
  # Also add to event history if available (for client replay)
343
338
  # Access through server reference to maintain single history source
344
- if hasattr(self, 'server') and hasattr(self.server, 'event_history'):
339
+ if hasattr(self, "server") and hasattr(self.server, "event_history"):
345
340
  self.server.event_history.append(event)
346
- self.logger.debug(f"Added {event['type']}/{event['subtype']} to history (total: {len(self.server.event_history)})")
341
+ self.logger.debug(
342
+ f"Added {event['type']}/{event['subtype']} to history (total: {len(self.server.event_history)})"
343
+ )
347
344
 
348
345
  # Broadcast to all connected clients
349
346
  broadcast_success = False
@@ -355,9 +352,9 @@ class SocketIOEventBroadcaster:
355
352
  coro = self.sio.emit("claude_event", event, skip_sid=skip_sid)
356
353
  else:
357
354
  coro = self.sio.emit("claude_event", event)
358
-
355
+
359
356
  future = asyncio.run_coroutine_threadsafe(coro, self.loop)
360
-
357
+
361
358
  # Wait briefly to see if broadcast succeeds
362
359
  try:
363
360
  future.result(timeout=0.5) # 500ms timeout
@@ -374,21 +371,18 @@ class SocketIOEventBroadcaster:
374
371
 
375
372
  except Exception as e:
376
373
  self.logger.error(f"Failed to broadcast event {event_type}: {e}")
377
-
374
+
378
375
  # Add to retry queue if broadcast failed
379
376
  if not broadcast_success and self.loop:
380
377
  retryable_event = RetryableEvent(
381
- event_type=event_type,
382
- data=data,
383
- skip_sid=skip_sid
378
+ event_type=event_type, data=data, skip_sid=skip_sid
384
379
  )
385
-
380
+
386
381
  # Queue for retry
387
382
  asyncio.run_coroutine_threadsafe(
388
- self.retry_queue.add(retryable_event),
389
- self.loop
383
+ self.retry_queue.add(retryable_event), self.loop
390
384
  )
391
-
385
+
392
386
  self.logger.warning(
393
387
  f"⚠️ Queued {event_type} for retry (queue size: {len(self.retry_queue.queue)})"
394
388
  )
@@ -529,10 +523,10 @@ class SocketIOEventBroadcaster:
529
523
  def system_status(self, status: Dict[str, Any]):
530
524
  """Broadcast system status information."""
531
525
  self.broadcast_event("system_status", status)
532
-
526
+
533
527
  def broadcast_system_heartbeat(self, heartbeat_data: Dict[str, Any]):
534
528
  """Broadcast system heartbeat event.
535
-
529
+
536
530
  WHY: System events are separate from hook events to provide
537
531
  server health monitoring independent of Claude activity.
538
532
  Now uses broadcast_event for consistency with buffering and normalization.