claude-mpm 4.1.1__py3-none-any.whl → 4.1.3__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 (389) 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/engineer.json +33 -11
  18. claude_mpm/agents/templates/imagemagick.json +256 -0
  19. claude_mpm/agents/templates/qa.json +41 -2
  20. claude_mpm/agents/templates/ticketing.json +5 -5
  21. claude_mpm/agents/templates/web_qa.json +50 -2
  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 +648 -1098
  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 +339 -967
  39. claude_mpm/cli/commands/monitor.py +117 -88
  40. claude_mpm/cli/commands/run.py +233 -542
  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 +280 -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 +22 -29
  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 +500 -680
  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 -17
  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 +99 -154
  114. claude_mpm/hooks/claude_hooks/hook_handler.py +110 -720
  115. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
  116. claude_mpm/hooks/claude_hooks/hook_handler_original.py +1040 -0
  117. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +347 -0
  118. claude_mpm/hooks/claude_hooks/memory_integration.py +2 -4
  119. claude_mpm/hooks/claude_hooks/response_tracking.py +15 -11
  120. claude_mpm/hooks/claude_hooks/services/__init__.py +13 -0
  121. claude_mpm/hooks/claude_hooks/services/connection_manager.py +190 -0
  122. claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
  123. claude_mpm/hooks/claude_hooks/services/state_manager.py +282 -0
  124. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
  125. claude_mpm/hooks/claude_hooks/tool_analysis.py +12 -18
  126. claude_mpm/hooks/memory_integration_hook.py +5 -5
  127. claude_mpm/hooks/tool_call_interceptor.py +1 -1
  128. claude_mpm/hooks/validation_hooks.py +4 -4
  129. claude_mpm/init.py +4 -9
  130. claude_mpm/models/__init__.py +2 -2
  131. claude_mpm/models/agent_session.py +11 -14
  132. claude_mpm/scripts/mcp_server.py +20 -11
  133. claude_mpm/scripts/mcp_wrapper.py +5 -5
  134. claude_mpm/scripts/mpm_doctor.py +321 -0
  135. claude_mpm/scripts/socketio_daemon.py +28 -25
  136. claude_mpm/scripts/socketio_daemon_hardened.py +298 -258
  137. claude_mpm/scripts/socketio_server_manager.py +116 -95
  138. claude_mpm/services/__init__.py +49 -49
  139. claude_mpm/services/agent_capabilities_service.py +12 -18
  140. claude_mpm/services/agents/__init__.py +22 -22
  141. claude_mpm/services/agents/agent_builder.py +140 -119
  142. claude_mpm/services/agents/deployment/__init__.py +3 -3
  143. claude_mpm/services/agents/deployment/agent_config_provider.py +9 -9
  144. claude_mpm/services/agents/deployment/agent_configuration_manager.py +19 -20
  145. claude_mpm/services/agents/deployment/agent_definition_factory.py +1 -5
  146. claude_mpm/services/agents/deployment/agent_deployment.py +129 -511
  147. claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -8
  148. claude_mpm/services/agents/deployment/agent_environment_manager.py +2 -7
  149. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +6 -10
  150. claude_mpm/services/agents/deployment/agent_format_converter.py +11 -15
  151. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +2 -3
  152. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -5
  153. claude_mpm/services/agents/deployment/agent_metrics_collector.py +13 -19
  154. claude_mpm/services/agents/deployment/agent_restore_handler.py +0 -1
  155. claude_mpm/services/agents/deployment/agent_template_builder.py +26 -35
  156. claude_mpm/services/agents/deployment/agent_validator.py +0 -1
  157. claude_mpm/services/agents/deployment/agent_version_manager.py +7 -9
  158. claude_mpm/services/agents/deployment/agent_versioning.py +3 -3
  159. claude_mpm/services/agents/deployment/agents_directory_resolver.py +6 -7
  160. claude_mpm/services/agents/deployment/async_agent_deployment.py +51 -38
  161. claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
  162. claude_mpm/services/agents/deployment/config/__init__.py +1 -1
  163. claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
  164. claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
  165. claude_mpm/services/agents/deployment/deployment_type_detector.py +1 -1
  166. claude_mpm/services/agents/deployment/deployment_wrapper.py +18 -18
  167. claude_mpm/services/agents/deployment/facade/__init__.py +1 -1
  168. claude_mpm/services/agents/deployment/facade/deployment_executor.py +0 -3
  169. claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -4
  170. claude_mpm/services/agents/deployment/interface_adapter.py +5 -7
  171. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +345 -276
  172. claude_mpm/services/agents/deployment/pipeline/__init__.py +2 -2
  173. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +1 -1
  174. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +6 -4
  175. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +3 -3
  176. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +2 -2
  177. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +14 -13
  178. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +0 -1
  179. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +1 -1
  180. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +8 -9
  181. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +1 -1
  182. claude_mpm/services/agents/deployment/processors/__init__.py +1 -1
  183. claude_mpm/services/agents/deployment/processors/agent_processor.py +20 -16
  184. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +5 -12
  185. claude_mpm/services/agents/deployment/results/__init__.py +1 -1
  186. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +1 -1
  187. claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
  188. claude_mpm/services/agents/deployment/strategies/__init__.py +2 -2
  189. claude_mpm/services/agents/deployment/strategies/base_strategy.py +1 -7
  190. claude_mpm/services/agents/deployment/strategies/project_strategy.py +1 -4
  191. claude_mpm/services/agents/deployment/strategies/system_strategy.py +2 -3
  192. claude_mpm/services/agents/deployment/strategies/user_strategy.py +3 -7
  193. claude_mpm/services/agents/deployment/validation/__init__.py +1 -1
  194. claude_mpm/services/agents/deployment/validation/agent_validator.py +1 -1
  195. claude_mpm/services/agents/deployment/validation/template_validator.py +2 -2
  196. claude_mpm/services/agents/deployment/validation/validation_result.py +2 -6
  197. claude_mpm/services/agents/loading/__init__.py +1 -1
  198. claude_mpm/services/agents/loading/agent_profile_loader.py +6 -12
  199. claude_mpm/services/agents/loading/base_agent_manager.py +5 -5
  200. claude_mpm/services/agents/loading/framework_agent_loader.py +2 -4
  201. claude_mpm/services/agents/management/__init__.py +1 -1
  202. claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -3
  203. claude_mpm/services/agents/management/agent_management_service.py +5 -9
  204. claude_mpm/services/agents/memory/__init__.py +4 -4
  205. claude_mpm/services/agents/memory/agent_memory_manager.py +157 -503
  206. claude_mpm/services/agents/memory/agent_persistence_service.py +0 -2
  207. claude_mpm/services/agents/memory/content_manager.py +44 -38
  208. claude_mpm/services/agents/memory/memory_categorization_service.py +165 -0
  209. claude_mpm/services/agents/memory/memory_file_service.py +103 -0
  210. claude_mpm/services/agents/memory/memory_format_service.py +201 -0
  211. claude_mpm/services/agents/memory/memory_limits_service.py +99 -0
  212. claude_mpm/services/agents/memory/template_generator.py +4 -6
  213. claude_mpm/services/agents/registry/__init__.py +11 -7
  214. claude_mpm/services/agents/registry/deployed_agent_discovery.py +30 -27
  215. claude_mpm/services/agents/registry/modification_tracker.py +3 -6
  216. claude_mpm/services/async_session_logger.py +1 -2
  217. claude_mpm/services/claude_session_logger.py +1 -2
  218. claude_mpm/services/cli/__init__.py +18 -0
  219. claude_mpm/services/cli/agent_cleanup_service.py +407 -0
  220. claude_mpm/services/cli/agent_dependency_service.py +395 -0
  221. claude_mpm/services/cli/agent_listing_service.py +463 -0
  222. claude_mpm/services/cli/agent_output_formatter.py +605 -0
  223. claude_mpm/services/cli/agent_validation_service.py +589 -0
  224. claude_mpm/services/cli/dashboard_launcher.py +424 -0
  225. claude_mpm/services/cli/memory_crud_service.py +617 -0
  226. claude_mpm/services/cli/memory_output_formatter.py +604 -0
  227. claude_mpm/services/cli/session_manager.py +513 -0
  228. claude_mpm/services/cli/socketio_manager.py +498 -0
  229. claude_mpm/services/cli/startup_checker.py +370 -0
  230. claude_mpm/services/command_deployment_service.py +173 -0
  231. claude_mpm/services/command_handler_service.py +20 -22
  232. claude_mpm/services/core/__init__.py +25 -25
  233. claude_mpm/services/core/base.py +0 -5
  234. claude_mpm/services/core/cache_manager.py +311 -0
  235. claude_mpm/services/core/interfaces/__init__.py +32 -32
  236. claude_mpm/services/core/interfaces/agent.py +0 -21
  237. claude_mpm/services/core/interfaces/communication.py +0 -27
  238. claude_mpm/services/core/interfaces/infrastructure.py +0 -56
  239. claude_mpm/services/core/interfaces/service.py +0 -29
  240. claude_mpm/services/core/memory_manager.py +637 -0
  241. claude_mpm/services/core/path_resolver.py +498 -0
  242. claude_mpm/services/core/service_container.py +520 -0
  243. claude_mpm/services/core/service_interfaces.py +436 -0
  244. claude_mpm/services/diagnostics/__init__.py +1 -1
  245. claude_mpm/services/diagnostics/checks/__init__.py +6 -6
  246. claude_mpm/services/diagnostics/checks/agent_check.py +152 -97
  247. claude_mpm/services/diagnostics/checks/base_check.py +12 -16
  248. claude_mpm/services/diagnostics/checks/claude_desktop_check.py +84 -81
  249. claude_mpm/services/diagnostics/checks/common_issues_check.py +99 -91
  250. claude_mpm/services/diagnostics/checks/configuration_check.py +82 -77
  251. claude_mpm/services/diagnostics/checks/filesystem_check.py +67 -68
  252. claude_mpm/services/diagnostics/checks/installation_check.py +254 -94
  253. claude_mpm/services/diagnostics/checks/mcp_check.py +90 -88
  254. claude_mpm/services/diagnostics/checks/monitor_check.py +75 -76
  255. claude_mpm/services/diagnostics/checks/startup_log_check.py +67 -73
  256. claude_mpm/services/diagnostics/diagnostic_runner.py +67 -59
  257. claude_mpm/services/diagnostics/doctor_reporter.py +107 -70
  258. claude_mpm/services/diagnostics/models.py +21 -19
  259. claude_mpm/services/event_aggregator.py +10 -17
  260. claude_mpm/services/event_bus/__init__.py +1 -1
  261. claude_mpm/services/event_bus/config.py +54 -35
  262. claude_mpm/services/event_bus/event_bus.py +76 -71
  263. claude_mpm/services/event_bus/relay.py +74 -64
  264. claude_mpm/services/events/__init__.py +11 -11
  265. claude_mpm/services/events/consumers/__init__.py +3 -3
  266. claude_mpm/services/events/consumers/dead_letter.py +71 -63
  267. claude_mpm/services/events/consumers/logging.py +39 -37
  268. claude_mpm/services/events/consumers/metrics.py +56 -57
  269. claude_mpm/services/events/consumers/socketio.py +82 -81
  270. claude_mpm/services/events/core.py +110 -99
  271. claude_mpm/services/events/interfaces.py +56 -72
  272. claude_mpm/services/events/producers/__init__.py +1 -1
  273. claude_mpm/services/events/producers/hook.py +38 -38
  274. claude_mpm/services/events/producers/system.py +46 -44
  275. claude_mpm/services/exceptions.py +81 -80
  276. claude_mpm/services/framework_claude_md_generator/__init__.py +2 -4
  277. claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -5
  278. claude_mpm/services/framework_claude_md_generator/content_validator.py +1 -1
  279. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +4 -4
  280. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -1
  281. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -2
  282. claude_mpm/services/framework_claude_md_generator/version_manager.py +4 -5
  283. claude_mpm/services/hook_service.py +6 -9
  284. claude_mpm/services/infrastructure/__init__.py +1 -1
  285. claude_mpm/services/infrastructure/context_preservation.py +8 -12
  286. claude_mpm/services/infrastructure/monitoring.py +21 -23
  287. claude_mpm/services/mcp_gateway/__init__.py +37 -37
  288. claude_mpm/services/mcp_gateway/auto_configure.py +95 -103
  289. claude_mpm/services/mcp_gateway/config/__init__.py +1 -1
  290. claude_mpm/services/mcp_gateway/config/config_loader.py +23 -25
  291. claude_mpm/services/mcp_gateway/config/config_schema.py +5 -5
  292. claude_mpm/services/mcp_gateway/config/configuration.py +9 -6
  293. claude_mpm/services/mcp_gateway/core/__init__.py +10 -10
  294. claude_mpm/services/mcp_gateway/core/base.py +0 -3
  295. claude_mpm/services/mcp_gateway/core/interfaces.py +1 -38
  296. claude_mpm/services/mcp_gateway/core/process_pool.py +99 -93
  297. claude_mpm/services/mcp_gateway/core/singleton_manager.py +65 -62
  298. claude_mpm/services/mcp_gateway/core/startup_verification.py +75 -74
  299. claude_mpm/services/mcp_gateway/main.py +2 -1
  300. claude_mpm/services/mcp_gateway/registry/service_registry.py +5 -8
  301. claude_mpm/services/mcp_gateway/registry/tool_registry.py +1 -1
  302. claude_mpm/services/mcp_gateway/server/__init__.py +1 -1
  303. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +12 -19
  304. claude_mpm/services/mcp_gateway/server/stdio_handler.py +4 -3
  305. claude_mpm/services/mcp_gateway/server/stdio_server.py +79 -71
  306. claude_mpm/services/mcp_gateway/tools/__init__.py +2 -2
  307. claude_mpm/services/mcp_gateway/tools/base_adapter.py +5 -6
  308. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +13 -22
  309. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +79 -78
  310. claude_mpm/services/mcp_gateway/tools/hello_world.py +12 -14
  311. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +42 -49
  312. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +51 -55
  313. claude_mpm/services/memory/__init__.py +3 -3
  314. claude_mpm/services/memory/builder.py +3 -6
  315. claude_mpm/services/memory/cache/__init__.py +1 -1
  316. claude_mpm/services/memory/cache/shared_prompt_cache.py +3 -5
  317. claude_mpm/services/memory/cache/simple_cache.py +1 -1
  318. claude_mpm/services/memory/indexed_memory.py +5 -7
  319. claude_mpm/services/memory/optimizer.py +7 -10
  320. claude_mpm/services/memory/router.py +8 -9
  321. claude_mpm/services/memory_hook_service.py +48 -34
  322. claude_mpm/services/monitor_build_service.py +77 -73
  323. claude_mpm/services/port_manager.py +130 -108
  324. claude_mpm/services/project/analyzer.py +12 -10
  325. claude_mpm/services/project/registry.py +11 -11
  326. claude_mpm/services/recovery_manager.py +10 -19
  327. claude_mpm/services/response_tracker.py +0 -1
  328. claude_mpm/services/runner_configuration_service.py +19 -20
  329. claude_mpm/services/session_management_service.py +7 -11
  330. claude_mpm/services/shared/__init__.py +1 -1
  331. claude_mpm/services/shared/async_service_base.py +58 -50
  332. claude_mpm/services/shared/config_service_base.py +73 -67
  333. claude_mpm/services/shared/lifecycle_service_base.py +82 -78
  334. claude_mpm/services/shared/manager_base.py +94 -82
  335. claude_mpm/services/shared/service_factory.py +96 -98
  336. claude_mpm/services/socketio/__init__.py +3 -3
  337. claude_mpm/services/socketio/client_proxy.py +5 -5
  338. claude_mpm/services/socketio/event_normalizer.py +199 -181
  339. claude_mpm/services/socketio/handlers/__init__.py +3 -3
  340. claude_mpm/services/socketio/handlers/base.py +5 -4
  341. claude_mpm/services/socketio/handlers/connection.py +163 -136
  342. claude_mpm/services/socketio/handlers/file.py +13 -14
  343. claude_mpm/services/socketio/handlers/git.py +12 -7
  344. claude_mpm/services/socketio/handlers/hook.py +49 -44
  345. claude_mpm/services/socketio/handlers/memory.py +0 -1
  346. claude_mpm/services/socketio/handlers/project.py +0 -1
  347. claude_mpm/services/socketio/handlers/registry.py +37 -19
  348. claude_mpm/services/socketio/migration_utils.py +98 -84
  349. claude_mpm/services/socketio/server/__init__.py +1 -1
  350. claude_mpm/services/socketio/server/broadcaster.py +81 -87
  351. claude_mpm/services/socketio/server/core.py +65 -54
  352. claude_mpm/services/socketio/server/eventbus_integration.py +95 -56
  353. claude_mpm/services/socketio/server/main.py +64 -38
  354. claude_mpm/services/socketio_client_manager.py +10 -12
  355. claude_mpm/services/subprocess_launcher_service.py +4 -7
  356. claude_mpm/services/system_instructions_service.py +13 -14
  357. claude_mpm/services/ticket_manager.py +2 -2
  358. claude_mpm/services/utility_service.py +5 -13
  359. claude_mpm/services/version_control/__init__.py +16 -16
  360. claude_mpm/services/version_control/branch_strategy.py +5 -8
  361. claude_mpm/services/version_control/conflict_resolution.py +9 -23
  362. claude_mpm/services/version_control/git_operations.py +5 -7
  363. claude_mpm/services/version_control/semantic_versioning.py +16 -17
  364. claude_mpm/services/version_control/version_parser.py +13 -18
  365. claude_mpm/services/version_service.py +10 -11
  366. claude_mpm/storage/__init__.py +1 -1
  367. claude_mpm/storage/state_storage.py +22 -28
  368. claude_mpm/utils/__init__.py +6 -6
  369. claude_mpm/utils/agent_dependency_loader.py +47 -33
  370. claude_mpm/utils/config_manager.py +11 -14
  371. claude_mpm/utils/dependency_cache.py +1 -1
  372. claude_mpm/utils/dependency_manager.py +13 -17
  373. claude_mpm/utils/dependency_strategies.py +8 -10
  374. claude_mpm/utils/environment_context.py +3 -9
  375. claude_mpm/utils/error_handler.py +3 -13
  376. claude_mpm/utils/file_utils.py +1 -1
  377. claude_mpm/utils/path_operations.py +8 -12
  378. claude_mpm/utils/robust_installer.py +110 -33
  379. claude_mpm/utils/subprocess_utils.py +5 -6
  380. claude_mpm/validation/agent_validator.py +3 -6
  381. claude_mpm/validation/frontmatter_validator.py +1 -1
  382. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/METADATA +1 -1
  383. claude_mpm-4.1.3.dist-info/RECORD +528 -0
  384. claude_mpm/cli/commands/run_config_checker.py +0 -160
  385. claude_mpm-4.1.1.dist-info/RECORD +0 -494
  386. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/WHEEL +0 -0
  387. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/entry_points.txt +0 -0
  388. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/licenses/LICENSE +0 -0
  389. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,106 @@
1
+ """Duplicate event detection service for Claude hook handler.
2
+
3
+ This service manages:
4
+ - Event key generation
5
+ - Duplicate event detection within time windows
6
+ - Recent event tracking
7
+ """
8
+
9
+ import threading
10
+ import time
11
+ from collections import deque
12
+
13
+
14
+ class DuplicateEventDetector:
15
+ """Detects and filters duplicate events."""
16
+
17
+ def __init__(
18
+ self, max_recent_events: int = 10, duplicate_window_seconds: float = 0.1
19
+ ):
20
+ """Initialize duplicate event detector.
21
+
22
+ Args:
23
+ max_recent_events: Maximum number of recent events to track
24
+ duplicate_window_seconds: Time window in seconds for duplicate detection
25
+ """
26
+ # Track recent events to detect duplicates
27
+ self._recent_events = deque(maxlen=max_recent_events)
28
+ self._events_lock = threading.Lock()
29
+ self.duplicate_window_seconds = duplicate_window_seconds
30
+
31
+ def is_duplicate(self, event: dict) -> bool:
32
+ """Check if an event is a duplicate of a recent event.
33
+
34
+ Args:
35
+ event: The event dictionary to check
36
+
37
+ Returns:
38
+ True if the event is a duplicate, False otherwise
39
+ """
40
+ event_key = self.generate_event_key(event)
41
+ current_time = time.time()
42
+
43
+ with self._events_lock:
44
+ # Check if we've seen this event recently
45
+ for recent_key, recent_time in self._recent_events:
46
+ if (
47
+ recent_key == event_key
48
+ and (current_time - recent_time) < self.duplicate_window_seconds
49
+ ):
50
+ return True
51
+
52
+ # Not a duplicate, record it
53
+ self._recent_events.append((event_key, current_time))
54
+ return False
55
+
56
+ def generate_event_key(self, event: dict) -> str:
57
+ """Generate a unique key for an event to detect duplicates.
58
+
59
+ WHY: Claude Code may call the hook multiple times for the same event
60
+ because the hook is registered for multiple event types. We need to
61
+ detect and skip duplicate processing while still returning continue.
62
+
63
+ Args:
64
+ event: The event dictionary
65
+
66
+ Returns:
67
+ A unique string key for the event
68
+ """
69
+ # Create a key from event type, session_id, and key data
70
+ hook_type = event.get("hook_event_name", "unknown")
71
+ session_id = event.get("session_id", "")
72
+
73
+ # Add type-specific data to make the key unique
74
+ if hook_type == "PreToolUse":
75
+ tool_name = event.get("tool_name", "")
76
+ # For some tools, include parameters to distinguish calls
77
+ if tool_name == "Task":
78
+ tool_input = event.get("tool_input", {})
79
+ agent = tool_input.get("subagent_type", "")
80
+ prompt_preview = (
81
+ tool_input.get("prompt", "") or tool_input.get("description", "")
82
+ )[:50]
83
+ return f"{hook_type}:{session_id}:{tool_name}:{agent}:{prompt_preview}"
84
+ return f"{hook_type}:{session_id}:{tool_name}"
85
+
86
+ if hook_type == "UserPromptSubmit":
87
+ prompt_preview = event.get("prompt", "")[:50]
88
+ return f"{hook_type}:{session_id}:{prompt_preview}"
89
+
90
+ # For other events, just use type and session
91
+ return f"{hook_type}:{session_id}"
92
+
93
+ def clear_old_events(self):
94
+ """Clear events older than the duplicate window."""
95
+ current_time = time.time()
96
+ cutoff_time = current_time - self.duplicate_window_seconds
97
+
98
+ with self._events_lock:
99
+ # Create a new deque with only recent events
100
+ recent_only = deque(
101
+ (key, timestamp)
102
+ for key, timestamp in self._recent_events
103
+ if timestamp > cutoff_time
104
+ )
105
+ recent_only.maxlen = self._recent_events.maxlen
106
+ self._recent_events = recent_only
@@ -0,0 +1,282 @@
1
+ """State management service for Claude hook handler.
2
+
3
+ This service manages:
4
+ - Agent delegation tracking
5
+ - Git branch caching
6
+ - Session state management
7
+ - Cleanup of old entries
8
+ """
9
+
10
+ import os
11
+ import subprocess
12
+ import time
13
+ from collections import deque
14
+ from datetime import datetime
15
+ from typing import Optional
16
+
17
+ # Import constants for configuration
18
+ try:
19
+ from claude_mpm.core.constants import TimeoutConfig
20
+ except ImportError:
21
+ # Fallback values if constants module not available
22
+ class TimeoutConfig:
23
+ QUICK_TIMEOUT = 2.0
24
+
25
+
26
+ # Debug mode is enabled by default for better visibility into hook processing
27
+ DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "true").lower() != "false"
28
+
29
+
30
+ class StateManagerService:
31
+ """Manages state for the Claude hook handler."""
32
+
33
+ def __init__(self):
34
+ """Initialize state management service."""
35
+ # Maximum sizes for tracking
36
+ self.MAX_DELEGATION_TRACKING = 200
37
+ self.MAX_PROMPT_TRACKING = 100
38
+ self.MAX_CACHE_AGE_SECONDS = 300
39
+ self.CLEANUP_INTERVAL_EVENTS = 100
40
+
41
+ # Agent delegation tracking
42
+ # Store recent Task delegations: session_id -> agent_type
43
+ self.active_delegations = {}
44
+ # Use deque to limit memory usage (keep last 100 delegations)
45
+ self.delegation_history = deque(maxlen=100)
46
+ # Store delegation request data for response correlation: session_id -> request_data
47
+ self.delegation_requests = {}
48
+
49
+ # Git branch cache (to avoid repeated subprocess calls)
50
+ self._git_branch_cache = {}
51
+ self._git_branch_cache_time = {}
52
+
53
+ # Store current user prompts for comprehensive response tracking
54
+ self.pending_prompts = {} # session_id -> prompt data
55
+
56
+ # Track events for periodic cleanup
57
+ self.events_processed = 0
58
+ self.last_cleanup = time.time()
59
+
60
+ def track_delegation(
61
+ self, session_id: str, agent_type: str, request_data: Optional[dict] = None
62
+ ):
63
+ """Track a new agent delegation with optional request data for response correlation."""
64
+ if DEBUG:
65
+ import sys
66
+
67
+ print(
68
+ f" - session_id: {session_id[:16] if session_id else 'None'}...",
69
+ file=sys.stderr,
70
+ )
71
+ print(f" - agent_type: {agent_type}", file=sys.stderr)
72
+ print(f" - request_data provided: {bool(request_data)}", file=sys.stderr)
73
+ print(
74
+ f" - delegation_requests size before: {len(self.delegation_requests)}",
75
+ file=sys.stderr,
76
+ )
77
+
78
+ if session_id and agent_type and agent_type != "unknown":
79
+ self.active_delegations[session_id] = agent_type
80
+ key = f"{session_id}:{datetime.now().timestamp()}"
81
+ self.delegation_history.append((key, agent_type))
82
+
83
+ # Store request data for response tracking correlation
84
+ if request_data:
85
+ self.delegation_requests[session_id] = {
86
+ "agent_type": agent_type,
87
+ "request": request_data,
88
+ "timestamp": datetime.now().isoformat(),
89
+ }
90
+ if DEBUG:
91
+ import sys
92
+
93
+ print(
94
+ f" - ✅ Stored in delegation_requests[{session_id[:16]}...]",
95
+ file=sys.stderr,
96
+ )
97
+ print(
98
+ f" - delegation_requests size after: {len(self.delegation_requests)}",
99
+ file=sys.stderr,
100
+ )
101
+
102
+ # Clean up old delegations (older than 5 minutes)
103
+ cutoff_time = datetime.now().timestamp() - 300
104
+ keys_to_remove = []
105
+ for sid in list(self.active_delegations.keys()):
106
+ # Check if this is an old entry by looking in history
107
+ found_recent = False
108
+ for hist_key, _ in reversed(self.delegation_history):
109
+ if hist_key.startswith(sid):
110
+ _, timestamp = hist_key.split(":", 1)
111
+ if float(timestamp) > cutoff_time:
112
+ found_recent = True
113
+ break
114
+ if not found_recent:
115
+ keys_to_remove.append(sid)
116
+
117
+ for key in keys_to_remove:
118
+ if key in self.active_delegations:
119
+ del self.active_delegations[key]
120
+ if key in self.delegation_requests:
121
+ del self.delegation_requests[key]
122
+
123
+ def get_delegation_agent_type(self, session_id: str) -> str:
124
+ """Get the agent type for a session's active delegation."""
125
+ # First try exact session match
126
+ if session_id and session_id in self.active_delegations:
127
+ return self.active_delegations[session_id]
128
+
129
+ # Then try to find in recent history
130
+ if session_id:
131
+ for key, agent_type in reversed(self.delegation_history):
132
+ if key.startswith(session_id):
133
+ return agent_type
134
+
135
+ return "unknown"
136
+
137
+ def cleanup_old_entries(self):
138
+ """Clean up old entries to prevent memory growth."""
139
+ datetime.now().timestamp() - self.MAX_CACHE_AGE_SECONDS
140
+
141
+ # Clean up delegation tracking dictionaries
142
+ for storage in [self.active_delegations, self.delegation_requests]:
143
+ if len(storage) > self.MAX_DELEGATION_TRACKING:
144
+ # Keep only the most recent entries
145
+ sorted_keys = sorted(storage.keys())
146
+ excess = len(storage) - self.MAX_DELEGATION_TRACKING
147
+ for key in sorted_keys[:excess]:
148
+ del storage[key]
149
+
150
+ # Clean up pending prompts
151
+ if len(self.pending_prompts) > self.MAX_PROMPT_TRACKING:
152
+ sorted_keys = sorted(self.pending_prompts.keys())
153
+ excess = len(self.pending_prompts) - self.MAX_PROMPT_TRACKING
154
+ for key in sorted_keys[:excess]:
155
+ del self.pending_prompts[key]
156
+
157
+ # Clean up git branch cache
158
+ expired_keys = [
159
+ key
160
+ for key, cache_time in self._git_branch_cache_time.items()
161
+ if datetime.now().timestamp() - cache_time > self.MAX_CACHE_AGE_SECONDS
162
+ ]
163
+ for key in expired_keys:
164
+ self._git_branch_cache.pop(key, None)
165
+ self._git_branch_cache_time.pop(key, None)
166
+
167
+ def get_git_branch(self, working_dir: Optional[str] = None) -> str:
168
+ """Get git branch for the given directory with caching.
169
+
170
+ WHY caching approach:
171
+ - Avoids repeated subprocess calls which are expensive
172
+ - Caches results for 30 seconds per directory
173
+ - Falls back gracefully if git command fails
174
+ - Returns 'Unknown' for non-git directories
175
+ """
176
+ # Use current working directory if not specified
177
+ if not working_dir:
178
+ working_dir = os.getcwd()
179
+
180
+ # Check cache first (cache for 30 seconds)
181
+ current_time = datetime.now().timestamp()
182
+ cache_key = working_dir
183
+
184
+ if (
185
+ cache_key in self._git_branch_cache
186
+ and cache_key in self._git_branch_cache_time
187
+ and current_time - self._git_branch_cache_time[cache_key] < 30
188
+ ):
189
+ return self._git_branch_cache[cache_key]
190
+
191
+ # Try to get git branch
192
+ try:
193
+ # Change to the working directory temporarily
194
+ original_cwd = os.getcwd()
195
+ os.chdir(working_dir)
196
+
197
+ # Run git command to get current branch
198
+ result = subprocess.run(
199
+ ["git", "branch", "--show-current"],
200
+ capture_output=True,
201
+ text=True,
202
+ timeout=TimeoutConfig.QUICK_TIMEOUT,
203
+ check=False, # Quick timeout to avoid hanging
204
+ )
205
+
206
+ # Restore original directory
207
+ os.chdir(original_cwd)
208
+
209
+ if result.returncode == 0 and result.stdout.strip():
210
+ branch = result.stdout.strip()
211
+ # Cache the result
212
+ self._git_branch_cache[cache_key] = branch
213
+ self._git_branch_cache_time[cache_key] = current_time
214
+ return branch
215
+ # Not a git repository or no branch
216
+ self._git_branch_cache[cache_key] = "Unknown"
217
+ self._git_branch_cache_time[cache_key] = current_time
218
+ return "Unknown"
219
+
220
+ except (
221
+ subprocess.TimeoutExpired,
222
+ subprocess.CalledProcessError,
223
+ FileNotFoundError,
224
+ OSError,
225
+ ):
226
+ # Git not available or command failed
227
+ self._git_branch_cache[cache_key] = "Unknown"
228
+ self._git_branch_cache_time[cache_key] = current_time
229
+ return "Unknown"
230
+
231
+ def find_matching_request(self, session_id: str) -> Optional[dict]:
232
+ """Find matching request data for a session, with fuzzy matching fallback."""
233
+ # First try exact match
234
+ request_info = self.delegation_requests.get(session_id)
235
+
236
+ # If exact match fails, try partial matching
237
+ if not request_info and session_id:
238
+ if DEBUG:
239
+ import sys
240
+
241
+ print(
242
+ f" - Trying fuzzy match for session {session_id[:16]}...",
243
+ file=sys.stderr,
244
+ )
245
+ # Try to find a session that matches the first 8-16 characters
246
+ for stored_sid in list(self.delegation_requests.keys()):
247
+ if (
248
+ stored_sid.startswith(session_id[:8])
249
+ or session_id.startswith(stored_sid[:8])
250
+ or (
251
+ len(session_id) >= 16
252
+ and len(stored_sid) >= 16
253
+ and stored_sid[:16] == session_id[:16]
254
+ )
255
+ ):
256
+ if DEBUG:
257
+ import sys
258
+
259
+ print(
260
+ f" - ✅ Fuzzy match found: {stored_sid[:16]}...",
261
+ file=sys.stderr,
262
+ )
263
+ request_info = self.delegation_requests.get(stored_sid)
264
+ # Update the key to use the current session_id for consistency
265
+ if request_info:
266
+ self.delegation_requests[session_id] = request_info
267
+ # Optionally remove the old key to avoid duplicates
268
+ if stored_sid != session_id:
269
+ del self.delegation_requests[stored_sid]
270
+ break
271
+
272
+ return request_info
273
+
274
+ def remove_request(self, session_id: str):
275
+ """Remove request data for a session."""
276
+ if session_id in self.delegation_requests:
277
+ del self.delegation_requests[session_id]
278
+
279
+ def increment_events_processed(self) -> bool:
280
+ """Increment events processed counter and return True if cleanup is needed."""
281
+ self.events_processed += 1
282
+ return self.events_processed % self.CLEANUP_INTERVAL_EVENTS == 0