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
@@ -9,7 +9,7 @@ import os
9
9
  from pathlib import Path
10
10
  from typing import Any, Dict, Optional
11
11
 
12
- from ....core.typing_utils import EventData, PathLike, SocketId
12
+ from ....core.typing_utils import EventData
13
13
  from ....core.unified_paths import get_project_root
14
14
  from .base import BaseEventHandler
15
15
 
@@ -156,7 +156,7 @@ class FileEventHandler(BaseEventHandler):
156
156
 
157
157
  # Read file content
158
158
  try:
159
- with open(real_path, "r", encoding="utf-8") as f:
159
+ with open(real_path, encoding="utf-8") as f:
160
160
  content = f.read()
161
161
 
162
162
  # Get file extension for syntax highlighting hint
@@ -203,17 +203,16 @@ class FileEventHandler(BaseEventHandler):
203
203
  "file_path": file_path,
204
204
  "file_size": file_size,
205
205
  }
206
- else:
207
- # Text file with different encoding
208
- ext = real_path.suffix
209
- return {
210
- "success": True,
211
- "file_path": file_path,
212
- "content": text_content,
213
- "file_size": file_size,
214
- "extension": ext.lower(),
215
- "encoding": "latin-1",
216
- }
206
+ # Text file with different encoding
207
+ ext = real_path.suffix
208
+ return {
209
+ "success": True,
210
+ "file_path": file_path,
211
+ "content": text_content,
212
+ "file_size": file_size,
213
+ "extension": ext.lower(),
214
+ "encoding": "latin-1",
215
+ }
217
216
  except Exception:
218
217
  return {
219
218
  "success": False,
@@ -223,6 +222,6 @@ class FileEventHandler(BaseEventHandler):
223
222
  except Exception as read_error:
224
223
  return {
225
224
  "success": False,
226
- "error": f"Failed to read file: {str(read_error)}",
225
+ "error": f"Failed to read file: {read_error!s}",
227
226
  "file_path": file_path,
228
227
  }
@@ -10,9 +10,8 @@ import os
10
10
  import subprocess
11
11
  from datetime import datetime
12
12
  from pathlib import Path
13
- from typing import Any, Dict, List, Optional
13
+ from typing import Any, Dict, Optional
14
14
 
15
- from ....core.typing_utils import EventData, PathLike, SocketId
16
15
  from .base import BaseEventHandler
17
16
 
18
17
 
@@ -53,6 +52,7 @@ class GitEventHandler(BaseEventHandler):
53
52
  cwd=working_dir,
54
53
  capture_output=True,
55
54
  text=True,
55
+ check=False,
56
56
  )
57
57
 
58
58
  # Debug: Git command completed
@@ -125,6 +125,7 @@ class GitEventHandler(BaseEventHandler):
125
125
  ["git", "-C", working_dir, "ls-files", "--", file_path],
126
126
  capture_output=True,
127
127
  text=True,
128
+ check=False,
128
129
  )
129
130
 
130
131
  is_tracked = result.returncode == 0 and result.stdout.strip()
@@ -318,6 +319,7 @@ class GitEventHandler(BaseEventHandler):
318
319
  ["git", "-C", working_dir, "add", file_path],
319
320
  capture_output=True,
320
321
  text=True,
322
+ check=False,
321
323
  )
322
324
 
323
325
  # Debug: Git add completed
@@ -389,7 +391,7 @@ class GitEventHandler(BaseEventHandler):
389
391
  ):
390
392
  working_dir = os.getcwd()
391
393
  self.logger.info(
392
- f"[{operation}] working_dir was invalid ({repr(original_working_dir)}), using cwd: {working_dir}"
394
+ f"[{operation}] working_dir was invalid ({original_working_dir!r}), using cwd: {working_dir}"
393
395
  )
394
396
  else:
395
397
  self.logger.info(f"[{operation}] Using provided working_dir: {working_dir}")
@@ -424,7 +426,7 @@ class GitEventHandler(BaseEventHandler):
424
426
  response_event,
425
427
  {
426
428
  "success": False,
427
- "error": f"Directory not found",
429
+ "error": "Directory not found",
428
430
  "working_dir": working_dir,
429
431
  "detail": f"Path does not exist: {working_dir}",
430
432
  },
@@ -440,7 +442,7 @@ class GitEventHandler(BaseEventHandler):
440
442
  response_event,
441
443
  {
442
444
  "success": False,
443
- "error": f"Not a directory",
445
+ "error": "Not a directory",
444
446
  "working_dir": working_dir,
445
447
  "detail": f"Path is not a directory: {working_dir}",
446
448
  },
@@ -529,6 +531,7 @@ class GitEventHandler(BaseEventHandler):
529
531
  ["git", "-C", working_dir, "rev-parse", "--git-dir"],
530
532
  capture_output=True,
531
533
  text=True,
534
+ check=False,
532
535
  )
533
536
  return git_check.returncode == 0
534
537
 
@@ -543,6 +546,7 @@ class GitEventHandler(BaseEventHandler):
543
546
  ["git", "-C", working_dir, "rev-parse", "--show-toplevel"],
544
547
  capture_output=True,
545
548
  text=True,
549
+ check=False,
546
550
  )
547
551
 
548
552
  if git_root_result.returncode == 0:
@@ -570,6 +574,7 @@ class GitEventHandler(BaseEventHandler):
570
574
  ["git", "-C", working_dir, "status", "--porcelain", file_path],
571
575
  capture_output=True,
572
576
  text=True,
577
+ check=False,
573
578
  )
574
579
 
575
580
  # Check if file is tracked by git
@@ -577,6 +582,7 @@ class GitEventHandler(BaseEventHandler):
577
582
  ["git", "-C", working_dir, "ls-files", file_path],
578
583
  capture_output=True,
579
584
  text=True,
585
+ check=False,
580
586
  )
581
587
 
582
588
  is_tracked = ls_files_result.returncode == 0 and ls_files_result.stdout.strip()
@@ -633,7 +639,6 @@ class GitEventHandler(BaseEventHandler):
633
639
  )
634
640
 
635
641
  # Handle case where working_dir is None, empty string, or 'Unknown'
636
- original_working_dir = working_dir
637
642
  if not working_dir or working_dir == "Unknown" or working_dir.strip() == "":
638
643
  working_dir = os.getcwd()
639
644
  # Debug: working_dir was invalid, using cwd
@@ -952,6 +957,6 @@ class GitEventHandler(BaseEventHandler):
952
957
  self.logger.error(f"Error in generate_git_diff: {e}")
953
958
  return {
954
959
  "success": False,
955
- "error": f"Git diff generation failed: {str(e)}",
960
+ "error": f"Git diff generation failed: {e!s}",
956
961
  "file_path": file_path,
957
962
  }
@@ -5,48 +5,47 @@ agent delegations, and other hook-based activity for the system heartbeat.
5
5
  """
6
6
 
7
7
  from datetime import datetime
8
- from typing import Any, Dict, Optional
8
+ from typing import Any, Dict
9
9
 
10
10
  from .base import BaseEventHandler
11
11
 
12
12
 
13
13
  class HookEventHandler(BaseEventHandler):
14
14
  """Handles hook events from Claude for session tracking.
15
-
15
+
16
16
  WHY: Hook events provide rich information about Claude's activity including
17
17
  session starts/stops, agent delegations, and tool usage. This handler
18
18
  extracts session information to populate the system heartbeat data.
19
19
  """
20
-
20
+
21
21
  def register_events(self) -> None:
22
22
  """Register hook event handlers.
23
-
23
+
24
24
  NOTE: This handler no longer registers a claude_event handler directly
25
25
  to avoid conflicts with ConnectionEventHandler. Instead, it processes
26
26
  hook events passed from ConnectionEventHandler.
27
27
  """
28
28
  # No direct event registration - events are passed from ConnectionEventHandler
29
- pass
30
-
29
+
31
30
  async def process_hook_event(self, data: Dict[str, Any]) -> None:
32
31
  """Process a hook event received from ConnectionEventHandler.
33
-
32
+
34
33
  WHY: This method is called by ConnectionEventHandler when it receives
35
34
  a claude_event with type starting with 'hook.'. This separation avoids handler conflicts.
36
-
35
+
37
36
  Args:
38
37
  data: The complete event data including type, timestamp, and data fields
39
38
  """
40
39
  if not isinstance(data, dict):
41
40
  return
42
-
41
+
43
42
  # Extract hook event details
44
43
  # Hook events can come in two formats:
45
44
  # 1. Normalized: { type: "hook", subtype: "user_prompt", ... }
46
45
  # 2. Legacy: { type: "hook.user_prompt", ... }
47
46
  event_type = data.get("type", "")
48
47
  event_subtype = data.get("subtype", "")
49
-
48
+
50
49
  # Determine the actual hook event name
51
50
  hook_event = ""
52
51
  if event_type == "hook" and event_subtype:
@@ -58,26 +57,26 @@ class HookEventHandler(BaseEventHandler):
58
57
  else:
59
58
  # Fallback: check for 'event' field (another legacy format)
60
59
  hook_event = data.get("event", "")
61
-
60
+
62
61
  hook_data = data.get("data", {})
63
-
62
+
64
63
  # Create properly formatted event for history
65
64
  # Note: add_to_history expects the event data directly, not wrapped
66
65
  history_event = {
67
66
  "type": "hook",
68
67
  "event": hook_event,
69
68
  "data": hook_data,
70
- "timestamp": data.get("timestamp") or datetime.now().isoformat()
69
+ "timestamp": data.get("timestamp") or datetime.now().isoformat(),
71
70
  }
72
-
71
+
73
72
  # Add the event to history for replay
74
73
  # The base handler's add_to_history will wrap it properly
75
74
  self.event_history.append(history_event)
76
-
75
+
77
76
  # Broadcast the original event to all connected clients
78
77
  # (preserves all original fields)
79
78
  await self.broadcast_event("claude_event", data)
80
-
79
+
81
80
  # Track sessions based on hook events
82
81
  if hook_event == "subagent_start":
83
82
  await self._handle_subagent_start(hook_data)
@@ -87,23 +86,23 @@ class HookEventHandler(BaseEventHandler):
87
86
  await self._handle_user_prompt(hook_data)
88
87
  elif hook_event == "pre_tool":
89
88
  await self._handle_pre_tool(hook_data)
90
-
89
+
91
90
  self.logger.debug(f"Processed hook event: {hook_event}")
92
-
91
+
93
92
  async def _handle_subagent_start(self, data: Dict[str, Any]):
94
93
  """Handle subagent start events.
95
-
94
+
96
95
  WHY: When a subagent starts, we track it as an active session
97
96
  with the agent type and start time for the heartbeat.
98
97
  """
99
98
  session_id = data.get("session_id")
100
99
  agent_type = data.get("agent_type", "unknown")
101
-
100
+
102
101
  if not session_id:
103
102
  return
104
-
103
+
105
104
  # Update or create session tracking
106
- if hasattr(self.server, 'active_sessions'):
105
+ if hasattr(self.server, "active_sessions"):
107
106
  self.server.active_sessions[session_id] = {
108
107
  "session_id": session_id,
109
108
  "start_time": datetime.now().isoformat(),
@@ -112,46 +111,48 @@ class HookEventHandler(BaseEventHandler):
112
111
  "prompt": data.get("prompt", "")[:100], # First 100 chars
113
112
  "last_activity": datetime.now().isoformat(),
114
113
  }
115
-
114
+
116
115
  self.logger.debug(
117
116
  f"Tracked subagent start: session={session_id[:8]}..., agent={agent_type}"
118
117
  )
119
-
118
+
120
119
  async def _handle_subagent_stop(self, data: Dict[str, Any]):
121
120
  """Handle subagent stop events.
122
-
121
+
123
122
  WHY: When a subagent stops, we update its status or remove it
124
123
  from active sessions depending on the stop reason.
125
124
  """
126
125
  session_id = data.get("session_id")
127
-
126
+
128
127
  if not session_id:
129
128
  return
130
-
129
+
131
130
  # Update session status
132
- if hasattr(self.server, 'active_sessions'):
131
+ if hasattr(self.server, "active_sessions"):
133
132
  if session_id in self.server.active_sessions:
134
133
  # Mark as completed rather than removing immediately
135
134
  self.server.active_sessions[session_id]["status"] = "completed"
136
- self.server.active_sessions[session_id]["last_activity"] = datetime.now().isoformat()
137
-
135
+ self.server.active_sessions[session_id][
136
+ "last_activity"
137
+ ] = datetime.now().isoformat()
138
+
138
139
  self.logger.debug(
139
140
  f"Marked session completed: session={session_id[:8]}..."
140
141
  )
141
-
142
+
142
143
  async def _handle_user_prompt(self, data: Dict[str, Any]):
143
144
  """Handle user prompt events.
144
-
145
+
145
146
  WHY: User prompts indicate the start of a new interaction,
146
147
  which we track as a PM session if no delegation occurs.
147
148
  """
148
149
  session_id = data.get("session_id")
149
-
150
+
150
151
  if not session_id:
151
152
  return
152
-
153
+
153
154
  # Create or update PM session
154
- if hasattr(self.server, 'active_sessions'):
155
+ if hasattr(self.server, "active_sessions"):
155
156
  if session_id not in self.server.active_sessions:
156
157
  self.server.active_sessions[session_id] = {
157
158
  "session_id": session_id,
@@ -164,31 +165,35 @@ class HookEventHandler(BaseEventHandler):
164
165
  }
165
166
  else:
166
167
  # Update last activity
167
- self.server.active_sessions[session_id]["last_activity"] = datetime.now().isoformat()
168
-
168
+ self.server.active_sessions[session_id][
169
+ "last_activity"
170
+ ] = datetime.now().isoformat()
171
+
169
172
  async def _handle_pre_tool(self, data: Dict[str, Any]):
170
173
  """Handle pre-tool events.
171
-
174
+
172
175
  WHY: Pre-tool events with Task delegation indicate agent changes
173
176
  that we need to track for accurate session information.
174
177
  """
175
178
  if data.get("tool_name") != "Task":
176
179
  return
177
-
180
+
178
181
  session_id = data.get("session_id")
179
182
  delegation_details = data.get("delegation_details", {})
180
183
  agent_type = delegation_details.get("agent_type", "unknown")
181
-
184
+
182
185
  if not session_id:
183
186
  return
184
-
187
+
185
188
  # Update session with new agent
186
- if hasattr(self.server, 'active_sessions'):
189
+ if hasattr(self.server, "active_sessions"):
187
190
  if session_id in self.server.active_sessions:
188
191
  self.server.active_sessions[session_id]["agent"] = agent_type
189
192
  self.server.active_sessions[session_id]["status"] = "delegated"
190
- self.server.active_sessions[session_id]["last_activity"] = datetime.now().isoformat()
191
-
193
+ self.server.active_sessions[session_id][
194
+ "last_activity"
195
+ ] = datetime.now().isoformat()
196
+
192
197
  self.logger.debug(
193
198
  f"Updated session delegation: session={session_id[:8]}..., agent={agent_type}"
194
199
  )
@@ -24,4 +24,3 @@ class MemoryEventHandler(BaseEventHandler):
24
24
  """
25
25
  # Future memory management events will be registered here
26
26
  # For example: query_memory, clear_memory, export_memory, etc.
27
- pass
@@ -22,4 +22,3 @@ class ProjectEventHandler(BaseEventHandler):
22
22
  handler is ready for future expansion.
23
23
  """
24
24
  # Future project events will be registered here
25
- pass
@@ -5,13 +5,14 @@ providing a clean interface for the SocketIOServer to register all
5
5
  events without knowing the details of each handler.
6
6
  """
7
7
 
8
- from logging import Logger
9
8
  from typing import TYPE_CHECKING, List, Optional, Type
10
9
 
11
10
  from ....core.logger import get_logger
12
11
  from .base import BaseEventHandler
13
12
 
14
13
  if TYPE_CHECKING:
14
+ from logging import Logger
15
+
15
16
  from ..server import SocketIOServer
16
17
 
17
18
  from .connection import ConnectionEventHandler
@@ -46,7 +47,7 @@ class EventHandlerRegistry:
46
47
  Args:
47
48
  server: The SocketIOServer instance
48
49
  """
49
- self.server: "SocketIOServer" = server
50
+ self.server: SocketIOServer = server
50
51
  self.logger: Logger = get_logger("EventHandlerRegistry")
51
52
  self.handlers: List[BaseEventHandler] = []
52
53
  self._initialized: bool = False
@@ -73,8 +74,11 @@ class EventHandlerRegistry:
73
74
  # Add debug logging for deployment context
74
75
  try:
75
76
  from ....core.unified_paths import PathContext
77
+
76
78
  deployment_context = PathContext.detect_deployment_context()
77
- self.logger.info(f"Initializing event handlers in {deployment_context.value} mode")
79
+ self.logger.info(
80
+ f"Initializing event handlers in {deployment_context.value} mode"
81
+ )
78
82
  except Exception as e:
79
83
  self.logger.debug(f"Could not detect deployment context: {e}")
80
84
 
@@ -88,7 +92,9 @@ class EventHandlerRegistry:
88
92
  self.handlers.append(handler)
89
93
  self.logger.info(f"✅ Initialized handler: {handler_class.__name__}")
90
94
  except Exception as e:
91
- self.logger.error(f"❌ Failed to initialize {handler_class.__name__}: {e}")
95
+ self.logger.error(
96
+ f"❌ Failed to initialize {handler_class.__name__}: {e}"
97
+ )
92
98
  import traceback
93
99
 
94
100
  self.logger.error(f"Stack trace: {traceback.format_exc()}")
@@ -107,31 +113,43 @@ class EventHandlerRegistry:
107
113
  self.logger.error("Registry not initialized. Call initialize() first.")
108
114
  raise RuntimeError("EventHandlerRegistry not initialized")
109
115
 
110
- self.logger.info(f"🔄 Starting event registration for {len(self.handlers)} handlers")
111
-
116
+ self.logger.info(
117
+ f"🔄 Starting event registration for {len(self.handlers)} handlers"
118
+ )
119
+
112
120
  # Verify Socket.IO server is available
113
- if not hasattr(self.server, 'core') or not self.server.core or not self.server.core.sio:
114
- self.logger.error("❌ Socket.IO server instance not available for event registration")
121
+ if (
122
+ not hasattr(self.server, "core")
123
+ or not self.server.core
124
+ or not self.server.core.sio
125
+ ):
126
+ self.logger.error(
127
+ "❌ Socket.IO server instance not available for event registration"
128
+ )
115
129
  raise RuntimeError("Socket.IO server not available")
116
-
130
+
117
131
  self.logger.debug(f"Socket.IO server available: {type(self.server.core.sio)}")
118
132
 
119
133
  registered_count = 0
120
134
  for handler in self.handlers:
121
135
  try:
122
- self.logger.debug(f"Registering events for {handler.__class__.__name__}")
123
-
136
+ self.logger.debug(
137
+ f"Registering events for {handler.__class__.__name__}"
138
+ )
139
+
124
140
  # Get the number of registered events before and after
125
- sio_events_before = len(getattr(self.server.core.sio, 'handlers', {}))
126
-
141
+ sio_events_before = len(getattr(self.server.core.sio, "handlers", {}))
142
+
127
143
  handler.register_events()
128
-
129
- sio_events_after = len(getattr(self.server.core.sio, 'handlers', {}))
144
+
145
+ sio_events_after = len(getattr(self.server.core.sio, "handlers", {}))
130
146
  events_added = sio_events_after - sio_events_before
131
-
147
+
132
148
  registered_count += 1
133
- self.logger.info(f"✅ Registered {events_added} events for {handler.__class__.__name__}")
134
-
149
+ self.logger.info(
150
+ f"✅ Registered {events_added} events for {handler.__class__.__name__}"
151
+ )
152
+
135
153
  except NotImplementedError:
136
154
  # Handler has no events to register (like ProjectEventHandler)
137
155
  self.logger.debug(
@@ -146,7 +164,7 @@ class EventHandlerRegistry:
146
164
  self.logger.error(f"Stack trace: {traceback.format_exc()}")
147
165
 
148
166
  # Final verification
149
- total_sio_events = len(getattr(self.server.core.sio, 'handlers', {}))
167
+ total_sio_events = len(getattr(self.server.core.sio, "handlers", {}))
150
168
  self.logger.info(
151
169
  f"🎉 Event registration complete: {registered_count} handlers processed, "
152
170
  f"{total_sio_events} total Socket.IO events registered"