claude-mpm 4.1.0__py3-none-any.whl → 4.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (358) hide show
  1. claude_mpm/BUILD_NUMBER +1 -1
  2. claude_mpm/VERSION +1 -1
  3. claude_mpm/__main__.py +1 -1
  4. claude_mpm/agents/BASE_PM.md +74 -46
  5. claude_mpm/agents/INSTRUCTIONS.md +11 -153
  6. claude_mpm/agents/WORKFLOW.md +61 -321
  7. claude_mpm/agents/__init__.py +11 -11
  8. claude_mpm/agents/agent_loader.py +23 -20
  9. claude_mpm/agents/agent_loader_integration.py +1 -1
  10. claude_mpm/agents/agents_metadata.py +27 -0
  11. claude_mpm/agents/async_agent_loader.py +5 -8
  12. claude_mpm/agents/base_agent_loader.py +36 -25
  13. claude_mpm/agents/frontmatter_validator.py +6 -6
  14. claude_mpm/agents/schema/agent_schema.json +1 -1
  15. claude_mpm/agents/system_agent_config.py +9 -9
  16. claude_mpm/agents/templates/api_qa.json +47 -2
  17. claude_mpm/agents/templates/imagemagick.json +256 -0
  18. claude_mpm/agents/templates/qa.json +41 -2
  19. claude_mpm/agents/templates/ticketing.json +5 -5
  20. claude_mpm/agents/templates/web_qa.json +133 -58
  21. claude_mpm/agents/templates/web_ui.json +3 -3
  22. claude_mpm/cli/__init__.py +51 -46
  23. claude_mpm/cli/__main__.py +1 -1
  24. claude_mpm/cli/commands/__init__.py +10 -12
  25. claude_mpm/cli/commands/agent_manager.py +186 -181
  26. claude_mpm/cli/commands/agents.py +271 -268
  27. claude_mpm/cli/commands/aggregate.py +30 -29
  28. claude_mpm/cli/commands/cleanup.py +50 -44
  29. claude_mpm/cli/commands/cleanup_orphaned_agents.py +25 -25
  30. claude_mpm/cli/commands/config.py +162 -127
  31. claude_mpm/cli/commands/doctor.py +52 -62
  32. claude_mpm/cli/commands/info.py +37 -25
  33. claude_mpm/cli/commands/mcp.py +3 -7
  34. claude_mpm/cli/commands/mcp_command_router.py +14 -18
  35. claude_mpm/cli/commands/mcp_install_commands.py +28 -23
  36. claude_mpm/cli/commands/mcp_pipx_config.py +58 -49
  37. claude_mpm/cli/commands/mcp_server_commands.py +23 -17
  38. claude_mpm/cli/commands/memory.py +192 -141
  39. claude_mpm/cli/commands/monitor.py +117 -88
  40. claude_mpm/cli/commands/run.py +120 -84
  41. claude_mpm/cli/commands/run_config_checker.py +4 -5
  42. claude_mpm/cli/commands/socketio_monitor.py +17 -19
  43. claude_mpm/cli/commands/tickets.py +92 -92
  44. claude_mpm/cli/parser.py +1 -5
  45. claude_mpm/cli/parsers/__init__.py +1 -1
  46. claude_mpm/cli/parsers/agent_manager_parser.py +50 -98
  47. claude_mpm/cli/parsers/agents_parser.py +2 -3
  48. claude_mpm/cli/parsers/base_parser.py +7 -5
  49. claude_mpm/cli/parsers/mcp_parser.py +4 -2
  50. claude_mpm/cli/parsers/monitor_parser.py +26 -18
  51. claude_mpm/cli/shared/__init__.py +10 -10
  52. claude_mpm/cli/shared/argument_patterns.py +57 -71
  53. claude_mpm/cli/shared/base_command.py +61 -53
  54. claude_mpm/cli/shared/error_handling.py +62 -58
  55. claude_mpm/cli/shared/output_formatters.py +78 -77
  56. claude_mpm/cli/startup_logging.py +204 -172
  57. claude_mpm/cli/utils.py +10 -11
  58. claude_mpm/cli_module/__init__.py +1 -1
  59. claude_mpm/cli_module/args.py +1 -1
  60. claude_mpm/cli_module/migration_example.py +5 -5
  61. claude_mpm/config/__init__.py +9 -9
  62. claude_mpm/config/agent_config.py +15 -14
  63. claude_mpm/config/experimental_features.py +4 -4
  64. claude_mpm/config/paths.py +0 -1
  65. claude_mpm/config/socketio_config.py +5 -6
  66. claude_mpm/constants.py +1 -2
  67. claude_mpm/core/__init__.py +8 -8
  68. claude_mpm/core/agent_name_normalizer.py +1 -1
  69. claude_mpm/core/agent_registry.py +20 -23
  70. claude_mpm/core/agent_session_manager.py +3 -3
  71. claude_mpm/core/base_service.py +7 -15
  72. claude_mpm/core/cache.py +4 -6
  73. claude_mpm/core/claude_runner.py +85 -113
  74. claude_mpm/core/config.py +43 -28
  75. claude_mpm/core/config_aliases.py +0 -9
  76. claude_mpm/core/config_constants.py +52 -30
  77. claude_mpm/core/constants.py +0 -1
  78. claude_mpm/core/container.py +18 -27
  79. claude_mpm/core/exceptions.py +2 -2
  80. claude_mpm/core/factories.py +10 -12
  81. claude_mpm/core/framework_loader.py +581 -280
  82. claude_mpm/core/hook_manager.py +26 -22
  83. claude_mpm/core/hook_performance_config.py +58 -47
  84. claude_mpm/core/injectable_service.py +1 -1
  85. claude_mpm/core/interactive_session.py +61 -152
  86. claude_mpm/core/interfaces.py +1 -100
  87. claude_mpm/core/lazy.py +5 -5
  88. claude_mpm/core/log_manager.py +587 -0
  89. claude_mpm/core/logger.py +125 -8
  90. claude_mpm/core/logging_config.py +15 -15
  91. claude_mpm/core/minimal_framework_loader.py +5 -8
  92. claude_mpm/core/oneshot_session.py +15 -33
  93. claude_mpm/core/optimized_agent_loader.py +4 -6
  94. claude_mpm/core/optimized_startup.py +2 -1
  95. claude_mpm/core/output_style_manager.py +147 -106
  96. claude_mpm/core/pm_hook_interceptor.py +0 -1
  97. claude_mpm/core/service_registry.py +11 -8
  98. claude_mpm/core/session_manager.py +1 -2
  99. claude_mpm/core/shared/__init__.py +1 -1
  100. claude_mpm/core/shared/config_loader.py +101 -97
  101. claude_mpm/core/shared/path_resolver.py +72 -68
  102. claude_mpm/core/shared/singleton_manager.py +56 -50
  103. claude_mpm/core/socketio_pool.py +26 -6
  104. claude_mpm/core/tool_access_control.py +4 -5
  105. claude_mpm/core/typing_utils.py +50 -59
  106. claude_mpm/core/unified_agent_registry.py +14 -19
  107. claude_mpm/core/unified_config.py +4 -6
  108. claude_mpm/core/unified_paths.py +197 -109
  109. claude_mpm/dashboard/open_dashboard.py +2 -4
  110. claude_mpm/experimental/cli_enhancements.py +51 -36
  111. claude_mpm/generators/agent_profile_generator.py +2 -4
  112. claude_mpm/hooks/base_hook.py +1 -2
  113. claude_mpm/hooks/claude_hooks/connection_pool.py +72 -26
  114. claude_mpm/hooks/claude_hooks/event_handlers.py +93 -38
  115. claude_mpm/hooks/claude_hooks/hook_handler.py +130 -76
  116. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
  117. claude_mpm/hooks/claude_hooks/memory_integration.py +2 -4
  118. claude_mpm/hooks/claude_hooks/response_tracking.py +15 -11
  119. claude_mpm/hooks/claude_hooks/tool_analysis.py +12 -18
  120. claude_mpm/hooks/memory_integration_hook.py +5 -5
  121. claude_mpm/hooks/tool_call_interceptor.py +1 -1
  122. claude_mpm/hooks/validation_hooks.py +4 -4
  123. claude_mpm/init.py +4 -9
  124. claude_mpm/models/__init__.py +2 -2
  125. claude_mpm/models/agent_session.py +11 -14
  126. claude_mpm/scripts/mcp_server.py +20 -11
  127. claude_mpm/scripts/mcp_wrapper.py +5 -5
  128. claude_mpm/scripts/mpm_doctor.py +321 -0
  129. claude_mpm/scripts/socketio_daemon.py +28 -25
  130. claude_mpm/scripts/socketio_daemon_hardened.py +298 -258
  131. claude_mpm/scripts/socketio_server_manager.py +116 -95
  132. claude_mpm/services/__init__.py +49 -49
  133. claude_mpm/services/agent_capabilities_service.py +12 -18
  134. claude_mpm/services/agents/__init__.py +22 -22
  135. claude_mpm/services/agents/agent_builder.py +140 -119
  136. claude_mpm/services/agents/deployment/__init__.py +3 -3
  137. claude_mpm/services/agents/deployment/agent_config_provider.py +9 -9
  138. claude_mpm/services/agents/deployment/agent_configuration_manager.py +19 -20
  139. claude_mpm/services/agents/deployment/agent_definition_factory.py +1 -5
  140. claude_mpm/services/agents/deployment/agent_deployment.py +136 -106
  141. claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -8
  142. claude_mpm/services/agents/deployment/agent_environment_manager.py +2 -7
  143. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +6 -10
  144. claude_mpm/services/agents/deployment/agent_format_converter.py +11 -15
  145. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +2 -3
  146. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -5
  147. claude_mpm/services/agents/deployment/agent_metrics_collector.py +13 -19
  148. claude_mpm/services/agents/deployment/agent_restore_handler.py +0 -1
  149. claude_mpm/services/agents/deployment/agent_template_builder.py +26 -35
  150. claude_mpm/services/agents/deployment/agent_validator.py +0 -1
  151. claude_mpm/services/agents/deployment/agent_version_manager.py +7 -9
  152. claude_mpm/services/agents/deployment/agent_versioning.py +3 -3
  153. claude_mpm/services/agents/deployment/agents_directory_resolver.py +6 -7
  154. claude_mpm/services/agents/deployment/async_agent_deployment.py +51 -38
  155. claude_mpm/services/agents/deployment/config/__init__.py +1 -1
  156. claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
  157. claude_mpm/services/agents/deployment/deployment_type_detector.py +1 -1
  158. claude_mpm/services/agents/deployment/deployment_wrapper.py +18 -18
  159. claude_mpm/services/agents/deployment/facade/__init__.py +1 -1
  160. claude_mpm/services/agents/deployment/facade/deployment_executor.py +0 -3
  161. claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -4
  162. claude_mpm/services/agents/deployment/interface_adapter.py +5 -7
  163. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +345 -276
  164. claude_mpm/services/agents/deployment/pipeline/__init__.py +2 -2
  165. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +1 -1
  166. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +6 -4
  167. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +3 -3
  168. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +2 -2
  169. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +14 -13
  170. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +0 -1
  171. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +1 -1
  172. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +8 -9
  173. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +1 -1
  174. claude_mpm/services/agents/deployment/processors/__init__.py +1 -1
  175. claude_mpm/services/agents/deployment/processors/agent_processor.py +20 -16
  176. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +5 -12
  177. claude_mpm/services/agents/deployment/results/__init__.py +1 -1
  178. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +1 -1
  179. claude_mpm/services/agents/deployment/strategies/__init__.py +2 -2
  180. claude_mpm/services/agents/deployment/strategies/base_strategy.py +1 -7
  181. claude_mpm/services/agents/deployment/strategies/project_strategy.py +1 -4
  182. claude_mpm/services/agents/deployment/strategies/system_strategy.py +2 -3
  183. claude_mpm/services/agents/deployment/strategies/user_strategy.py +3 -7
  184. claude_mpm/services/agents/deployment/validation/__init__.py +1 -1
  185. claude_mpm/services/agents/deployment/validation/agent_validator.py +1 -1
  186. claude_mpm/services/agents/deployment/validation/template_validator.py +2 -2
  187. claude_mpm/services/agents/deployment/validation/validation_result.py +2 -6
  188. claude_mpm/services/agents/loading/__init__.py +1 -1
  189. claude_mpm/services/agents/loading/agent_profile_loader.py +6 -12
  190. claude_mpm/services/agents/loading/base_agent_manager.py +5 -5
  191. claude_mpm/services/agents/loading/framework_agent_loader.py +2 -4
  192. claude_mpm/services/agents/management/__init__.py +1 -1
  193. claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -3
  194. claude_mpm/services/agents/management/agent_management_service.py +5 -9
  195. claude_mpm/services/agents/memory/__init__.py +4 -4
  196. claude_mpm/services/agents/memory/agent_memory_manager.py +280 -160
  197. claude_mpm/services/agents/memory/agent_persistence_service.py +0 -2
  198. claude_mpm/services/agents/memory/content_manager.py +44 -38
  199. claude_mpm/services/agents/memory/template_generator.py +4 -6
  200. claude_mpm/services/agents/registry/__init__.py +10 -6
  201. claude_mpm/services/agents/registry/deployed_agent_discovery.py +30 -27
  202. claude_mpm/services/agents/registry/modification_tracker.py +3 -6
  203. claude_mpm/services/async_session_logger.py +1 -2
  204. claude_mpm/services/claude_session_logger.py +1 -2
  205. claude_mpm/services/command_deployment_service.py +173 -0
  206. claude_mpm/services/command_handler_service.py +20 -22
  207. claude_mpm/services/core/__init__.py +25 -25
  208. claude_mpm/services/core/base.py +0 -5
  209. claude_mpm/services/core/interfaces/__init__.py +32 -32
  210. claude_mpm/services/core/interfaces/agent.py +0 -21
  211. claude_mpm/services/core/interfaces/communication.py +0 -27
  212. claude_mpm/services/core/interfaces/infrastructure.py +0 -56
  213. claude_mpm/services/core/interfaces/service.py +0 -29
  214. claude_mpm/services/diagnostics/__init__.py +1 -1
  215. claude_mpm/services/diagnostics/checks/__init__.py +6 -6
  216. claude_mpm/services/diagnostics/checks/agent_check.py +89 -80
  217. claude_mpm/services/diagnostics/checks/base_check.py +12 -16
  218. claude_mpm/services/diagnostics/checks/claude_desktop_check.py +84 -81
  219. claude_mpm/services/diagnostics/checks/common_issues_check.py +99 -91
  220. claude_mpm/services/diagnostics/checks/configuration_check.py +82 -77
  221. claude_mpm/services/diagnostics/checks/filesystem_check.py +67 -68
  222. claude_mpm/services/diagnostics/checks/installation_check.py +254 -94
  223. claude_mpm/services/diagnostics/checks/mcp_check.py +90 -88
  224. claude_mpm/services/diagnostics/checks/monitor_check.py +75 -76
  225. claude_mpm/services/diagnostics/checks/startup_log_check.py +67 -73
  226. claude_mpm/services/diagnostics/diagnostic_runner.py +67 -59
  227. claude_mpm/services/diagnostics/doctor_reporter.py +107 -70
  228. claude_mpm/services/diagnostics/models.py +21 -19
  229. claude_mpm/services/event_aggregator.py +10 -17
  230. claude_mpm/services/event_bus/__init__.py +1 -1
  231. claude_mpm/services/event_bus/config.py +54 -35
  232. claude_mpm/services/event_bus/event_bus.py +76 -71
  233. claude_mpm/services/event_bus/relay.py +74 -64
  234. claude_mpm/services/events/__init__.py +11 -11
  235. claude_mpm/services/events/consumers/__init__.py +3 -3
  236. claude_mpm/services/events/consumers/dead_letter.py +71 -63
  237. claude_mpm/services/events/consumers/logging.py +39 -37
  238. claude_mpm/services/events/consumers/metrics.py +56 -57
  239. claude_mpm/services/events/consumers/socketio.py +82 -81
  240. claude_mpm/services/events/core.py +110 -99
  241. claude_mpm/services/events/interfaces.py +56 -72
  242. claude_mpm/services/events/producers/__init__.py +1 -1
  243. claude_mpm/services/events/producers/hook.py +38 -38
  244. claude_mpm/services/events/producers/system.py +46 -44
  245. claude_mpm/services/exceptions.py +81 -80
  246. claude_mpm/services/framework_claude_md_generator/__init__.py +2 -4
  247. claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -5
  248. claude_mpm/services/framework_claude_md_generator/content_validator.py +1 -1
  249. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +4 -4
  250. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -1
  251. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -2
  252. claude_mpm/services/framework_claude_md_generator/version_manager.py +4 -5
  253. claude_mpm/services/hook_service.py +6 -9
  254. claude_mpm/services/infrastructure/__init__.py +1 -1
  255. claude_mpm/services/infrastructure/context_preservation.py +8 -12
  256. claude_mpm/services/infrastructure/monitoring.py +21 -23
  257. claude_mpm/services/mcp_gateway/__init__.py +37 -37
  258. claude_mpm/services/mcp_gateway/auto_configure.py +95 -103
  259. claude_mpm/services/mcp_gateway/config/__init__.py +1 -1
  260. claude_mpm/services/mcp_gateway/config/config_loader.py +23 -25
  261. claude_mpm/services/mcp_gateway/config/config_schema.py +5 -5
  262. claude_mpm/services/mcp_gateway/config/configuration.py +9 -6
  263. claude_mpm/services/mcp_gateway/core/__init__.py +10 -10
  264. claude_mpm/services/mcp_gateway/core/base.py +0 -3
  265. claude_mpm/services/mcp_gateway/core/interfaces.py +1 -38
  266. claude_mpm/services/mcp_gateway/core/process_pool.py +99 -93
  267. claude_mpm/services/mcp_gateway/core/singleton_manager.py +65 -62
  268. claude_mpm/services/mcp_gateway/core/startup_verification.py +75 -74
  269. claude_mpm/services/mcp_gateway/main.py +2 -1
  270. claude_mpm/services/mcp_gateway/registry/service_registry.py +5 -8
  271. claude_mpm/services/mcp_gateway/registry/tool_registry.py +1 -1
  272. claude_mpm/services/mcp_gateway/server/__init__.py +1 -1
  273. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +12 -19
  274. claude_mpm/services/mcp_gateway/server/stdio_handler.py +4 -3
  275. claude_mpm/services/mcp_gateway/server/stdio_server.py +79 -71
  276. claude_mpm/services/mcp_gateway/tools/__init__.py +2 -2
  277. claude_mpm/services/mcp_gateway/tools/base_adapter.py +5 -6
  278. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +13 -22
  279. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +79 -78
  280. claude_mpm/services/mcp_gateway/tools/hello_world.py +12 -14
  281. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +42 -49
  282. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +51 -55
  283. claude_mpm/services/memory/__init__.py +3 -3
  284. claude_mpm/services/memory/builder.py +3 -6
  285. claude_mpm/services/memory/cache/__init__.py +1 -1
  286. claude_mpm/services/memory/cache/shared_prompt_cache.py +3 -5
  287. claude_mpm/services/memory/cache/simple_cache.py +1 -1
  288. claude_mpm/services/memory/indexed_memory.py +5 -7
  289. claude_mpm/services/memory/optimizer.py +7 -10
  290. claude_mpm/services/memory/router.py +8 -9
  291. claude_mpm/services/memory_hook_service.py +48 -34
  292. claude_mpm/services/monitor_build_service.py +77 -73
  293. claude_mpm/services/port_manager.py +130 -108
  294. claude_mpm/services/project/analyzer.py +12 -10
  295. claude_mpm/services/project/registry.py +11 -11
  296. claude_mpm/services/recovery_manager.py +10 -19
  297. claude_mpm/services/response_tracker.py +0 -1
  298. claude_mpm/services/runner_configuration_service.py +19 -20
  299. claude_mpm/services/session_management_service.py +7 -11
  300. claude_mpm/services/shared/__init__.py +1 -1
  301. claude_mpm/services/shared/async_service_base.py +58 -50
  302. claude_mpm/services/shared/config_service_base.py +73 -67
  303. claude_mpm/services/shared/lifecycle_service_base.py +82 -78
  304. claude_mpm/services/shared/manager_base.py +94 -82
  305. claude_mpm/services/shared/service_factory.py +96 -98
  306. claude_mpm/services/socketio/__init__.py +3 -3
  307. claude_mpm/services/socketio/client_proxy.py +5 -5
  308. claude_mpm/services/socketio/event_normalizer.py +199 -181
  309. claude_mpm/services/socketio/handlers/__init__.py +3 -3
  310. claude_mpm/services/socketio/handlers/base.py +5 -4
  311. claude_mpm/services/socketio/handlers/connection.py +163 -136
  312. claude_mpm/services/socketio/handlers/file.py +13 -14
  313. claude_mpm/services/socketio/handlers/git.py +12 -7
  314. claude_mpm/services/socketio/handlers/hook.py +49 -44
  315. claude_mpm/services/socketio/handlers/memory.py +0 -1
  316. claude_mpm/services/socketio/handlers/project.py +0 -1
  317. claude_mpm/services/socketio/handlers/registry.py +37 -19
  318. claude_mpm/services/socketio/migration_utils.py +98 -84
  319. claude_mpm/services/socketio/server/__init__.py +1 -1
  320. claude_mpm/services/socketio/server/broadcaster.py +81 -87
  321. claude_mpm/services/socketio/server/core.py +65 -54
  322. claude_mpm/services/socketio/server/eventbus_integration.py +95 -56
  323. claude_mpm/services/socketio/server/main.py +64 -38
  324. claude_mpm/services/socketio_client_manager.py +10 -12
  325. claude_mpm/services/subprocess_launcher_service.py +4 -7
  326. claude_mpm/services/system_instructions_service.py +13 -14
  327. claude_mpm/services/ticket_manager.py +2 -2
  328. claude_mpm/services/utility_service.py +5 -13
  329. claude_mpm/services/version_control/__init__.py +16 -16
  330. claude_mpm/services/version_control/branch_strategy.py +5 -8
  331. claude_mpm/services/version_control/conflict_resolution.py +9 -23
  332. claude_mpm/services/version_control/git_operations.py +5 -7
  333. claude_mpm/services/version_control/semantic_versioning.py +16 -17
  334. claude_mpm/services/version_control/version_parser.py +13 -18
  335. claude_mpm/services/version_service.py +10 -11
  336. claude_mpm/storage/__init__.py +1 -1
  337. claude_mpm/storage/state_storage.py +22 -28
  338. claude_mpm/utils/__init__.py +6 -6
  339. claude_mpm/utils/agent_dependency_loader.py +47 -33
  340. claude_mpm/utils/config_manager.py +11 -14
  341. claude_mpm/utils/dependency_cache.py +1 -1
  342. claude_mpm/utils/dependency_manager.py +13 -17
  343. claude_mpm/utils/dependency_strategies.py +8 -10
  344. claude_mpm/utils/environment_context.py +3 -9
  345. claude_mpm/utils/error_handler.py +3 -13
  346. claude_mpm/utils/file_utils.py +1 -1
  347. claude_mpm/utils/path_operations.py +8 -12
  348. claude_mpm/utils/robust_installer.py +110 -33
  349. claude_mpm/utils/subprocess_utils.py +5 -6
  350. claude_mpm/validation/agent_validator.py +3 -6
  351. claude_mpm/validation/frontmatter_validator.py +1 -1
  352. {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/METADATA +1 -1
  353. claude_mpm-4.1.2.dist-info/RECORD +498 -0
  354. claude_mpm-4.1.0.dist-info/RECORD +0 -494
  355. {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/WHEEL +0 -0
  356. {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/entry_points.txt +0 -0
  357. {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/licenses/LICENSE +0 -0
  358. {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/top_level.txt +0 -0
@@ -12,24 +12,24 @@ from ..logger import get_logger
12
12
  class PathResolver:
13
13
  """
14
14
  Centralized path resolution utility.
15
-
15
+
16
16
  Reduces duplication by providing standard patterns for:
17
17
  - Working directory resolution
18
18
  - Configuration directory discovery
19
19
  - Agent directory resolution
20
20
  - Memory directory resolution
21
21
  """
22
-
23
- def __init__(self, base_dir: Union[str, Path] = None):
22
+
23
+ def __init__(self, base_dir: Optional[Union[str, Path]] = None):
24
24
  """
25
25
  Initialize path resolver.
26
-
26
+
27
27
  Args:
28
28
  base_dir: Base directory for relative paths
29
29
  """
30
30
  self.base_dir = Path(base_dir) if base_dir else self._get_working_dir()
31
31
  self.logger = get_logger("path_resolver")
32
-
32
+
33
33
  def _get_working_dir(self) -> Path:
34
34
  """Get working directory respecting CLAUDE_MPM_USER_PWD."""
35
35
  # Use CLAUDE_MPM_USER_PWD if available (when called via shell script)
@@ -37,111 +37,113 @@ class PathResolver:
37
37
  if user_pwd:
38
38
  return Path(user_pwd)
39
39
  return Path.cwd()
40
-
40
+
41
41
  def resolve_config_dir(self, create: bool = False) -> Path:
42
42
  """
43
43
  Resolve configuration directory.
44
-
44
+
45
45
  Args:
46
46
  create: Whether to create directory if it doesn't exist
47
-
47
+
48
48
  Returns:
49
49
  Path to configuration directory
50
50
  """
51
51
  config_dir = self.base_dir / ".claude-mpm"
52
-
52
+
53
53
  if create and not config_dir.exists():
54
54
  config_dir.mkdir(parents=True, exist_ok=True)
55
55
  self.logger.debug(f"Created config directory: {config_dir}")
56
-
56
+
57
57
  return config_dir
58
-
58
+
59
59
  def resolve_agents_dir(self, create: bool = False) -> Path:
60
60
  """
61
61
  Resolve agents directory.
62
-
62
+
63
63
  Args:
64
64
  create: Whether to create directory if it doesn't exist
65
-
65
+
66
66
  Returns:
67
67
  Path to agents directory
68
68
  """
69
69
  agents_dir = self.resolve_config_dir(create) / "agents"
70
-
70
+
71
71
  if create and not agents_dir.exists():
72
72
  agents_dir.mkdir(parents=True, exist_ok=True)
73
73
  self.logger.debug(f"Created agents directory: {agents_dir}")
74
-
74
+
75
75
  return agents_dir
76
-
76
+
77
77
  def resolve_memories_dir(self, create: bool = False) -> Path:
78
78
  """
79
79
  Resolve memories directory.
80
-
80
+
81
81
  Args:
82
82
  create: Whether to create directory if it doesn't exist
83
-
83
+
84
84
  Returns:
85
85
  Path to memories directory
86
86
  """
87
87
  memories_dir = self.resolve_config_dir(create) / "memories"
88
-
88
+
89
89
  if create and not memories_dir.exists():
90
90
  memories_dir.mkdir(parents=True, exist_ok=True)
91
91
  self.logger.debug(f"Created memories directory: {memories_dir}")
92
-
92
+
93
93
  return memories_dir
94
-
94
+
95
95
  def resolve_logs_dir(self, create: bool = False) -> Path:
96
96
  """
97
97
  Resolve logs directory.
98
-
98
+
99
99
  Args:
100
100
  create: Whether to create directory if it doesn't exist
101
-
101
+
102
102
  Returns:
103
103
  Path to logs directory
104
104
  """
105
105
  logs_dir = self.resolve_config_dir(create) / "logs"
106
-
106
+
107
107
  if create and not logs_dir.exists():
108
108
  logs_dir.mkdir(parents=True, exist_ok=True)
109
109
  self.logger.debug(f"Created logs directory: {logs_dir}")
110
-
110
+
111
111
  return logs_dir
112
-
112
+
113
113
  def resolve_temp_dir(self, create: bool = False) -> Path:
114
114
  """
115
115
  Resolve temporary directory.
116
-
116
+
117
117
  Args:
118
118
  create: Whether to create directory if it doesn't exist
119
-
119
+
120
120
  Returns:
121
121
  Path to temporary directory
122
122
  """
123
123
  temp_dir = self.resolve_config_dir(create) / "tmp"
124
-
124
+
125
125
  if create and not temp_dir.exists():
126
126
  temp_dir.mkdir(parents=True, exist_ok=True)
127
127
  self.logger.debug(f"Created temp directory: {temp_dir}")
128
-
128
+
129
129
  return temp_dir
130
-
131
- def find_agent_file(self, agent_name: str, filename: str = None) -> Optional[Path]:
130
+
131
+ def find_agent_file(
132
+ self, agent_name: str, filename: Optional[str] = None
133
+ ) -> Optional[Path]:
132
134
  """
133
135
  Find agent file in standard locations.
134
-
136
+
135
137
  Args:
136
138
  agent_name: Name of the agent
137
139
  filename: Specific filename to look for (defaults to agent_name.md)
138
-
140
+
139
141
  Returns:
140
142
  Path to agent file if found
141
143
  """
142
144
  if filename is None:
143
145
  filename = f"{agent_name}.md"
144
-
146
+
145
147
  # Search locations in order of preference
146
148
  search_paths = [
147
149
  self.resolve_agents_dir(), # Project agents
@@ -149,50 +151,52 @@ class PathResolver:
149
151
  self.base_dir / "agents", # Local agents directory
150
152
  self.base_dir, # Current directory
151
153
  ]
152
-
154
+
153
155
  for search_path in search_paths:
154
156
  if not search_path.exists():
155
157
  continue
156
-
158
+
157
159
  agent_file = search_path / filename
158
160
  if agent_file.exists() and agent_file.is_file():
159
161
  self.logger.debug(f"Found agent file: {agent_file}")
160
162
  return agent_file
161
-
163
+
162
164
  return None
163
-
164
- def find_memory_file(self, agent_name: str, filename: str = None) -> Optional[Path]:
165
+
166
+ def find_memory_file(
167
+ self, agent_name: str, filename: Optional[str] = None
168
+ ) -> Optional[Path]:
165
169
  """
166
170
  Find memory file for an agent.
167
-
171
+
168
172
  Args:
169
173
  agent_name: Name of the agent
170
174
  filename: Specific filename to look for (defaults to agent_name.md)
171
-
175
+
172
176
  Returns:
173
177
  Path to memory file if found
174
178
  """
175
179
  if filename is None:
176
180
  filename = f"{agent_name}.md"
177
-
181
+
178
182
  memories_dir = self.resolve_memories_dir()
179
183
  memory_file = memories_dir / filename
180
-
184
+
181
185
  if memory_file.exists() and memory_file.is_file():
182
186
  return memory_file
183
-
187
+
184
188
  return None
185
-
186
- def find_config_file(self,
187
- filename: str,
188
- search_paths: List[Union[str, Path]] = None) -> Optional[Path]:
189
+
190
+ def find_config_file(
191
+ self, filename: str, search_paths: Optional[List[Union[str, Path]]] = None
192
+ ) -> Optional[Path]:
189
193
  """
190
194
  Find configuration file in standard locations.
191
-
195
+
192
196
  Args:
193
197
  filename: Configuration filename
194
198
  search_paths: Additional search paths
195
-
199
+
196
200
  Returns:
197
201
  Path to configuration file if found
198
202
  """
@@ -201,64 +205,64 @@ class PathResolver:
201
205
  self.base_dir,
202
206
  Path.home() / ".claude-mpm",
203
207
  ]
204
-
208
+
205
209
  if search_paths:
206
210
  all_paths = [Path(p) for p in search_paths] + default_paths
207
211
  else:
208
212
  all_paths = default_paths
209
-
213
+
210
214
  for search_path in all_paths:
211
215
  if not search_path.exists():
212
216
  continue
213
-
217
+
214
218
  config_file = search_path / filename
215
219
  if config_file.exists() and config_file.is_file():
216
220
  self.logger.debug(f"Found config file: {config_file}")
217
221
  return config_file
218
-
222
+
219
223
  return None
220
-
224
+
221
225
  def ensure_directory(self, path: Union[str, Path]) -> Path:
222
226
  """
223
227
  Ensure directory exists.
224
-
228
+
225
229
  Args:
226
230
  path: Directory path
227
-
231
+
228
232
  Returns:
229
233
  Path object for the directory
230
234
  """
231
235
  dir_path = Path(path)
232
-
236
+
233
237
  if not dir_path.exists():
234
238
  dir_path.mkdir(parents=True, exist_ok=True)
235
239
  self.logger.debug(f"Created directory: {dir_path}")
236
240
  elif not dir_path.is_dir():
237
241
  raise ValueError(f"Path exists but is not a directory: {dir_path}")
238
-
242
+
239
243
  return dir_path
240
-
244
+
241
245
  def resolve_relative_path(self, path: Union[str, Path]) -> Path:
242
246
  """
243
247
  Resolve path relative to base directory.
244
-
248
+
245
249
  Args:
246
250
  path: Path to resolve
247
-
251
+
248
252
  Returns:
249
253
  Resolved absolute path
250
254
  """
251
255
  path_obj = Path(path)
252
-
256
+
253
257
  if path_obj.is_absolute():
254
258
  return path_obj
255
-
259
+
256
260
  return (self.base_dir / path_obj).resolve()
257
-
261
+
258
262
  def get_path_info(self) -> dict:
259
263
  """
260
264
  Get information about resolved paths.
261
-
265
+
262
266
  Returns:
263
267
  Dictionary with path information
264
268
  """
@@ -271,7 +275,7 @@ class PathResolver:
271
275
  "temp_dir": str(self.resolve_temp_dir()),
272
276
  "working_dir_from_env": os.environ.get("CLAUDE_MPM_USER_PWD"),
273
277
  }
274
-
278
+
275
279
  def __repr__(self) -> str:
276
280
  """String representation."""
277
281
  return f"PathResolver(base_dir={self.base_dir})"
@@ -3,40 +3,38 @@ Shared singleton management utilities to reduce duplication.
3
3
  """
4
4
 
5
5
  import threading
6
- from typing import Any, Dict, Optional, Type, TypeVar
6
+ from typing import Any, Dict, Type, TypeVar
7
7
 
8
8
  from ..logger import get_logger
9
9
 
10
- T = TypeVar('T')
10
+ T = TypeVar("T")
11
11
 
12
12
 
13
13
  class SingletonManager:
14
14
  """
15
15
  Centralized singleton management utility.
16
-
16
+
17
17
  Reduces duplication by providing thread-safe singleton patterns
18
18
  that can be used across different classes.
19
19
  """
20
-
20
+
21
21
  _instances: Dict[Type, Any] = {}
22
22
  _locks: Dict[Type, threading.Lock] = {}
23
23
  _global_lock = threading.Lock()
24
-
24
+
25
25
  @classmethod
26
- def get_instance(cls,
27
- singleton_class: Type[T],
28
- *args,
29
- force_new: bool = False,
30
- **kwargs) -> T:
26
+ def get_instance(
27
+ cls, singleton_class: Type[T], *args, force_new: bool = False, **kwargs
28
+ ) -> T:
31
29
  """
32
30
  Get singleton instance of a class.
33
-
31
+
34
32
  Args:
35
33
  singleton_class: Class to get singleton instance of
36
34
  *args: Arguments for class constructor
37
35
  force_new: Force creation of new instance
38
36
  **kwargs: Keyword arguments for class constructor
39
-
37
+
40
38
  Returns:
41
39
  Singleton instance
42
40
  """
@@ -45,38 +43,38 @@ class SingletonManager:
45
43
  with cls._global_lock:
46
44
  if singleton_class not in cls._locks:
47
45
  cls._locks[singleton_class] = threading.Lock()
48
-
46
+
49
47
  # Get instance with class-specific lock
50
48
  with cls._locks[singleton_class]:
51
49
  if force_new or singleton_class not in cls._instances:
52
50
  logger = get_logger("singleton_manager")
53
51
  logger.debug(f"Creating singleton instance: {singleton_class.__name__}")
54
-
52
+
55
53
  instance = singleton_class(*args, **kwargs)
56
54
  cls._instances[singleton_class] = instance
57
-
55
+
58
56
  return instance
59
-
57
+
60
58
  return cls._instances[singleton_class]
61
-
59
+
62
60
  @classmethod
63
61
  def has_instance(cls, singleton_class: Type) -> bool:
64
62
  """
65
63
  Check if singleton instance exists.
66
-
64
+
67
65
  Args:
68
66
  singleton_class: Class to check
69
-
67
+
70
68
  Returns:
71
69
  True if instance exists
72
70
  """
73
71
  return singleton_class in cls._instances
74
-
72
+
75
73
  @classmethod
76
74
  def clear_instance(cls, singleton_class: Type) -> None:
77
75
  """
78
76
  Clear singleton instance.
79
-
77
+
80
78
  Args:
81
79
  singleton_class: Class to clear instance for
82
80
  """
@@ -84,9 +82,11 @@ class SingletonManager:
84
82
  with cls._locks[singleton_class]:
85
83
  if singleton_class in cls._instances:
86
84
  logger = get_logger("singleton_manager")
87
- logger.debug(f"Clearing singleton instance: {singleton_class.__name__}")
85
+ logger.debug(
86
+ f"Clearing singleton instance: {singleton_class.__name__}"
87
+ )
88
88
  del cls._instances[singleton_class]
89
-
89
+
90
90
  @classmethod
91
91
  def clear_all_instances(cls) -> None:
92
92
  """Clear all singleton instances."""
@@ -94,47 +94,47 @@ class SingletonManager:
94
94
  logger = get_logger("singleton_manager")
95
95
  logger.debug(f"Clearing {len(cls._instances)} singleton instances")
96
96
  cls._instances.clear()
97
-
97
+
98
98
  @classmethod
99
99
  def get_instance_info(cls) -> Dict[str, Any]:
100
100
  """
101
101
  Get information about managed instances.
102
-
102
+
103
103
  Returns:
104
104
  Dictionary with instance information
105
105
  """
106
106
  return {
107
107
  "instance_count": len(cls._instances),
108
- "instance_types": [cls_type.__name__ for cls_type in cls._instances.keys()],
109
- "lock_count": len(cls._locks)
108
+ "instance_types": [cls_type.__name__ for cls_type in cls._instances],
109
+ "lock_count": len(cls._locks),
110
110
  }
111
111
 
112
112
 
113
113
  class SingletonMixin:
114
114
  """
115
115
  Mixin class to add singleton behavior to any class.
116
-
116
+
117
117
  Usage:
118
118
  class MyService(SingletonMixin):
119
119
  def __init__(self):
120
120
  super().__init__()
121
121
  # Your initialization code
122
122
  """
123
-
123
+
124
124
  def __new__(cls, *args, **kwargs):
125
125
  """Override __new__ to implement singleton pattern."""
126
126
  return SingletonManager.get_instance(cls, *args, **kwargs)
127
-
127
+
128
128
  @classmethod
129
129
  def get_instance(cls, *args, **kwargs):
130
130
  """Get singleton instance."""
131
131
  return SingletonManager.get_instance(cls, *args, **kwargs)
132
-
132
+
133
133
  @classmethod
134
134
  def clear_instance(cls):
135
135
  """Clear singleton instance."""
136
136
  SingletonManager.clear_instance(cls)
137
-
137
+
138
138
  @classmethod
139
139
  def has_instance(cls) -> bool:
140
140
  """Check if instance exists."""
@@ -144,7 +144,7 @@ class SingletonMixin:
144
144
  def singleton(cls: Type[T]) -> Type[T]:
145
145
  """
146
146
  Decorator to make a class a singleton.
147
-
147
+
148
148
  Usage:
149
149
  @singleton
150
150
  class MyService:
@@ -152,21 +152,25 @@ def singleton(cls: Type[T]) -> Type[T]:
152
152
  # Your initialization code
153
153
  pass
154
154
  """
155
- original_new = cls.__new__
156
-
155
+
157
156
  def new_new(cls_inner, *args, **kwargs):
158
157
  return SingletonManager.get_instance(cls_inner, *args, **kwargs)
159
-
158
+
160
159
  cls.__new__ = new_new
161
-
160
+
162
161
  # Add convenience methods
163
- cls.get_instance = classmethod(lambda cls_inner, *args, **kwargs:
164
- SingletonManager.get_instance(cls_inner, *args, **kwargs))
165
- cls.clear_instance = classmethod(lambda cls_inner:
166
- SingletonManager.clear_instance(cls_inner))
167
- cls.has_instance = classmethod(lambda cls_inner:
168
- SingletonManager.has_instance(cls_inner))
169
-
162
+ cls.get_instance = classmethod(
163
+ lambda cls_inner, *args, **kwargs: SingletonManager.get_instance(
164
+ cls_inner, *args, **kwargs
165
+ )
166
+ )
167
+ cls.clear_instance = classmethod(
168
+ lambda cls_inner: SingletonManager.clear_instance(cls_inner)
169
+ )
170
+ cls.has_instance = classmethod(
171
+ lambda cls_inner: SingletonManager.has_instance(cls_inner)
172
+ )
173
+
170
174
  return cls
171
175
 
172
176
 
@@ -177,32 +181,34 @@ if __name__ == "__main__":
177
181
  def __init__(self, config_path: str = "default.yaml"):
178
182
  self.config_path = config_path
179
183
  self.loaded = True
180
-
184
+
181
185
  # Example 2: Using @singleton decorator
182
186
  @singleton
183
187
  class LoggerService:
184
188
  def __init__(self, log_level: str = "INFO"):
185
189
  self.log_level = log_level
186
190
  self.initialized = True
187
-
191
+
188
192
  # Example 3: Using SingletonManager directly
189
193
  class DatabaseService:
190
194
  def __init__(self, connection_string: str):
191
195
  self.connection_string = connection_string
192
196
  self.connected = True
193
-
197
+
194
198
  # Test the patterns
195
199
  config1 = ConfigService("config1.yaml")
196
200
  config2 = ConfigService("config2.yaml") # Same instance as config1
197
201
  assert config1 is config2
198
202
  assert config1.config_path == "config1.yaml" # First initialization wins
199
-
203
+
200
204
  logger1 = LoggerService("DEBUG")
201
205
  logger2 = LoggerService("ERROR") # Same instance as logger1
202
206
  assert logger1 is logger2
203
207
  assert logger1.log_level == "DEBUG" # First initialization wins
204
-
208
+
205
209
  db1 = SingletonManager.get_instance(DatabaseService, "postgres://localhost")
206
- db2 = SingletonManager.get_instance(DatabaseService, "mysql://localhost") # Same instance
210
+ db2 = SingletonManager.get_instance(
211
+ DatabaseService, "mysql://localhost"
212
+ ) # Same instance
207
213
  assert db1 is db2
208
214
  assert db1.connection_string == "postgres://localhost" # First initialization wins
@@ -95,7 +95,7 @@ class CircuitBreaker:
95
95
  """Check if execution is allowed based on circuit state."""
96
96
  if self.state == CircuitState.CLOSED:
97
97
  return True
98
- elif self.state == CircuitState.OPEN:
98
+ if self.state == CircuitState.OPEN:
99
99
  # Check if recovery timeout has passed
100
100
  if (
101
101
  self.last_failure_time
@@ -108,7 +108,7 @@ class CircuitBreaker:
108
108
  )
109
109
  return True
110
110
  return False
111
- elif self.state == CircuitState.HALF_OPEN:
111
+ if self.state == CircuitState.HALF_OPEN:
112
112
  # Allow one test request
113
113
  return True
114
114
 
@@ -496,7 +496,7 @@ class SocketIOConnectionPool:
496
496
  await client.emit(event.event, enhanced_data, namespace=namespace)
497
497
 
498
498
  # Update stats
499
- for conn_id, stats in self.connection_stats.items():
499
+ for _conn_id, stats in self.connection_stats.items():
500
500
  if stats.is_connected:
501
501
  stats.events_sent += len(events)
502
502
  stats.consecutive_errors = 0
@@ -547,7 +547,7 @@ class SocketIOConnectionPool:
547
547
  )
548
548
 
549
549
  # Update stats
550
- for conn_id, stats in self.connection_stats.items():
550
+ for _conn_id, stats in self.connection_stats.items():
551
551
  if stats.is_connected:
552
552
  stats.events_sent += len(events)
553
553
  stats.consecutive_errors = 0
@@ -562,7 +562,7 @@ class SocketIOConnectionPool:
562
562
  self.logger.error(f"Failed to emit batch to {namespace}: {e}")
563
563
 
564
564
  # Update stats
565
- for conn_id, stats in self.connection_stats.items():
565
+ for _conn_id, stats in self.connection_stats.items():
566
566
  if stats.is_connected:
567
567
  stats.errors += 1
568
568
  stats.consecutive_errors += 1
@@ -572,7 +572,7 @@ class SocketIOConnectionPool:
572
572
  finally:
573
573
  self._return_connection(client)
574
574
  # Only close loop if we created it
575
- if loop and not asyncio.get_event_loop() == loop:
575
+ if loop and asyncio.get_event_loop() != loop:
576
576
  try:
577
577
  # Ensure all tasks are done before closing
578
578
  pending = asyncio.all_tasks(loop)
@@ -731,6 +731,26 @@ class SocketIOConnectionPool:
731
731
  except (asyncio.TimeoutError, Exception):
732
732
  return False
733
733
 
734
+ def emit(self, event: str, data: Dict[str, Any]) -> bool:
735
+ """Emit an event through the connection pool.
736
+
737
+ This method provides compatibility for the legacy emit() interface
738
+ by mapping to the modern emit_event() method with appropriate defaults.
739
+
740
+ Args:
741
+ event: Event name (e.g., "claude_event")
742
+ data: Event data dictionary
743
+
744
+ Returns:
745
+ bool: True if event was sent successfully (always True for async emission)
746
+ """
747
+ if not SOCKETIO_AVAILABLE or not self._running:
748
+ return False
749
+
750
+ # Map to the modern emit_event method using default namespace
751
+ self.emit_event("/", event, data)
752
+ return True
753
+
734
754
  def get_stats(self) -> Dict[str, Any]:
735
755
  """Get connection pool statistics."""
736
756
  with self.pool_lock: