claude-mpm 3.9.11__py3-none-any.whl → 4.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (419) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +2 -2
  3. claude_mpm/__main__.py +3 -2
  4. claude_mpm/agents/__init__.py +85 -79
  5. claude_mpm/agents/agent_loader.py +464 -1003
  6. claude_mpm/agents/agent_loader_integration.py +45 -45
  7. claude_mpm/agents/agents_metadata.py +29 -30
  8. claude_mpm/agents/async_agent_loader.py +156 -138
  9. claude_mpm/agents/base_agent.json +1 -1
  10. claude_mpm/agents/base_agent_loader.py +179 -151
  11. claude_mpm/agents/frontmatter_validator.py +229 -130
  12. claude_mpm/agents/schema/agent_schema.json +1 -1
  13. claude_mpm/agents/system_agent_config.py +213 -147
  14. claude_mpm/agents/templates/__init__.py +13 -13
  15. claude_mpm/agents/templates/code_analyzer.json +2 -2
  16. claude_mpm/agents/templates/data_engineer.json +1 -1
  17. claude_mpm/agents/templates/documentation.json +23 -11
  18. claude_mpm/agents/templates/engineer.json +22 -6
  19. claude_mpm/agents/templates/memory_manager.json +1 -1
  20. claude_mpm/agents/templates/ops.json +2 -2
  21. claude_mpm/agents/templates/project_organizer.json +1 -1
  22. claude_mpm/agents/templates/qa.json +1 -1
  23. claude_mpm/agents/templates/refactoring_engineer.json +222 -0
  24. claude_mpm/agents/templates/research.json +20 -14
  25. claude_mpm/agents/templates/security.json +1 -1
  26. claude_mpm/agents/templates/ticketing.json +1 -1
  27. claude_mpm/agents/templates/version_control.json +1 -1
  28. claude_mpm/agents/templates/web_qa.json +3 -1
  29. claude_mpm/agents/templates/web_ui.json +2 -2
  30. claude_mpm/cli/__init__.py +79 -51
  31. claude_mpm/cli/__main__.py +3 -2
  32. claude_mpm/cli/commands/__init__.py +20 -20
  33. claude_mpm/cli/commands/agents.py +279 -247
  34. claude_mpm/cli/commands/aggregate.py +138 -157
  35. claude_mpm/cli/commands/cleanup.py +147 -147
  36. claude_mpm/cli/commands/config.py +93 -76
  37. claude_mpm/cli/commands/info.py +17 -16
  38. claude_mpm/cli/commands/mcp.py +140 -905
  39. claude_mpm/cli/commands/mcp_command_router.py +139 -0
  40. claude_mpm/cli/commands/mcp_config_commands.py +20 -0
  41. claude_mpm/cli/commands/mcp_install_commands.py +20 -0
  42. claude_mpm/cli/commands/mcp_server_commands.py +175 -0
  43. claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
  44. claude_mpm/cli/commands/memory.py +239 -203
  45. claude_mpm/cli/commands/monitor.py +203 -81
  46. claude_mpm/cli/commands/run.py +380 -429
  47. claude_mpm/cli/commands/run_config_checker.py +160 -0
  48. claude_mpm/cli/commands/socketio_monitor.py +235 -0
  49. claude_mpm/cli/commands/tickets.py +305 -197
  50. claude_mpm/cli/parser.py +24 -1156
  51. claude_mpm/cli/parsers/__init__.py +29 -0
  52. claude_mpm/cli/parsers/agents_parser.py +136 -0
  53. claude_mpm/cli/parsers/base_parser.py +331 -0
  54. claude_mpm/cli/parsers/config_parser.py +85 -0
  55. claude_mpm/cli/parsers/mcp_parser.py +152 -0
  56. claude_mpm/cli/parsers/memory_parser.py +138 -0
  57. claude_mpm/cli/parsers/monitor_parser.py +104 -0
  58. claude_mpm/cli/parsers/run_parser.py +147 -0
  59. claude_mpm/cli/parsers/tickets_parser.py +203 -0
  60. claude_mpm/cli/ticket_cli.py +7 -3
  61. claude_mpm/cli/utils.py +55 -37
  62. claude_mpm/cli_module/__init__.py +6 -6
  63. claude_mpm/cli_module/args.py +188 -140
  64. claude_mpm/cli_module/commands.py +79 -70
  65. claude_mpm/cli_module/migration_example.py +38 -60
  66. claude_mpm/config/__init__.py +32 -25
  67. claude_mpm/config/agent_config.py +151 -119
  68. claude_mpm/config/experimental_features.py +71 -73
  69. claude_mpm/config/paths.py +94 -208
  70. claude_mpm/config/socketio_config.py +84 -73
  71. claude_mpm/constants.py +35 -18
  72. claude_mpm/core/__init__.py +9 -6
  73. claude_mpm/core/agent_name_normalizer.py +68 -71
  74. claude_mpm/core/agent_registry.py +372 -521
  75. claude_mpm/core/agent_session_manager.py +74 -63
  76. claude_mpm/core/base_service.py +116 -87
  77. claude_mpm/core/cache.py +119 -153
  78. claude_mpm/core/claude_runner.py +425 -1120
  79. claude_mpm/core/config.py +263 -168
  80. claude_mpm/core/config_aliases.py +69 -61
  81. claude_mpm/core/config_constants.py +292 -0
  82. claude_mpm/core/constants.py +57 -99
  83. claude_mpm/core/container.py +211 -178
  84. claude_mpm/core/exceptions.py +233 -89
  85. claude_mpm/core/factories.py +92 -54
  86. claude_mpm/core/framework_loader.py +378 -220
  87. claude_mpm/core/hook_manager.py +198 -83
  88. claude_mpm/core/hook_performance_config.py +136 -0
  89. claude_mpm/core/injectable_service.py +61 -55
  90. claude_mpm/core/interactive_session.py +165 -155
  91. claude_mpm/core/interfaces.py +221 -195
  92. claude_mpm/core/lazy.py +96 -96
  93. claude_mpm/core/logger.py +133 -107
  94. claude_mpm/core/logging_config.py +185 -157
  95. claude_mpm/core/minimal_framework_loader.py +20 -15
  96. claude_mpm/core/mixins.py +30 -29
  97. claude_mpm/core/oneshot_session.py +215 -181
  98. claude_mpm/core/optimized_agent_loader.py +134 -138
  99. claude_mpm/core/optimized_startup.py +159 -157
  100. claude_mpm/core/pm_hook_interceptor.py +85 -72
  101. claude_mpm/core/service_registry.py +103 -101
  102. claude_mpm/core/session_manager.py +97 -87
  103. claude_mpm/core/socketio_pool.py +212 -158
  104. claude_mpm/core/tool_access_control.py +58 -51
  105. claude_mpm/core/types.py +46 -24
  106. claude_mpm/core/typing_utils.py +166 -82
  107. claude_mpm/core/unified_agent_registry.py +721 -0
  108. claude_mpm/core/unified_config.py +550 -0
  109. claude_mpm/core/unified_paths.py +549 -0
  110. claude_mpm/dashboard/index.html +1 -1
  111. claude_mpm/dashboard/open_dashboard.py +51 -17
  112. claude_mpm/dashboard/static/css/dashboard.css +27 -8
  113. claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
  114. claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
  115. claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
  116. claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
  117. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
  118. claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
  119. claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
  120. claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
  121. claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
  122. claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
  123. claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
  124. claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
  125. claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
  126. claude_mpm/dashboard/static/dist/dashboard.js +2 -0
  127. claude_mpm/dashboard/static/dist/socket-client.js +2 -0
  128. claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
  129. claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
  130. claude_mpm/dashboard/static/js/components/event-viewer.js +74 -70
  131. claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
  132. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +106 -92
  133. claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
  134. claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
  135. claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
  136. claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
  137. claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
  138. claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
  139. claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
  140. claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
  141. claude_mpm/dashboard/static/js/dashboard.js +178 -453
  142. claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
  143. claude_mpm/dashboard/static/js/socket-client.js +120 -54
  144. claude_mpm/dashboard/templates/index.html +40 -50
  145. claude_mpm/experimental/cli_enhancements.py +60 -58
  146. claude_mpm/generators/__init__.py +1 -1
  147. claude_mpm/generators/agent_profile_generator.py +75 -65
  148. claude_mpm/hooks/__init__.py +1 -1
  149. claude_mpm/hooks/base_hook.py +33 -28
  150. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  151. claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
  152. claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
  153. claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
  154. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
  155. claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
  156. claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
  157. claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
  158. claude_mpm/hooks/memory_integration_hook.py +140 -100
  159. claude_mpm/hooks/tool_call_interceptor.py +89 -76
  160. claude_mpm/hooks/validation_hooks.py +57 -49
  161. claude_mpm/init.py +145 -121
  162. claude_mpm/models/__init__.py +9 -9
  163. claude_mpm/models/agent_definition.py +33 -23
  164. claude_mpm/models/agent_session.py +228 -200
  165. claude_mpm/scripts/__init__.py +1 -1
  166. claude_mpm/scripts/socketio_daemon.py +192 -75
  167. claude_mpm/scripts/socketio_server_manager.py +328 -0
  168. claude_mpm/scripts/start_activity_logging.py +25 -22
  169. claude_mpm/services/__init__.py +68 -43
  170. claude_mpm/services/agent_capabilities_service.py +271 -0
  171. claude_mpm/services/agents/__init__.py +23 -32
  172. claude_mpm/services/agents/deployment/__init__.py +3 -3
  173. claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
  174. claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
  175. claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
  176. claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
  177. claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
  178. claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
  179. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
  180. claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
  181. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
  182. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
  183. claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
  184. claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
  185. claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
  186. claude_mpm/services/agents/deployment/agent_validator.py +352 -0
  187. claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
  188. claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
  189. claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
  190. claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
  191. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  192. claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
  193. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  194. claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
  195. claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
  196. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  197. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  198. claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
  199. claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
  200. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  201. claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
  202. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  203. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  204. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  205. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  206. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
  207. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  208. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  209. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
  210. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
  211. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
  212. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
  213. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
  214. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  215. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
  216. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  217. claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
  218. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
  219. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  220. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  221. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  222. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  223. claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
  224. claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
  225. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  226. claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
  227. claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
  228. claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
  229. claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
  230. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  231. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  232. claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
  233. claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
  234. claude_mpm/services/agents/loading/__init__.py +2 -2
  235. claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
  236. claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
  237. claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
  238. claude_mpm/services/agents/management/__init__.py +2 -2
  239. claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
  240. claude_mpm/services/agents/management/agent_management_service.py +209 -156
  241. claude_mpm/services/agents/memory/__init__.py +9 -6
  242. claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
  243. claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
  244. claude_mpm/services/agents/memory/analyzer.py +430 -0
  245. claude_mpm/services/agents/memory/content_manager.py +376 -0
  246. claude_mpm/services/agents/memory/template_generator.py +468 -0
  247. claude_mpm/services/agents/registry/__init__.py +7 -10
  248. claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
  249. claude_mpm/services/agents/registry/modification_tracker.py +351 -285
  250. claude_mpm/services/async_session_logger.py +187 -153
  251. claude_mpm/services/claude_session_logger.py +87 -72
  252. claude_mpm/services/command_handler_service.py +217 -0
  253. claude_mpm/services/communication/__init__.py +3 -2
  254. claude_mpm/services/core/__init__.py +50 -97
  255. claude_mpm/services/core/base.py +60 -53
  256. claude_mpm/services/core/interfaces/__init__.py +188 -0
  257. claude_mpm/services/core/interfaces/agent.py +351 -0
  258. claude_mpm/services/core/interfaces/communication.py +343 -0
  259. claude_mpm/services/core/interfaces/infrastructure.py +413 -0
  260. claude_mpm/services/core/interfaces/service.py +434 -0
  261. claude_mpm/services/core/interfaces.py +19 -944
  262. claude_mpm/services/event_aggregator.py +208 -170
  263. claude_mpm/services/exceptions.py +387 -308
  264. claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
  265. claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
  266. claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
  267. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
  268. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
  269. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
  270. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
  271. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
  272. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  273. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  274. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  275. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  276. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
  277. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  278. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  279. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
  280. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
  281. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  282. claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
  283. claude_mpm/services/hook_service.py +106 -114
  284. claude_mpm/services/infrastructure/__init__.py +7 -5
  285. claude_mpm/services/infrastructure/context_preservation.py +233 -199
  286. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  287. claude_mpm/services/infrastructure/logging.py +83 -76
  288. claude_mpm/services/infrastructure/monitoring.py +547 -404
  289. claude_mpm/services/mcp_gateway/__init__.py +30 -13
  290. claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
  291. claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
  292. claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
  293. claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
  294. claude_mpm/services/mcp_gateway/core/__init__.py +13 -20
  295. claude_mpm/services/mcp_gateway/core/base.py +80 -67
  296. claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
  297. claude_mpm/services/mcp_gateway/core/interfaces.py +87 -84
  298. claude_mpm/services/mcp_gateway/main.py +287 -137
  299. claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
  300. claude_mpm/services/mcp_gateway/registry/service_registry.py +97 -94
  301. claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
  302. claude_mpm/services/mcp_gateway/server/__init__.py +2 -2
  303. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +105 -110
  304. claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
  305. claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
  306. claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
  307. claude_mpm/services/mcp_gateway/tools/base_adapter.py +109 -119
  308. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
  309. claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
  310. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
  311. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
  312. claude_mpm/services/memory/__init__.py +2 -2
  313. claude_mpm/services/memory/builder.py +451 -362
  314. claude_mpm/services/memory/cache/__init__.py +2 -2
  315. claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
  316. claude_mpm/services/memory/cache/simple_cache.py +107 -93
  317. claude_mpm/services/memory/indexed_memory.py +195 -193
  318. claude_mpm/services/memory/optimizer.py +267 -234
  319. claude_mpm/services/memory/router.py +571 -263
  320. claude_mpm/services/memory_hook_service.py +237 -0
  321. claude_mpm/services/port_manager.py +223 -0
  322. claude_mpm/services/project/__init__.py +3 -3
  323. claude_mpm/services/project/analyzer.py +451 -305
  324. claude_mpm/services/project/registry.py +262 -240
  325. claude_mpm/services/recovery_manager.py +287 -231
  326. claude_mpm/services/response_tracker.py +87 -67
  327. claude_mpm/services/runner_configuration_service.py +587 -0
  328. claude_mpm/services/session_management_service.py +304 -0
  329. claude_mpm/services/socketio/__init__.py +4 -4
  330. claude_mpm/services/socketio/client_proxy.py +174 -0
  331. claude_mpm/services/socketio/handlers/__init__.py +3 -3
  332. claude_mpm/services/socketio/handlers/base.py +44 -30
  333. claude_mpm/services/socketio/handlers/connection.py +145 -65
  334. claude_mpm/services/socketio/handlers/file.py +123 -108
  335. claude_mpm/services/socketio/handlers/git.py +607 -373
  336. claude_mpm/services/socketio/handlers/hook.py +170 -0
  337. claude_mpm/services/socketio/handlers/memory.py +4 -4
  338. claude_mpm/services/socketio/handlers/project.py +4 -4
  339. claude_mpm/services/socketio/handlers/registry.py +53 -38
  340. claude_mpm/services/socketio/server/__init__.py +18 -0
  341. claude_mpm/services/socketio/server/broadcaster.py +252 -0
  342. claude_mpm/services/socketio/server/core.py +399 -0
  343. claude_mpm/services/socketio/server/main.py +323 -0
  344. claude_mpm/services/socketio_client_manager.py +160 -133
  345. claude_mpm/services/socketio_server.py +36 -1885
  346. claude_mpm/services/subprocess_launcher_service.py +316 -0
  347. claude_mpm/services/system_instructions_service.py +258 -0
  348. claude_mpm/services/ticket_manager.py +19 -533
  349. claude_mpm/services/utility_service.py +285 -0
  350. claude_mpm/services/version_control/__init__.py +18 -21
  351. claude_mpm/services/version_control/branch_strategy.py +20 -10
  352. claude_mpm/services/version_control/conflict_resolution.py +37 -13
  353. claude_mpm/services/version_control/git_operations.py +52 -21
  354. claude_mpm/services/version_control/semantic_versioning.py +92 -53
  355. claude_mpm/services/version_control/version_parser.py +145 -125
  356. claude_mpm/services/version_service.py +270 -0
  357. claude_mpm/storage/__init__.py +2 -2
  358. claude_mpm/storage/state_storage.py +177 -181
  359. claude_mpm/ticket_wrapper.py +2 -2
  360. claude_mpm/utils/__init__.py +2 -2
  361. claude_mpm/utils/agent_dependency_loader.py +453 -243
  362. claude_mpm/utils/config_manager.py +157 -118
  363. claude_mpm/utils/console.py +1 -1
  364. claude_mpm/utils/dependency_cache.py +102 -107
  365. claude_mpm/utils/dependency_manager.py +52 -47
  366. claude_mpm/utils/dependency_strategies.py +131 -96
  367. claude_mpm/utils/environment_context.py +110 -102
  368. claude_mpm/utils/error_handler.py +75 -55
  369. claude_mpm/utils/file_utils.py +80 -67
  370. claude_mpm/utils/framework_detection.py +12 -11
  371. claude_mpm/utils/import_migration_example.py +12 -60
  372. claude_mpm/utils/imports.py +48 -45
  373. claude_mpm/utils/path_operations.py +100 -93
  374. claude_mpm/utils/robust_installer.py +172 -164
  375. claude_mpm/utils/session_logging.py +30 -23
  376. claude_mpm/utils/subprocess_utils.py +99 -61
  377. claude_mpm/validation/__init__.py +1 -1
  378. claude_mpm/validation/agent_validator.py +151 -111
  379. claude_mpm/validation/frontmatter_validator.py +92 -71
  380. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/METADATA +27 -1
  381. claude_mpm-4.0.3.dist-info/RECORD +402 -0
  382. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
  383. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/licenses/LICENSE +1 -1
  384. claude_mpm/cli/commands/run_guarded.py +0 -511
  385. claude_mpm/config/memory_guardian_config.py +0 -325
  386. claude_mpm/config/memory_guardian_yaml.py +0 -335
  387. claude_mpm/core/config_paths.py +0 -150
  388. claude_mpm/core/memory_aware_runner.py +0 -353
  389. claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
  390. claude_mpm/deployment_paths.py +0 -261
  391. claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
  392. claude_mpm/models/state_models.py +0 -433
  393. claude_mpm/services/agent/__init__.py +0 -24
  394. claude_mpm/services/agent/deployment.py +0 -2548
  395. claude_mpm/services/agent/management.py +0 -598
  396. claude_mpm/services/agent/registry.py +0 -813
  397. claude_mpm/services/agents/registry/agent_registry.py +0 -813
  398. claude_mpm/services/communication/socketio.py +0 -1935
  399. claude_mpm/services/communication/websocket.py +0 -479
  400. claude_mpm/services/framework_claude_md_generator.py +0 -624
  401. claude_mpm/services/health_monitor.py +0 -893
  402. claude_mpm/services/infrastructure/graceful_degradation.py +0 -616
  403. claude_mpm/services/infrastructure/health_monitor.py +0 -775
  404. claude_mpm/services/infrastructure/memory_dashboard.py +0 -479
  405. claude_mpm/services/infrastructure/memory_guardian.py +0 -944
  406. claude_mpm/services/infrastructure/restart_protection.py +0 -642
  407. claude_mpm/services/infrastructure/state_manager.py +0 -774
  408. claude_mpm/services/mcp_gateway/manager.py +0 -334
  409. claude_mpm/services/optimized_hook_service.py +0 -542
  410. claude_mpm/services/project_analyzer.py +0 -864
  411. claude_mpm/services/project_registry.py +0 -608
  412. claude_mpm/services/standalone_socketio_server.py +0 -1300
  413. claude_mpm/services/ticket_manager_di.py +0 -318
  414. claude_mpm/services/ticketing_service_original.py +0 -510
  415. claude_mpm/utils/paths.py +0 -395
  416. claude_mpm/utils/platform_memory.py +0 -524
  417. claude_mpm-3.9.11.dist-info/RECORD +0 -306
  418. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/WHEEL +0 -0
  419. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,5 @@
1
+ from pathlib import Path
2
+
1
3
  """Enhanced error classes for daemon conflict and process management in claude-mpm Socket.IO server.
2
4
 
3
5
  These error classes provide detailed context and actionable guidance for users to resolve
@@ -12,24 +14,25 @@ Design Principles:
12
14
  """
13
15
 
14
16
  import os
17
+ import platform
15
18
  import sys
16
19
  import time
17
- import platform
18
20
  from datetime import datetime
19
- from typing import Dict, Any, Optional, List
20
- from pathlib import Path
21
+ from typing import Any, Dict, List, Optional
21
22
 
22
23
 
23
24
  class SocketIOServerError(Exception):
24
25
  """Base exception for Socket.IO server errors.
25
-
26
+
26
27
  Provides common functionality for all server-related errors including
27
28
  structured error data and detailed context information.
28
29
  """
29
-
30
- def __init__(self, message: str, error_code: str = None, context: Dict[str, Any] = None):
30
+
31
+ def __init__(
32
+ self, message: str, error_code: str = None, context: Dict[str, Any] = None
33
+ ):
31
34
  """Initialize base server error.
32
-
35
+
33
36
  Args:
34
37
  message: Human-readable error message
35
38
  error_code: Machine-readable error code for programmatic handling
@@ -40,7 +43,7 @@ class SocketIOServerError(Exception):
40
43
  self.error_code = error_code or self.__class__.__name__.lower()
41
44
  self.context = context or {}
42
45
  self.timestamp = datetime.utcnow().isoformat() + "Z"
43
-
46
+
44
47
  def to_dict(self) -> Dict[str, Any]:
45
48
  """Convert error to dictionary format for structured logging/handling."""
46
49
  return {
@@ -48,25 +51,27 @@ class SocketIOServerError(Exception):
48
51
  "error_code": self.error_code,
49
52
  "message": self.message,
50
53
  "context": self.context,
51
- "timestamp": self.timestamp
54
+ "timestamp": self.timestamp,
52
55
  }
53
56
 
54
57
 
55
58
  class DaemonConflictError(SocketIOServerError):
56
59
  """Error raised when attempting to start server while another instance is already running.
57
-
60
+
58
61
  This error provides detailed information about the conflicting process and
59
62
  actionable steps to resolve the conflict.
60
63
  """
61
-
62
- def __init__(self,
63
- port: int,
64
- existing_pid: int,
65
- existing_server_id: str = None,
66
- process_info: Dict[str, Any] = None,
67
- pidfile_path: Path = None):
64
+
65
+ def __init__(
66
+ self,
67
+ port: int,
68
+ existing_pid: int,
69
+ existing_server_id: str = None,
70
+ process_info: Dict[str, Any] = None,
71
+ pidfile_path: Path = None,
72
+ ):
68
73
  """Initialize daemon conflict error with detailed context.
69
-
74
+
70
75
  Args:
71
76
  port: Port number where conflict occurred
72
77
  existing_pid: PID of the existing server process
@@ -79,21 +84,21 @@ class DaemonConflictError(SocketIOServerError):
79
84
  self.existing_server_id = existing_server_id or "unknown"
80
85
  self.process_info = process_info or {}
81
86
  self.pidfile_path = pidfile_path
82
-
87
+
83
88
  # Build detailed error message with resolution steps
84
89
  message = self._build_error_message()
85
-
90
+
86
91
  context = {
87
92
  "port": port,
88
93
  "existing_pid": existing_pid,
89
94
  "existing_server_id": self.existing_server_id,
90
95
  "process_info": process_info,
91
96
  "pidfile_path": str(pidfile_path) if pidfile_path else None,
92
- "resolution_steps": self._get_resolution_steps()
97
+ "resolution_steps": self._get_resolution_steps(),
93
98
  }
94
-
99
+
95
100
  super().__init__(message, "daemon_conflict", context)
96
-
101
+
97
102
  def _build_error_message(self) -> str:
98
103
  """Build comprehensive error message with process details."""
99
104
  lines = [
@@ -103,46 +108,54 @@ class DaemonConflictError(SocketIOServerError):
103
108
  f" • Existing PID: {self.existing_pid}",
104
109
  f" • Server ID: {self.existing_server_id}",
105
110
  ]
106
-
111
+
107
112
  # Add process information if available
108
113
  if self.process_info:
109
- status = self.process_info.get('status', 'unknown')
110
- name = self.process_info.get('name', 'unknown')
111
- create_time = self.process_info.get('create_time')
112
- memory_info = self.process_info.get('memory_info', {})
113
-
114
- lines.extend([
115
- f" • Process Status: {status}",
116
- f" • Process Name: {name}",
117
- ])
118
-
114
+ status = self.process_info.get("status", "unknown")
115
+ name = self.process_info.get("name", "unknown")
116
+ create_time = self.process_info.get("create_time")
117
+ memory_info = self.process_info.get("memory_info", {})
118
+
119
+ lines.extend(
120
+ [
121
+ f" • Process Status: {status}",
122
+ f" • Process Name: {name}",
123
+ ]
124
+ )
125
+
119
126
  if create_time:
120
- start_time = datetime.fromtimestamp(create_time).strftime('%Y-%m-%d %H:%M:%S')
127
+ start_time = datetime.fromtimestamp(create_time).strftime(
128
+ "%Y-%m-%d %H:%M:%S"
129
+ )
121
130
  uptime = time.time() - create_time
122
131
  lines.append(f" • Started: {start_time} (uptime: {uptime:.0f}s)")
123
-
124
- if memory_info.get('rss'):
125
- memory_mb = memory_info['rss'] / (1024 * 1024)
132
+
133
+ if memory_info.get("rss"):
134
+ memory_mb = memory_info["rss"] / (1024 * 1024)
126
135
  lines.append(f" • Memory Usage: {memory_mb:.1f} MB")
127
-
136
+
128
137
  # Add PID file information
129
138
  if self.pidfile_path:
130
- lines.extend([
131
- f" • PID File: {self.pidfile_path}",
132
- f" • File Exists: {self.pidfile_path.exists() if isinstance(self.pidfile_path, Path) else 'unknown'}"
133
- ])
134
-
135
- lines.extend([
136
- f"",
137
- f"RESOLUTION STEPS:",
138
- ])
139
-
139
+ lines.extend(
140
+ [
141
+ f" • PID File: {self.pidfile_path}",
142
+ f" • File Exists: {self.pidfile_path.exists() if isinstance(self.pidfile_path, Path) else 'unknown'}",
143
+ ]
144
+ )
145
+
146
+ lines.extend(
147
+ [
148
+ f"",
149
+ f"RESOLUTION STEPS:",
150
+ ]
151
+ )
152
+
140
153
  # Add resolution steps
141
154
  for i, step in enumerate(self._get_resolution_steps(), 1):
142
155
  lines.append(f" {i}. {step}")
143
-
156
+
144
157
  return "\n".join(lines)
145
-
158
+
146
159
  def _get_resolution_steps(self) -> List[str]:
147
160
  """Get ordered list of resolution steps."""
148
161
  steps = [
@@ -150,52 +163,56 @@ class DaemonConflictError(SocketIOServerError):
150
163
  f"Stop the existing server gracefully: kill -TERM {self.existing_pid}",
151
164
  f"If graceful shutdown fails: kill -KILL {self.existing_pid}",
152
165
  ]
153
-
166
+
154
167
  if self.pidfile_path:
155
168
  steps.append(f"Remove stale PID file if needed: rm {self.pidfile_path}")
156
-
157
- steps.extend([
158
- f"Wait a few seconds for port cleanup",
159
- f"Try starting the server again on port {self.port}",
160
- f"Alternative: Use a different port with --port <new_port>"
161
- ])
162
-
169
+
170
+ steps.extend(
171
+ [
172
+ f"Wait a few seconds for port cleanup",
173
+ f"Try starting the server again on port {self.port}",
174
+ f"Alternative: Use a different port with --port <new_port>",
175
+ ]
176
+ )
177
+
163
178
  return steps
164
179
 
165
180
 
166
181
  class PortConflictError(SocketIOServerError):
167
182
  """Error raised when network port is already in use by another process.
168
-
183
+
169
184
  This error helps identify what process is using the port and provides
170
185
  steps to resolve the conflict.
171
186
  """
172
-
173
- def __init__(self,
174
- port: int,
175
- host: str = "localhost",
176
- conflicting_process: Dict[str, Any] = None):
187
+
188
+ def __init__(
189
+ self,
190
+ port: int,
191
+ host: str = "localhost",
192
+ conflicting_process: Dict[str, Any] = None,
193
+ ):
177
194
  """Initialize port conflict error.
178
-
195
+
179
196
  Args:
180
197
  port: Port number that's in use
181
- host: Host address where the conflict occurred
198
+ host: Host address where the conflict occurred
182
199
  conflicting_process: Information about the process using the port
183
200
  """
184
201
  self.port = port
185
202
  self.host = host
186
203
  self.conflicting_process = conflicting_process or {}
187
-
204
+
188
205
  message = self._build_error_message()
189
-
206
+
190
207
  context = {
191
208
  "port": port,
192
209
  "host": host,
193
210
  "conflicting_process": conflicting_process,
194
- "resolution_steps": self._get_resolution_steps()
211
+ "resolution_steps": self._get_resolution_steps(),
195
212
  }
196
-
213
+
197
214
  super().__init__(message, "port_conflict", context)
198
-
215
+
199
216
  def _build_error_message(self) -> str:
200
217
  """Build error message with port conflict details."""
201
218
  lines = [
@@ -206,81 +223,90 @@ class PortConflictError(SocketIOServerError):
206
223
  f" • Host: {self.host}",
207
224
  f" • Address: {self.host}:{self.port}",
208
225
  ]
209
-
226
+
210
227
  # Add information about conflicting process if available
211
228
  if self.conflicting_process:
212
- pid = self.conflicting_process.get('pid')
213
- name = self.conflicting_process.get('name', 'unknown')
214
- cmdline = self.conflicting_process.get('cmdline', [])
215
-
216
- lines.extend([
217
- f"",
218
- f"CONFLICTING PROCESS:",
219
- f" PID: {pid or 'unknown'}",
220
- f" • Name: {name}",
221
- ])
222
-
229
+ pid = self.conflicting_process.get("pid")
230
+ name = self.conflicting_process.get("name", "unknown")
231
+ cmdline = self.conflicting_process.get("cmdline", [])
232
+
233
+ lines.extend(
234
+ [
235
+ f"",
236
+ f"CONFLICTING PROCESS:",
237
+ f" • PID: {pid or 'unknown'}",
238
+ f" • Name: {name}",
239
+ ]
240
+ )
241
+
223
242
  if cmdline:
224
243
  lines.append(f" • Command: {' '.join(cmdline)}")
225
-
226
- lines.extend([
227
- f"",
228
- f"RESOLUTION STEPS:",
229
- ])
230
-
244
+
245
+ lines.extend(
246
+ [
247
+ f"",
248
+ f"RESOLUTION STEPS:",
249
+ ]
250
+ )
251
+
231
252
  for i, step in enumerate(self._get_resolution_steps(), 1):
232
253
  lines.append(f" {i}. {step}")
233
-
254
+
234
255
  return "\n".join(lines)
235
-
256
+
236
257
  def _get_resolution_steps(self) -> List[str]:
237
258
  """Get resolution steps for port conflicts."""
238
- steps = [
239
- f"Check what process is using port {self.port}:"
240
- ]
241
-
259
+ steps = [f"Check what process is using port {self.port}:"]
260
+
242
261
  # Add platform-specific commands
243
262
  if platform.system() == "Darwin": # macOS
244
- steps.extend([
245
- f" • lsof -i :{self.port}",
246
- f" • netstat -an | grep {self.port}"
247
- ])
263
+ steps.extend(
264
+ [f" • lsof -i :{self.port}", f" • netstat -an | grep {self.port}"]
265
+ )
248
266
  elif platform.system() == "Linux":
249
- steps.extend([
250
- f" • lsof -i :{self.port}",
251
- f" • netstat -tulpn | grep {self.port}",
252
- f" • ss -tulpn | grep {self.port}"
253
- ])
267
+ steps.extend(
268
+ [
269
+ f" • lsof -i :{self.port}",
270
+ f" • netstat -tulpn | grep {self.port}",
271
+ f" • ss -tulpn | grep {self.port}",
272
+ ]
273
+ )
254
274
  elif platform.system() == "Windows":
255
- steps.extend([
256
- f" • netstat -ano | findstr {self.port}",
257
- f" • tasklist /fi \"PID eq <PID_FROM_NETSTAT>\""
258
- ])
259
-
260
- steps.extend([
261
- f"Stop the conflicting process if it's safe to do so",
262
- f"Wait for port cleanup (may take 30-60 seconds)",
263
- f"Try again with the same port",
264
- f"Alternative: Use a different port: --port {self.port + 1}"
265
- ])
266
-
275
+ steps.extend(
276
+ [
277
+ f" • netstat -ano | findstr {self.port}",
278
+ f' • tasklist /fi "PID eq <PID_FROM_NETSTAT>"',
279
+ ]
280
+ )
281
+
282
+ steps.extend(
283
+ [
284
+ f"Stop the conflicting process if it's safe to do so",
285
+ f"Wait for port cleanup (may take 30-60 seconds)",
286
+ f"Try again with the same port",
287
+ f"Alternative: Use a different port: --port {self.port + 1}",
288
+ ]
289
+ )
290
+
267
291
  return steps
268
292
 
269
293
 
270
294
  class StaleProcessError(SocketIOServerError):
271
295
  """Error raised when dealing with stale processes or PID files.
272
-
296
+
273
297
  This error occurs when a PID file exists but the associated process
274
298
  is no longer running, is a zombie, or has been replaced.
275
299
  """
276
-
277
- def __init__(self,
278
- pid: int,
279
- pidfile_path: Path = None,
280
- process_status: str = "not_found",
281
- validation_errors: List[str] = None):
300
+
301
+ def __init__(
302
+ self,
303
+ pid: int,
304
+ pidfile_path: Path = None,
305
+ process_status: str = "not_found",
306
+ validation_errors: List[str] = None,
307
+ ):
282
308
  """Initialize stale process error.
283
-
309
+
284
310
  Args:
285
311
  pid: Process ID that's stale
286
312
  pidfile_path: Path to the stale PID file
@@ -291,19 +317,19 @@ class StaleProcessError(SocketIOServerError):
291
317
  self.pidfile_path = pidfile_path
292
318
  self.process_status = process_status
293
319
  self.validation_errors = validation_errors or []
294
-
320
+
295
321
  message = self._build_error_message()
296
-
322
+
297
323
  context = {
298
324
  "pid": pid,
299
325
  "pidfile_path": str(pidfile_path) if pidfile_path else None,
300
326
  "process_status": process_status,
301
327
  "validation_errors": validation_errors,
302
- "resolution_steps": self._get_resolution_steps()
328
+ "resolution_steps": self._get_resolution_steps(),
303
329
  }
304
-
330
+
305
331
  super().__init__(message, "stale_process", context)
306
-
332
+
307
333
  def _build_error_message(self) -> str:
308
334
  """Build error message for stale process."""
309
335
  status_descriptions = {
@@ -311,11 +337,13 @@ class StaleProcessError(SocketIOServerError):
311
337
  "zombie": "Process is a zombie (terminated but not reaped)",
312
338
  "invalid": "Process exists but is not the expected server",
313
339
  "access_denied": "Cannot access process information",
314
- "stale_pidfile": "PID file is stale or corrupted"
340
+ "stale_pidfile": "PID file is stale or corrupted",
315
341
  }
316
-
317
- status_desc = status_descriptions.get(self.process_status, f"Process status: {self.process_status}")
318
-
342
+
343
+ status_desc = status_descriptions.get(
344
+ self.process_status, f"Process status: {self.process_status}"
345
+ )
346
+
319
347
  lines = [
320
348
  f"🧟 Stale process detected",
321
349
  f"",
@@ -323,79 +351,91 @@ class StaleProcessError(SocketIOServerError):
323
351
  f" • PID: {self.pid}",
324
352
  f" • Status: {status_desc}",
325
353
  ]
326
-
354
+
327
355
  if self.pidfile_path:
328
- lines.extend([
329
- f" • PID File: {self.pidfile_path}",
330
- f" • File Exists: {self.pidfile_path.exists() if isinstance(self.pidfile_path, Path) else 'unknown'}"
331
- ])
332
-
356
+ lines.extend(
357
+ [
358
+ f" • PID File: {self.pidfile_path}",
359
+ f" • File Exists: {self.pidfile_path.exists() if isinstance(self.pidfile_path, Path) else 'unknown'}",
360
+ ]
361
+ )
362
+
333
363
  if self.validation_errors:
334
- lines.extend([
335
- f"",
336
- f"VALIDATION ERRORS:",
337
- ])
364
+ lines.extend(
365
+ [
366
+ f"",
367
+ f"VALIDATION ERRORS:",
368
+ ]
369
+ )
338
370
  for error in self.validation_errors:
339
371
  lines.append(f" • {error}")
340
-
341
- lines.extend([
342
- f"",
343
- f"RESOLUTION STEPS:",
344
- ])
345
-
372
+
373
+ lines.extend(
374
+ [
375
+ f"",
376
+ f"RESOLUTION STEPS:",
377
+ ]
378
+ )
379
+
346
380
  for i, step in enumerate(self._get_resolution_steps(), 1):
347
381
  lines.append(f" {i}. {step}")
348
-
382
+
349
383
  return "\n".join(lines)
350
-
384
+
351
385
  def _get_resolution_steps(self) -> List[str]:
352
386
  """Get resolution steps for stale processes."""
353
387
  steps = []
354
-
388
+
355
389
  if self.process_status == "zombie":
356
- steps.extend([
357
- "Wait for parent process to reap zombie (usually automatic)",
358
- f"If zombie persists, check parent process: ps -o ppid= -p {self.pid}",
359
- "Restart parent process if necessary"
360
- ])
390
+ steps.extend(
391
+ [
392
+ "Wait for parent process to reap zombie (usually automatic)",
393
+ f"If zombie persists, check parent process: ps -o ppid= -p {self.pid}",
394
+ "Restart parent process if necessary",
395
+ ]
396
+ )
361
397
  elif self.process_status == "not_found":
362
- steps.extend([
363
- f"Process {self.pid} no longer exists - safe to clean up"
364
- ])
398
+ steps.extend([f"Process {self.pid} no longer exists - safe to clean up"])
365
399
  elif self.process_status == "invalid":
366
- steps.extend([
367
- f"Verify process {self.pid} is not a legitimate server:",
368
- f" ps -p {self.pid} -o pid,ppid,cmd",
369
- "If it's not your server, it's safe to clean up the PID file"
370
- ])
371
-
400
+ steps.extend(
401
+ [
402
+ f"Verify process {self.pid} is not a legitimate server:",
403
+ f" ps -p {self.pid} -o pid,ppid,cmd",
404
+ "If it's not your server, it's safe to clean up the PID file",
405
+ ]
406
+ )
407
+
372
408
  # Common cleanup steps
373
409
  if self.pidfile_path:
374
410
  steps.append(f"Remove stale PID file: rm {self.pidfile_path}")
375
-
376
- steps.extend([
377
- "Try starting the server again",
378
- "If issues persist, check for permission problems or disk space"
379
- ])
380
-
411
+
412
+ steps.extend(
413
+ [
414
+ "Try starting the server again",
415
+ "If issues persist, check for permission problems or disk space",
416
+ ]
417
+ )
418
+
381
419
  return steps
382
420
 
383
421
 
384
422
  class RecoveryFailedError(SocketIOServerError):
385
423
  """Error raised when automatic recovery mechanisms fail.
386
-
424
+
387
425
  This error occurs when the health monitoring and recovery system
388
426
  cannot automatically resolve server issues.
389
427
  """
390
-
391
- def __init__(self,
392
- recovery_action: str,
393
- failure_reason: str,
394
- attempt_count: int = 1,
395
- health_status: Dict[str, Any] = None,
396
- last_successful_recovery: str = None):
428
+
429
+ def __init__(
430
+ self,
431
+ recovery_action: str,
432
+ failure_reason: str,
433
+ attempt_count: int = 1,
434
+ health_status: Dict[str, Any] = None,
435
+ last_successful_recovery: str = None,
436
+ ):
397
437
  """Initialize recovery failure error.
398
-
438
+
399
439
  Args:
400
440
  recovery_action: The recovery action that failed (e.g., 'restart', 'cleanup')
401
441
  failure_reason: Why the recovery failed
@@ -408,20 +448,20 @@ class RecoveryFailedError(SocketIOServerError):
408
448
  self.attempt_count = attempt_count
409
449
  self.health_status = health_status or {}
410
450
  self.last_successful_recovery = last_successful_recovery
411
-
451
+
412
452
  message = self._build_error_message()
413
-
453
+
414
454
  context = {
415
455
  "recovery_action": recovery_action,
416
456
  "failure_reason": failure_reason,
417
457
  "attempt_count": attempt_count,
418
458
  "health_status": health_status,
419
459
  "last_successful_recovery": last_successful_recovery,
420
- "resolution_steps": self._get_resolution_steps()
460
+ "resolution_steps": self._get_resolution_steps(),
421
461
  }
422
-
462
+
423
463
  super().__init__(message, "recovery_failed", context)
424
-
464
+
425
465
  def _build_error_message(self) -> str:
426
466
  """Build error message for recovery failure."""
427
467
  lines = [
@@ -432,32 +472,44 @@ class RecoveryFailedError(SocketIOServerError):
432
472
  f" • Failure Reason: {self.failure_reason}",
433
473
  f" • Attempt Count: {self.attempt_count}",
434
474
  ]
435
-
475
+
436
476
  if self.last_successful_recovery:
437
- lines.append(f" • Last Successful Recovery: {self.last_successful_recovery}")
438
-
477
+ lines.append(
478
+ f" • Last Successful Recovery: {self.last_successful_recovery}"
479
+ )
480
+
439
481
  # Add health status information
440
482
  if self.health_status:
441
- lines.extend([
442
- f"",
443
- f"CURRENT HEALTH STATUS:",
444
- ])
445
-
483
+ lines.extend(
484
+ [
485
+ f"",
486
+ f"CURRENT HEALTH STATUS:",
487
+ ]
488
+ )
489
+
446
490
  # Common health metrics
447
491
  for key, value in self.health_status.items():
448
- if key in ['status', 'uptime', 'clients_connected', 'events_processed', 'errors']:
492
+ if key in [
493
+ "status",
494
+ "uptime",
495
+ "clients_connected",
496
+ "events_processed",
497
+ "errors",
498
+ ]:
449
499
  lines.append(f" • {key.replace('_', ' ').title()}: {value}")
450
-
451
- lines.extend([
452
- f"",
453
- f"MANUAL RESOLUTION REQUIRED:",
454
- ])
455
-
500
+
501
+ lines.extend(
502
+ [
503
+ f"",
504
+ f"MANUAL RESOLUTION REQUIRED:",
505
+ ]
506
+ )
507
+
456
508
  for i, step in enumerate(self._get_resolution_steps(), 1):
457
509
  lines.append(f" {i}. {step}")
458
-
510
+
459
511
  return "\n".join(lines)
460
-
512
+
461
513
  def _get_resolution_steps(self) -> List[str]:
462
514
  """Get manual resolution steps for recovery failures."""
463
515
  steps = [
@@ -465,51 +517,61 @@ class RecoveryFailedError(SocketIOServerError):
465
517
  "Verify system resources (CPU, memory, disk space)",
466
518
  "Check network connectivity and port availability",
467
519
  ]
468
-
520
+
469
521
  if self.recovery_action == "restart":
470
- steps.extend([
471
- "Manually stop the server process",
472
- "Wait for complete shutdown (check process list)",
473
- "Remove any stale PID files",
474
- "Restart the server manually"
475
- ])
522
+ steps.extend(
523
+ [
524
+ "Manually stop the server process",
525
+ "Wait for complete shutdown (check process list)",
526
+ "Remove any stale PID files",
527
+ "Restart the server manually",
528
+ ]
529
+ )
476
530
  elif self.recovery_action == "cleanup":
477
- steps.extend([
478
- "Manually identify and clean up stale resources",
479
- "Check for zombie processes",
480
- "Clear temporary files and logs if needed"
481
- ])
531
+ steps.extend(
532
+ [
533
+ "Manually identify and clean up stale resources",
534
+ "Check for zombie processes",
535
+ "Clear temporary files and logs if needed",
536
+ ]
537
+ )
482
538
  elif self.recovery_action == "port_reset":
483
- steps.extend([
484
- "Check what's using the required port",
485
- "Stop conflicting processes",
486
- "Wait for port cleanup",
487
- "Consider using a different port temporarily"
488
- ])
489
-
490
- steps.extend([
491
- "Review health monitoring configuration",
492
- "Consider adjusting recovery thresholds if appropriate",
493
- "Monitor server stability after manual intervention"
494
- ])
495
-
539
+ steps.extend(
540
+ [
541
+ "Check what's using the required port",
542
+ "Stop conflicting processes",
543
+ "Wait for port cleanup",
544
+ "Consider using a different port temporarily",
545
+ ]
546
+ )
547
+
548
+ steps.extend(
549
+ [
550
+ "Review health monitoring configuration",
551
+ "Consider adjusting recovery thresholds if appropriate",
552
+ "Monitor server stability after manual intervention",
553
+ ]
554
+ )
555
+
496
556
  return steps
497
557
 
498
558
 
499
559
  class HealthCheckError(SocketIOServerError):
500
560
  """Error raised when health monitoring detects critical issues.
501
-
561
+
502
562
  This error provides detailed health status information and guidance
503
563
  for addressing system health problems.
504
564
  """
505
-
506
- def __init__(self,
507
- check_name: str,
508
- check_status: str,
509
- check_details: Dict[str, Any] = None,
510
- threshold_exceeded: Dict[str, Any] = None):
565
+
566
+ def __init__(
567
+ self,
568
+ check_name: str,
569
+ check_status: str,
570
+ check_details: Dict[str, Any] = None,
571
+ threshold_exceeded: Dict[str, Any] = None,
572
+ ):
511
573
  """Initialize health check error.
512
-
574
+
513
575
  Args:
514
576
  check_name: Name of the failed health check
515
577
  check_status: Status of the health check (critical, warning, failed)
@@ -520,29 +582,25 @@ class HealthCheckError(SocketIOServerError):
520
582
  self.check_status = check_status
521
583
  self.check_details = check_details or {}
522
584
  self.threshold_exceeded = threshold_exceeded or {}
523
-
585
+
524
586
  message = self._build_error_message()
525
-
587
+
526
588
  context = {
527
589
  "check_name": check_name,
528
590
  "check_status": check_status,
529
591
  "check_details": check_details,
530
592
  "threshold_exceeded": threshold_exceeded,
531
- "resolution_steps": self._get_resolution_steps()
593
+ "resolution_steps": self._get_resolution_steps(),
532
594
  }
533
-
595
+
534
596
  super().__init__(message, "health_check_failed", context)
535
-
597
+
536
598
  def _build_error_message(self) -> str:
537
599
  """Build error message for health check failure."""
538
- status_emoji = {
539
- "critical": "🚨",
540
- "warning": "⚠️",
541
- "failed": "❌"
542
- }
543
-
600
+ status_emoji = {"critical": "🚨", "warning": "⚠️", "failed": "❌"}
601
+
544
602
  emoji = status_emoji.get(self.check_status, "🔍")
545
-
603
+
546
604
  lines = [
547
605
  f"{emoji} Health check failed: {self.check_name}",
548
606
  f"",
@@ -550,81 +608,100 @@ class HealthCheckError(SocketIOServerError):
550
608
  f" • Check: {self.check_name}",
551
609
  f" • Status: {self.check_status.upper()}",
552
610
  ]
553
-
611
+
554
612
  # Add check details
555
613
  if self.check_details:
556
614
  for key, value in self.check_details.items():
557
- if key not in ['raw_data', 'internal_state']: # Skip internal data
615
+ if key not in ["raw_data", "internal_state"]: # Skip internal data
558
616
  lines.append(f" • {key.replace('_', ' ').title()}: {value}")
559
-
617
+
560
618
  # Add threshold information
561
619
  if self.threshold_exceeded:
562
- lines.extend([
563
- f"",
564
- f"THRESHOLDS EXCEEDED:",
565
- ])
620
+ lines.extend(
621
+ [
622
+ f"",
623
+ f"THRESHOLDS EXCEEDED:",
624
+ ]
625
+ )
566
626
  for metric, info in self.threshold_exceeded.items():
567
- current = info.get('current', 'unknown')
568
- threshold = info.get('threshold', 'unknown')
569
- lines.append(f" • {metric.title()}: {current} (threshold: {threshold})")
570
-
571
- lines.extend([
572
- f"",
573
- f"RECOMMENDED ACTIONS:",
574
- ])
575
-
627
+ current = info.get("current", "unknown")
628
+ threshold = info.get("threshold", "unknown")
629
+ lines.append(
630
+ f" • {metric.title()}: {current} (threshold: {threshold})"
631
+ )
632
+
633
+ lines.extend(
634
+ [
635
+ f"",
636
+ f"RECOMMENDED ACTIONS:",
637
+ ]
638
+ )
639
+
576
640
  for i, step in enumerate(self._get_resolution_steps(), 1):
577
641
  lines.append(f" {i}. {step}")
578
-
642
+
579
643
  return "\n".join(lines)
580
-
644
+
581
645
  def _get_resolution_steps(self) -> List[str]:
582
646
  """Get resolution steps based on health check type."""
583
647
  steps = []
584
-
648
+
585
649
  if "cpu" in self.check_name.lower():
586
- steps.extend([
587
- "Check for runaway processes consuming CPU",
588
- "Consider adding rate limiting or request throttling",
589
- "Monitor CPU usage patterns over time"
590
- ])
650
+ steps.extend(
651
+ [
652
+ "Check for runaway processes consuming CPU",
653
+ "Consider adding rate limiting or request throttling",
654
+ "Monitor CPU usage patterns over time",
655
+ ]
656
+ )
591
657
  elif "memory" in self.check_name.lower():
592
- steps.extend([
593
- "Check for memory leaks in the application",
594
- "Monitor memory usage trends",
595
- "Consider restarting if memory usage is excessive",
596
- "Review event history size limits"
597
- ])
598
- elif "network" in self.check_name.lower() or "connectivity" in self.check_name.lower():
599
- steps.extend([
600
- "Check network connectivity to required services",
601
- "Verify firewall settings and port accessibility",
602
- "Test network latency and bandwidth"
603
- ])
658
+ steps.extend(
659
+ [
660
+ "Check for memory leaks in the application",
661
+ "Monitor memory usage trends",
662
+ "Consider restarting if memory usage is excessive",
663
+ "Review event history size limits",
664
+ ]
665
+ )
666
+ elif (
667
+ "network" in self.check_name.lower()
668
+ or "connectivity" in self.check_name.lower()
669
+ ):
670
+ steps.extend(
671
+ [
672
+ "Check network connectivity to required services",
673
+ "Verify firewall settings and port accessibility",
674
+ "Test network latency and bandwidth",
675
+ ]
676
+ )
604
677
  elif "disk" in self.check_name.lower() or "file" in self.check_name.lower():
605
- steps.extend([
606
- "Check available disk space",
607
- "Clean up old log files and temporary data",
608
- "Verify file permissions and access"
609
- ])
610
-
678
+ steps.extend(
679
+ [
680
+ "Check available disk space",
681
+ "Clean up old log files and temporary data",
682
+ "Verify file permissions and access",
683
+ ]
684
+ )
685
+
611
686
  # General steps for all health check failures
612
- steps.extend([
613
- "Review recent system changes or deployments",
614
- "Check system logs for related errors",
615
- "Consider adjusting health check thresholds if appropriate",
616
- "Monitor the issue to identify patterns or trends"
617
- ])
618
-
687
+ steps.extend(
688
+ [
689
+ "Review recent system changes or deployments",
690
+ "Check system logs for related errors",
691
+ "Consider adjusting health check thresholds if appropriate",
692
+ "Monitor the issue to identify patterns or trends",
693
+ ]
694
+ )
695
+
619
696
  return steps
620
697
 
621
698
 
622
699
  def format_troubleshooting_guide(error: SocketIOServerError) -> str:
623
700
  """Format a comprehensive troubleshooting guide for any Socket.IO server error.
624
-
701
+
625
702
  Args:
626
703
  error: The error instance to create troubleshooting guide for
627
-
704
+
628
705
  Returns:
629
706
  Formatted troubleshooting guide as a string
630
707
  """
@@ -663,15 +740,17 @@ def format_troubleshooting_guide(error: SocketIOServerError) -> str:
663
740
  f"",
664
741
  f"🔗 ERROR CONTEXT DATA:",
665
742
  ]
666
-
743
+
667
744
  # Add structured context data
668
745
  for key, value in error.context.items():
669
746
  if key != "resolution_steps": # Skip resolution steps as they're already shown
670
747
  lines.append(f" • {key}: {value}")
671
-
672
- lines.extend([
673
- f"",
674
- f"═══════════════════════════════════════════════════════════════",
675
- ])
676
-
677
- return "\n".join(lines)
748
+
749
+ lines.extend(
750
+ [
751
+ f"",
752
+ f"═══════════════════════════════════════════════════════════════",
753
+ ]
754
+ )
755
+
756
+ return "\n".join(lines)