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
@@ -94,7 +94,7 @@ class AgentDependencyLoader:
94
94
  config_file = config_dir / f"{agent_id}.json"
95
95
  if config_file.exists():
96
96
  try:
97
- with open(config_file, "r") as f:
97
+ with open(config_file) as f:
98
98
  config = json.load(f)
99
99
  if "dependencies" in config:
100
100
  agent_dependencies[agent_id] = config["dependencies"]
@@ -141,11 +141,10 @@ class AgentDependencyLoader:
141
141
  # Check if version satisfies requirement
142
142
  if req.specifier.contains(version):
143
143
  return True, version
144
- else:
145
- logger.debug(
146
- f"{package_name} {version} does not satisfy {req.specifier}"
147
- )
148
- return False, version
144
+ logger.debug(
145
+ f"{package_name} {version} does not satisfy {req.specifier}"
146
+ )
147
+ return False, version
149
148
 
150
149
  except importlib.metadata.PackageNotFoundError:
151
150
  return False, None
@@ -160,8 +159,7 @@ class AgentDependencyLoader:
160
159
 
161
160
  if req.specifier.contains(version):
162
161
  return True, version
163
- else:
164
- return False, version
162
+ return False, version
165
163
 
166
164
  except pkg_resources.DistributionNotFound:
167
165
  return False, None
@@ -277,8 +275,6 @@ class AgentDependencyLoader:
277
275
  "re",
278
276
  "difflib",
279
277
  "textwrap",
280
- "unicodedata",
281
- "stringprep",
282
278
  "calendar",
283
279
  "locale",
284
280
  "gettext",
@@ -335,7 +331,11 @@ class AgentDependencyLoader:
335
331
  """
336
332
  try:
337
333
  result = subprocess.run(
338
- ["which", command], capture_output=True, text=True, timeout=5
334
+ ["which", command],
335
+ capture_output=True,
336
+ text=True,
337
+ timeout=5,
338
+ check=False,
339
339
  )
340
340
  return result.returncode == 0
341
341
  except Exception:
@@ -374,15 +374,14 @@ class AgentDependencyLoader:
374
374
  agent_result["python"]["satisfied"].append(dep_spec)
375
375
  if dep_spec not in results["summary"]["satisfied_python"]:
376
376
  results["summary"]["satisfied_python"].append(dep_spec)
377
- else:
378
- if version: # Installed but wrong version
379
- agent_result["python"]["outdated"].append(
380
- f"{dep_spec} (have {version})"
381
- )
382
- else: # Not installed
383
- agent_result["python"]["missing"].append(dep_spec)
384
- if dep_spec not in results["summary"]["missing_python"]:
385
- results["summary"]["missing_python"].append(dep_spec)
377
+ elif version: # Installed but wrong version
378
+ agent_result["python"]["outdated"].append(
379
+ f"{dep_spec} (have {version})"
380
+ )
381
+ else: # Not installed
382
+ agent_result["python"]["missing"].append(dep_spec)
383
+ if dep_spec not in results["summary"]["missing_python"]:
384
+ results["summary"]["missing_python"].append(dep_spec)
386
385
 
387
386
  # Check system dependencies
388
387
  if "system" in deps:
@@ -416,7 +415,6 @@ class AgentDependencyLoader:
416
415
  """
417
416
  import sys
418
417
 
419
- current_version = f"{sys.version_info.major}.{sys.version_info.minor}"
420
418
  compatible = []
421
419
  incompatible = []
422
420
 
@@ -428,10 +426,10 @@ class AgentDependencyLoader:
428
426
 
429
427
  # Known Python 3.13 incompatibilities
430
428
  if sys.version_info >= (3, 13):
431
- if package_name in ["ydata-profiling", "pandas-profiling"]:
432
- incompatible.append(f"{dep} (requires Python <3.13)")
433
- continue
434
- elif package_name == "apache-airflow":
429
+ if (
430
+ package_name in ["ydata-profiling", "pandas-profiling"]
431
+ or package_name == "apache-airflow"
432
+ ):
435
433
  incompatible.append(f"{dep} (requires Python <3.13)")
436
434
  continue
437
435
 
@@ -532,10 +530,27 @@ class AgentDependencyLoader:
532
530
  "Robust installer not available, falling back to simple installation"
533
531
  )
534
532
  try:
535
- cmd = [sys.executable, "-m", "pip", "install"] + compatible
533
+ cmd = [sys.executable, "-m", "pip", "install"]
534
+
535
+ # Check for PEP 668 managed environment
536
+ import sysconfig
537
+
538
+ stdlib_path = sysconfig.get_path("stdlib")
539
+ marker_file = Path(stdlib_path) / "EXTERNALLY-MANAGED"
540
+ parent_marker = marker_file.parent.parent / "EXTERNALLY-MANAGED"
541
+
542
+ if marker_file.exists() or parent_marker.exists():
543
+ logger.warning(
544
+ "PEP 668 managed environment detected. "
545
+ "Installing with --break-system-packages --user flags. "
546
+ "Consider using a virtual environment instead."
547
+ )
548
+ cmd.extend(["--break-system-packages", "--user"])
549
+
550
+ cmd.extend(compatible)
536
551
 
537
552
  result = subprocess.run(
538
- cmd, capture_output=True, text=True, timeout=300
553
+ cmd, capture_output=True, text=True, timeout=300, check=False
539
554
  )
540
555
 
541
556
  if result.returncode == 0:
@@ -546,10 +561,9 @@ class AgentDependencyLoader:
546
561
  f"Installed {len(compatible)} packages, skipped {len(incompatible)} incompatible",
547
562
  )
548
563
  return True, ""
549
- else:
550
- error_msg = f"Installation failed: {result.stderr}"
551
- logger.error(error_msg)
552
- return False, error_msg
564
+ error_msg = f"Installation failed: {result.stderr}"
565
+ logger.error(error_msg)
566
+ return False, error_msg
553
567
 
554
568
  except Exception as e:
555
569
  error_msg = f"Failed to install dependencies: {e}"
@@ -765,7 +779,7 @@ class AgentDependencyLoader:
765
779
  except Exception as e:
766
780
  logger.debug(f"Could not hash agent file {agent_path}: {e}")
767
781
  # Include error in hash to force recheck on next run
768
- hash_obj.update(f"error:{agent_id}:{e}".encode("utf-8"))
782
+ hash_obj.update(f"error:{agent_id}:{e}".encode())
769
783
 
770
784
  return hash_obj.hexdigest()
771
785
 
@@ -780,7 +794,7 @@ class AgentDependencyLoader:
780
794
  return {}
781
795
 
782
796
  try:
783
- with open(self.deployment_state_file, "r") as f:
797
+ with open(self.deployment_state_file) as f:
784
798
  return json.load(f)
785
799
  except Exception as e:
786
800
  logger.debug(f"Could not load deployment state: {e}")
@@ -6,7 +6,6 @@ configurations across different file formats (JSON, YAML, TOML).
6
6
 
7
7
  import json
8
8
  import os
9
- from functools import lru_cache
10
9
  from pathlib import Path
11
10
  from typing import Any, Dict, List, Optional, Union
12
11
 
@@ -56,7 +55,7 @@ class ConfigurationManager:
56
55
  try:
57
56
  cache_key = self._get_cache_key(file_path)
58
57
  return self._cache.get(cache_key)
59
- except (OSError, IOError):
58
+ except OSError:
60
59
  return None
61
60
 
62
61
  def _update_cache(self, file_path: Union[str, Path], config: Dict[str, Any]):
@@ -67,7 +66,7 @@ class ConfigurationManager:
67
66
  try:
68
67
  cache_key = self._get_cache_key(file_path)
69
68
  self._cache[cache_key] = config
70
- except (OSError, IOError):
69
+ except OSError:
71
70
  pass
72
71
 
73
72
  def clear_cache(self):
@@ -100,7 +99,7 @@ class ConfigurationManager:
100
99
 
101
100
  logger.debug(f"Loading JSON configuration from {file_path}")
102
101
  try:
103
- with open(file_path, "r", encoding="utf-8") as f:
102
+ with open(file_path, encoding="utf-8") as f:
104
103
  config = json.load(f)
105
104
  self._update_cache(file_path, config)
106
105
  return config
@@ -143,7 +142,7 @@ class ConfigurationManager:
143
142
 
144
143
  logger.debug(f"Loading YAML configuration from {file_path}")
145
144
  try:
146
- with open(file_path, "r", encoding="utf-8") as f:
145
+ with open(file_path, encoding="utf-8") as f:
147
146
  config = yaml.safe_load(f) or {}
148
147
  self._update_cache(file_path, config)
149
148
  return config
@@ -186,7 +185,7 @@ class ConfigurationManager:
186
185
 
187
186
  logger.debug(f"Loading TOML configuration from {file_path}")
188
187
  try:
189
- with open(file_path, "r", encoding="utf-8") as f:
188
+ with open(file_path, encoding="utf-8") as f:
190
189
  config = toml.load(f)
191
190
  self._update_cache(file_path, config)
192
191
  return config
@@ -215,12 +214,11 @@ class ConfigurationManager:
215
214
 
216
215
  if suffix in [".json"]:
217
216
  return self.load_json(file_path)
218
- elif suffix in [".yaml", ".yml"]:
217
+ if suffix in [".yaml", ".yml"]:
219
218
  return self.load_yaml(file_path)
220
- elif suffix in [".toml"]:
219
+ if suffix in [".toml"]:
221
220
  return self.load_toml(file_path)
222
- else:
223
- raise ValueError(f"Unsupported configuration format: {suffix}")
221
+ raise ValueError(f"Unsupported configuration format: {suffix}")
224
222
 
225
223
  def save_json(
226
224
  self,
@@ -461,12 +459,11 @@ class ConfigurationManager:
461
459
  result = result.replace(placeholder, env_value)
462
460
 
463
461
  return result
464
- elif isinstance(value, dict):
462
+ if isinstance(value, dict):
465
463
  return {k: _interpolate_value(v) for k, v in value.items()}
466
- elif isinstance(value, list):
464
+ if isinstance(value, list):
467
465
  return [_interpolate_value(item) for item in value]
468
- else:
469
- return value
466
+ return value
470
467
 
471
468
  return _interpolate_value(config)
472
469
 
@@ -66,7 +66,7 @@ class DependencyCache:
66
66
  return self._cache_data
67
67
 
68
68
  try:
69
- with open(self.cache_file, "r") as f:
69
+ with open(self.cache_file) as f:
70
70
  self._cache_data = json.load(f)
71
71
  return self._cache_data
72
72
  except Exception as e:
@@ -9,7 +9,6 @@ DESIGN DECISION: We use subprocess to install packages in the same environment
9
9
  that's running claude-mpm, respecting virtual environments and user setups.
10
10
  """
11
11
 
12
- import importlib
13
12
  import subprocess
14
13
  import sys
15
14
  from typing import List, Optional, Tuple
@@ -70,7 +69,7 @@ def install_packages(packages: List[str], logger=None) -> Tuple[bool, str]:
70
69
 
71
70
  try:
72
71
  # Use the same Python executable that's running this script
73
- cmd = [sys.executable, "-m", "pip", "install"] + packages
72
+ cmd = [sys.executable, "-m", "pip", "install", *packages]
74
73
 
75
74
  logger.info(f"Installing packages: {packages}")
76
75
  logger.debug(f"Running command: {' '.join(cmd)}")
@@ -80,18 +79,18 @@ def install_packages(packages: List[str], logger=None) -> Tuple[bool, str]:
80
79
  cmd,
81
80
  capture_output=True,
82
81
  text=True,
83
- timeout=300, # 5 minute timeout for installation
82
+ timeout=300,
83
+ check=False, # 5 minute timeout for installation
84
84
  )
85
85
 
86
86
  if result.returncode == 0:
87
87
  logger.info(f"Successfully installed packages: {packages}")
88
88
  return True, ""
89
- else:
90
- error_msg = f"pip install failed with return code {result.returncode}"
91
- if result.stderr:
92
- error_msg += f": {result.stderr.strip()}"
93
- logger.error(error_msg)
94
- return False, error_msg
89
+ error_msg = f"pip install failed with return code {result.returncode}"
90
+ if result.stderr:
91
+ error_msg += f": {result.stderr.strip()}"
92
+ logger.error(error_msg)
93
+ return False, error_msg
95
94
 
96
95
  except subprocess.TimeoutExpired:
97
96
  error_msg = "Package installation timed out after 5 minutes"
@@ -163,8 +162,7 @@ def ensure_socketio_dependencies(logger=None) -> Tuple[bool, str]:
163
162
 
164
163
  logger.info("Socket.IO dependencies installed and verified successfully")
165
164
  return True, ""
166
- else:
167
- return False, error_msg
165
+ return False, error_msg
168
166
 
169
167
 
170
168
  def get_pip_freeze_output() -> List[str]:
@@ -183,12 +181,12 @@ def get_pip_freeze_output() -> List[str]:
183
181
  capture_output=True,
184
182
  text=True,
185
183
  timeout=30,
184
+ check=False,
186
185
  )
187
186
 
188
187
  if result.returncode == 0:
189
188
  return result.stdout.strip().split("\n")
190
- else:
191
- return [f"pip freeze failed: {result.stderr}"]
189
+ return [f"pip freeze failed: {result.stderr}"]
192
190
 
193
191
  except Exception as e:
194
192
  return [f"Failed to get pip freeze output: {e}"]
@@ -206,8 +204,7 @@ def check_virtual_environment() -> Tuple[bool, str]:
206
204
  """
207
205
  # Check for virtual environment indicators
208
206
  in_venv = (
209
- hasattr(sys, "base_prefix")
210
- and sys.base_prefix != sys.prefix
207
+ (hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix)
211
208
  or hasattr(sys, "real_prefix")
212
209
  or (hasattr(sys, "prefix") and "conda" in sys.prefix.lower())
213
210
  )
@@ -215,5 +212,4 @@ def check_virtual_environment() -> Tuple[bool, str]:
215
212
  if in_venv:
216
213
  venv_path = getattr(sys, "prefix", "unknown")
217
214
  return True, f"Virtual environment: {venv_path}"
218
- else:
219
- return False, f"System Python: {sys.prefix}"
215
+ return False, f"System Python: {sys.prefix}"
@@ -10,7 +10,6 @@ based on the execution context and user preferences.
10
10
  import json
11
11
  import os
12
12
  import sys
13
- import time
14
13
  from datetime import datetime, timedelta
15
14
  from enum import Enum
16
15
  from typing import Any, Dict, Optional, Tuple
@@ -256,16 +255,15 @@ class DependencyStrategy:
256
255
 
257
256
  if response in ["y", "yes"]:
258
257
  return "yes"
259
- elif response in ["n", "no", ""]:
258
+ if response in ["n", "no", ""]:
260
259
  return "no"
261
- elif response == "always":
260
+ if response == "always":
262
261
  self._save_preference(DependencyMode.AUTO)
263
262
  return "yes"
264
- elif response == "never":
263
+ if response == "never":
265
264
  self._save_preference(DependencyMode.OFF)
266
265
  return "no"
267
- else:
268
- print("Invalid choice. Please enter: y, n, always, or never")
266
+ print("Invalid choice. Please enter: y, n, always, or never")
269
267
 
270
268
  def _save_preference(self, mode: DependencyMode) -> None:
271
269
  """
@@ -366,13 +364,13 @@ def lazy_check_agent_dependency(agent_id: str) -> bool:
366
364
  success, _ = loader.install_missing_dependencies(missing)
367
365
  return success
368
366
 
369
- elif strategy.mode == DependencyMode.INTERACTIVE:
367
+ if strategy.mode == DependencyMode.INTERACTIVE:
370
368
  choice = strategy.prompt_for_installation(missing)
371
369
  if choice in ["yes"]:
372
370
  success, _ = loader.install_missing_dependencies(missing)
373
371
  return success
374
372
  return False
375
373
 
376
- else: # CHECK or OFF
377
- logger.warning(f"Agent {agent_id} missing {len(missing)} dependencies")
378
- return False # Proceed anyway
374
+ # CHECK or OFF
375
+ logger.warning(f"Agent {agent_id} missing {len(missing)} dependencies")
376
+ return False # Proceed anyway
@@ -127,10 +127,7 @@ class EnvironmentContext:
127
127
  return True
128
128
 
129
129
  # Additional heuristics for CI detection
130
- if os.environ.get("BUILD_ID") or os.environ.get("BUILD_NUMBER"):
131
- return True
132
-
133
- return False
130
+ return bool(os.environ.get("BUILD_ID") or os.environ.get("BUILD_NUMBER"))
134
131
 
135
132
  @classmethod
136
133
  def _detect_docker(cls) -> bool:
@@ -152,7 +149,7 @@ class EnvironmentContext:
152
149
 
153
150
  # Check cgroup for docker/containerd references
154
151
  try:
155
- with open("/proc/1/cgroup", "r") as f:
152
+ with open("/proc/1/cgroup") as f:
156
153
  cgroup_content = f.read()
157
154
  if "docker" in cgroup_content or "containerd" in cgroup_content:
158
155
  return True
@@ -196,10 +193,7 @@ class EnvironmentContext:
196
193
  pass
197
194
 
198
195
  # Check for Jupyter-specific environment variables
199
- if "JPY_PARENT_PID" in os.environ:
200
- return True
201
-
202
- return False
196
+ return "JPY_PARENT_PID" in os.environ
203
197
 
204
198
  @classmethod
205
199
  def _detect_ssh(cls) -> bool:
@@ -6,7 +6,6 @@ Inspired by awesome-claude-code's comprehensive error handling approach.
6
6
 
7
7
  import logging
8
8
  import sys
9
- import traceback
10
9
  from datetime import datetime
11
10
  from functools import wraps
12
11
  from typing import Any, Callable, Dict, List, Optional, Type
@@ -31,7 +30,7 @@ class MPMError(Exception):
31
30
 
32
31
  def get_user_friendly_message(self) -> str:
33
32
  """Get a user-friendly error message."""
34
- lines = [f"❌ Error: {str(self)}"]
33
+ lines = [f"❌ Error: {self!s}"]
35
34
 
36
35
  if self.details:
37
36
  lines.append("\nDetails:")
@@ -49,26 +48,18 @@ class MPMError(Exception):
49
48
  class AgentLoadError(MPMError):
50
49
  """Raised when agent loading fails."""
51
50
 
52
- pass
53
-
54
51
 
55
52
  class ValidationError(MPMError):
56
53
  """Raised when validation fails."""
57
54
 
58
- pass
59
-
60
55
 
61
56
  class ExecutionError(MPMError):
62
57
  """Raised when agent execution fails."""
63
58
 
64
- pass
65
-
66
59
 
67
60
  class ConfigurationError(MPMError):
68
61
  """Raised when configuration is invalid."""
69
62
 
70
- pass
71
-
72
63
 
73
64
  def handle_errors(
74
65
  error_type: Type[Exception] = Exception,
@@ -131,7 +122,7 @@ class ErrorContext:
131
122
  """Exit the context, handling any errors."""
132
123
  if exc_type is None:
133
124
  logger.debug(f"Completed operation: {self.operation}")
134
- return
125
+ return None
135
126
 
136
127
  # Log the error with context
137
128
  logger.error(
@@ -216,8 +207,7 @@ def retry_on_error(
216
207
 
217
208
  if asyncio.iscoroutinefunction(func):
218
209
  return async_wrapper
219
- else:
220
- return sync_wrapper
210
+ return sync_wrapper
221
211
 
222
212
  return decorator
223
213
 
@@ -61,7 +61,7 @@ def safe_read_file(path: Union[str, Path], encoding: str = "utf-8") -> str:
61
61
  path = Path(path)
62
62
  try:
63
63
  return path.read_text(encoding=encoding)
64
- except FileNotFoundError as e:
64
+ except FileNotFoundError:
65
65
  raise FileOperationError(
66
66
  f"File not found: {path}",
67
67
  context={
@@ -135,7 +135,7 @@ class PathOperations:
135
135
  logger.warning(f"File not readable: {path}")
136
136
  return default
137
137
 
138
- with open(path_obj, "r", encoding=encoding) as f:
138
+ with open(path_obj, encoding=encoding) as f:
139
139
  return f.read()
140
140
  except Exception as e:
141
141
  logger.error(f"Error reading file {path}: {e}")
@@ -307,13 +307,12 @@ class PathOperations:
307
307
 
308
308
  if path_obj.is_file():
309
309
  return path_obj.stat().st_size
310
- else:
311
- # Calculate total size for directory
312
- total = 0
313
- for item in path_obj.rglob("*"):
314
- if item.is_file():
315
- total += item.stat().st_size
316
- return total
310
+ # Calculate total size for directory
311
+ total = 0
312
+ for item in path_obj.rglob("*"):
313
+ if item.is_file():
314
+ total += item.stat().st_size
315
+ return total
317
316
 
318
317
  except Exception as e:
319
318
  logger.error(f"Error getting size of {path}: {e}")
@@ -343,10 +342,7 @@ class PathOperations:
343
342
  logger.error(f"Not a directory: {path}")
344
343
  return []
345
344
 
346
- if recursive:
347
- items = path_obj.rglob(pattern)
348
- else:
349
- items = path_obj.glob(pattern)
345
+ items = path_obj.rglob(pattern) if recursive else path_obj.glob(pattern)
350
346
 
351
347
  results = []
352
348
  for item in items: