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.
- claude_mpm/VERSION +1 -1
- claude_mpm/__init__.py +2 -2
- claude_mpm/__main__.py +3 -2
- claude_mpm/agents/__init__.py +85 -79
- claude_mpm/agents/agent_loader.py +464 -1003
- claude_mpm/agents/agent_loader_integration.py +45 -45
- claude_mpm/agents/agents_metadata.py +29 -30
- claude_mpm/agents/async_agent_loader.py +156 -138
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/base_agent_loader.py +179 -151
- claude_mpm/agents/frontmatter_validator.py +229 -130
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +213 -147
- claude_mpm/agents/templates/__init__.py +13 -13
- claude_mpm/agents/templates/code_analyzer.json +2 -2
- claude_mpm/agents/templates/data_engineer.json +1 -1
- claude_mpm/agents/templates/documentation.json +23 -11
- claude_mpm/agents/templates/engineer.json +22 -6
- claude_mpm/agents/templates/memory_manager.json +1 -1
- claude_mpm/agents/templates/ops.json +2 -2
- claude_mpm/agents/templates/project_organizer.json +1 -1
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/refactoring_engineer.json +222 -0
- claude_mpm/agents/templates/research.json +20 -14
- claude_mpm/agents/templates/security.json +1 -1
- claude_mpm/agents/templates/ticketing.json +1 -1
- claude_mpm/agents/templates/version_control.json +1 -1
- claude_mpm/agents/templates/web_qa.json +3 -1
- claude_mpm/agents/templates/web_ui.json +2 -2
- claude_mpm/cli/__init__.py +79 -51
- claude_mpm/cli/__main__.py +3 -2
- claude_mpm/cli/commands/__init__.py +20 -20
- claude_mpm/cli/commands/agents.py +279 -247
- claude_mpm/cli/commands/aggregate.py +138 -157
- claude_mpm/cli/commands/cleanup.py +147 -147
- claude_mpm/cli/commands/config.py +93 -76
- claude_mpm/cli/commands/info.py +17 -16
- claude_mpm/cli/commands/mcp.py +140 -905
- claude_mpm/cli/commands/mcp_command_router.py +139 -0
- claude_mpm/cli/commands/mcp_config_commands.py +20 -0
- claude_mpm/cli/commands/mcp_install_commands.py +20 -0
- claude_mpm/cli/commands/mcp_server_commands.py +175 -0
- claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
- claude_mpm/cli/commands/memory.py +239 -203
- claude_mpm/cli/commands/monitor.py +203 -81
- claude_mpm/cli/commands/run.py +380 -429
- claude_mpm/cli/commands/run_config_checker.py +160 -0
- claude_mpm/cli/commands/socketio_monitor.py +235 -0
- claude_mpm/cli/commands/tickets.py +305 -197
- claude_mpm/cli/parser.py +24 -1156
- claude_mpm/cli/parsers/__init__.py +29 -0
- claude_mpm/cli/parsers/agents_parser.py +136 -0
- claude_mpm/cli/parsers/base_parser.py +331 -0
- claude_mpm/cli/parsers/config_parser.py +85 -0
- claude_mpm/cli/parsers/mcp_parser.py +152 -0
- claude_mpm/cli/parsers/memory_parser.py +138 -0
- claude_mpm/cli/parsers/monitor_parser.py +104 -0
- claude_mpm/cli/parsers/run_parser.py +147 -0
- claude_mpm/cli/parsers/tickets_parser.py +203 -0
- claude_mpm/cli/ticket_cli.py +7 -3
- claude_mpm/cli/utils.py +55 -37
- claude_mpm/cli_module/__init__.py +6 -6
- claude_mpm/cli_module/args.py +188 -140
- claude_mpm/cli_module/commands.py +79 -70
- claude_mpm/cli_module/migration_example.py +38 -60
- claude_mpm/config/__init__.py +32 -25
- claude_mpm/config/agent_config.py +151 -119
- claude_mpm/config/experimental_features.py +71 -73
- claude_mpm/config/paths.py +94 -208
- claude_mpm/config/socketio_config.py +84 -73
- claude_mpm/constants.py +35 -18
- claude_mpm/core/__init__.py +9 -6
- claude_mpm/core/agent_name_normalizer.py +68 -71
- claude_mpm/core/agent_registry.py +372 -521
- claude_mpm/core/agent_session_manager.py +74 -63
- claude_mpm/core/base_service.py +116 -87
- claude_mpm/core/cache.py +119 -153
- claude_mpm/core/claude_runner.py +425 -1120
- claude_mpm/core/config.py +263 -168
- claude_mpm/core/config_aliases.py +69 -61
- claude_mpm/core/config_constants.py +292 -0
- claude_mpm/core/constants.py +57 -99
- claude_mpm/core/container.py +211 -178
- claude_mpm/core/exceptions.py +233 -89
- claude_mpm/core/factories.py +92 -54
- claude_mpm/core/framework_loader.py +378 -220
- claude_mpm/core/hook_manager.py +198 -83
- claude_mpm/core/hook_performance_config.py +136 -0
- claude_mpm/core/injectable_service.py +61 -55
- claude_mpm/core/interactive_session.py +165 -155
- claude_mpm/core/interfaces.py +221 -195
- claude_mpm/core/lazy.py +96 -96
- claude_mpm/core/logger.py +133 -107
- claude_mpm/core/logging_config.py +185 -157
- claude_mpm/core/minimal_framework_loader.py +20 -15
- claude_mpm/core/mixins.py +30 -29
- claude_mpm/core/oneshot_session.py +215 -181
- claude_mpm/core/optimized_agent_loader.py +134 -138
- claude_mpm/core/optimized_startup.py +159 -157
- claude_mpm/core/pm_hook_interceptor.py +85 -72
- claude_mpm/core/service_registry.py +103 -101
- claude_mpm/core/session_manager.py +97 -87
- claude_mpm/core/socketio_pool.py +212 -158
- claude_mpm/core/tool_access_control.py +58 -51
- claude_mpm/core/types.py +46 -24
- claude_mpm/core/typing_utils.py +166 -82
- claude_mpm/core/unified_agent_registry.py +721 -0
- claude_mpm/core/unified_config.py +550 -0
- claude_mpm/core/unified_paths.py +549 -0
- claude_mpm/dashboard/index.html +1 -1
- claude_mpm/dashboard/open_dashboard.py +51 -17
- claude_mpm/dashboard/static/css/dashboard.css +27 -8
- claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
- claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
- claude_mpm/dashboard/static/dist/dashboard.js +2 -0
- claude_mpm/dashboard/static/dist/socket-client.js +2 -0
- claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
- claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
- claude_mpm/dashboard/static/js/components/event-viewer.js +74 -70
- claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +106 -92
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
- claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
- claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
- claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
- claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
- claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
- claude_mpm/dashboard/static/js/dashboard.js +178 -453
- claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
- claude_mpm/dashboard/static/js/socket-client.js +120 -54
- claude_mpm/dashboard/templates/index.html +40 -50
- claude_mpm/experimental/cli_enhancements.py +60 -58
- claude_mpm/generators/__init__.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +75 -65
- claude_mpm/hooks/__init__.py +1 -1
- claude_mpm/hooks/base_hook.py +33 -28
- claude_mpm/hooks/claude_hooks/__init__.py +1 -1
- claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
- claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
- claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
- claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
- claude_mpm/hooks/memory_integration_hook.py +140 -100
- claude_mpm/hooks/tool_call_interceptor.py +89 -76
- claude_mpm/hooks/validation_hooks.py +57 -49
- claude_mpm/init.py +145 -121
- claude_mpm/models/__init__.py +9 -9
- claude_mpm/models/agent_definition.py +33 -23
- claude_mpm/models/agent_session.py +228 -200
- claude_mpm/scripts/__init__.py +1 -1
- claude_mpm/scripts/socketio_daemon.py +192 -75
- claude_mpm/scripts/socketio_server_manager.py +328 -0
- claude_mpm/scripts/start_activity_logging.py +25 -22
- claude_mpm/services/__init__.py +68 -43
- claude_mpm/services/agent_capabilities_service.py +271 -0
- claude_mpm/services/agents/__init__.py +23 -32
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
- claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
- claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
- claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
- claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
- claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
- claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
- claude_mpm/services/agents/deployment/agent_validator.py +352 -0
- claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
- claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
- claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
- claude_mpm/services/agents/deployment/config/__init__.py +13 -0
- claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
- claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
- claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
- claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
- claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
- claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
- claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
- claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
- claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
- claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
- claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
- claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
- claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
- claude_mpm/services/agents/deployment/results/__init__.py +13 -0
- claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
- claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
- claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
- claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
- claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
- claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
- claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
- claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
- claude_mpm/services/agents/loading/__init__.py +2 -2
- claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
- claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
- claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
- claude_mpm/services/agents/management/__init__.py +2 -2
- claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
- claude_mpm/services/agents/management/agent_management_service.py +209 -156
- claude_mpm/services/agents/memory/__init__.py +9 -6
- claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
- claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
- claude_mpm/services/agents/memory/analyzer.py +430 -0
- claude_mpm/services/agents/memory/content_manager.py +376 -0
- claude_mpm/services/agents/memory/template_generator.py +468 -0
- claude_mpm/services/agents/registry/__init__.py +7 -10
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
- claude_mpm/services/agents/registry/modification_tracker.py +351 -285
- claude_mpm/services/async_session_logger.py +187 -153
- claude_mpm/services/claude_session_logger.py +87 -72
- claude_mpm/services/command_handler_service.py +217 -0
- claude_mpm/services/communication/__init__.py +3 -2
- claude_mpm/services/core/__init__.py +50 -97
- claude_mpm/services/core/base.py +60 -53
- claude_mpm/services/core/interfaces/__init__.py +188 -0
- claude_mpm/services/core/interfaces/agent.py +351 -0
- claude_mpm/services/core/interfaces/communication.py +343 -0
- claude_mpm/services/core/interfaces/infrastructure.py +413 -0
- claude_mpm/services/core/interfaces/service.py +434 -0
- claude_mpm/services/core/interfaces.py +19 -944
- claude_mpm/services/event_aggregator.py +208 -170
- claude_mpm/services/exceptions.py +387 -308
- claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
- claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
- claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
- claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
- claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
- claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
- claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
- claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
- claude_mpm/services/hook_service.py +106 -114
- claude_mpm/services/infrastructure/__init__.py +7 -5
- claude_mpm/services/infrastructure/context_preservation.py +233 -199
- claude_mpm/services/infrastructure/daemon_manager.py +279 -0
- claude_mpm/services/infrastructure/logging.py +83 -76
- claude_mpm/services/infrastructure/monitoring.py +547 -404
- claude_mpm/services/mcp_gateway/__init__.py +30 -13
- claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
- claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
- claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
- claude_mpm/services/mcp_gateway/core/__init__.py +13 -20
- claude_mpm/services/mcp_gateway/core/base.py +80 -67
- claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
- claude_mpm/services/mcp_gateway/core/interfaces.py +87 -84
- claude_mpm/services/mcp_gateway/main.py +287 -137
- claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +97 -94
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
- claude_mpm/services/mcp_gateway/server/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +105 -110
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
- claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
- claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +109 -119
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
- claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
- claude_mpm/services/memory/__init__.py +2 -2
- claude_mpm/services/memory/builder.py +451 -362
- claude_mpm/services/memory/cache/__init__.py +2 -2
- claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
- claude_mpm/services/memory/cache/simple_cache.py +107 -93
- claude_mpm/services/memory/indexed_memory.py +195 -193
- claude_mpm/services/memory/optimizer.py +267 -234
- claude_mpm/services/memory/router.py +571 -263
- claude_mpm/services/memory_hook_service.py +237 -0
- claude_mpm/services/port_manager.py +223 -0
- claude_mpm/services/project/__init__.py +3 -3
- claude_mpm/services/project/analyzer.py +451 -305
- claude_mpm/services/project/registry.py +262 -240
- claude_mpm/services/recovery_manager.py +287 -231
- claude_mpm/services/response_tracker.py +87 -67
- claude_mpm/services/runner_configuration_service.py +587 -0
- claude_mpm/services/session_management_service.py +304 -0
- claude_mpm/services/socketio/__init__.py +4 -4
- claude_mpm/services/socketio/client_proxy.py +174 -0
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +44 -30
- claude_mpm/services/socketio/handlers/connection.py +145 -65
- claude_mpm/services/socketio/handlers/file.py +123 -108
- claude_mpm/services/socketio/handlers/git.py +607 -373
- claude_mpm/services/socketio/handlers/hook.py +170 -0
- claude_mpm/services/socketio/handlers/memory.py +4 -4
- claude_mpm/services/socketio/handlers/project.py +4 -4
- claude_mpm/services/socketio/handlers/registry.py +53 -38
- claude_mpm/services/socketio/server/__init__.py +18 -0
- claude_mpm/services/socketio/server/broadcaster.py +252 -0
- claude_mpm/services/socketio/server/core.py +399 -0
- claude_mpm/services/socketio/server/main.py +323 -0
- claude_mpm/services/socketio_client_manager.py +160 -133
- claude_mpm/services/socketio_server.py +36 -1885
- claude_mpm/services/subprocess_launcher_service.py +316 -0
- claude_mpm/services/system_instructions_service.py +258 -0
- claude_mpm/services/ticket_manager.py +19 -533
- claude_mpm/services/utility_service.py +285 -0
- claude_mpm/services/version_control/__init__.py +18 -21
- claude_mpm/services/version_control/branch_strategy.py +20 -10
- claude_mpm/services/version_control/conflict_resolution.py +37 -13
- claude_mpm/services/version_control/git_operations.py +52 -21
- claude_mpm/services/version_control/semantic_versioning.py +92 -53
- claude_mpm/services/version_control/version_parser.py +145 -125
- claude_mpm/services/version_service.py +270 -0
- claude_mpm/storage/__init__.py +2 -2
- claude_mpm/storage/state_storage.py +177 -181
- claude_mpm/ticket_wrapper.py +2 -2
- claude_mpm/utils/__init__.py +2 -2
- claude_mpm/utils/agent_dependency_loader.py +453 -243
- claude_mpm/utils/config_manager.py +157 -118
- claude_mpm/utils/console.py +1 -1
- claude_mpm/utils/dependency_cache.py +102 -107
- claude_mpm/utils/dependency_manager.py +52 -47
- claude_mpm/utils/dependency_strategies.py +131 -96
- claude_mpm/utils/environment_context.py +110 -102
- claude_mpm/utils/error_handler.py +75 -55
- claude_mpm/utils/file_utils.py +80 -67
- claude_mpm/utils/framework_detection.py +12 -11
- claude_mpm/utils/import_migration_example.py +12 -60
- claude_mpm/utils/imports.py +48 -45
- claude_mpm/utils/path_operations.py +100 -93
- claude_mpm/utils/robust_installer.py +172 -164
- claude_mpm/utils/session_logging.py +30 -23
- claude_mpm/utils/subprocess_utils.py +99 -61
- claude_mpm/validation/__init__.py +1 -1
- claude_mpm/validation/agent_validator.py +151 -111
- claude_mpm/validation/frontmatter_validator.py +92 -71
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/METADATA +27 -1
- claude_mpm-4.0.3.dist-info/RECORD +402 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/licenses/LICENSE +1 -1
- claude_mpm/cli/commands/run_guarded.py +0 -511
- claude_mpm/config/memory_guardian_config.py +0 -325
- claude_mpm/config/memory_guardian_yaml.py +0 -335
- claude_mpm/core/config_paths.py +0 -150
- claude_mpm/core/memory_aware_runner.py +0 -353
- claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
- claude_mpm/deployment_paths.py +0 -261
- claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
- claude_mpm/models/state_models.py +0 -433
- claude_mpm/services/agent/__init__.py +0 -24
- claude_mpm/services/agent/deployment.py +0 -2548
- claude_mpm/services/agent/management.py +0 -598
- claude_mpm/services/agent/registry.py +0 -813
- claude_mpm/services/agents/registry/agent_registry.py +0 -813
- claude_mpm/services/communication/socketio.py +0 -1935
- claude_mpm/services/communication/websocket.py +0 -479
- claude_mpm/services/framework_claude_md_generator.py +0 -624
- claude_mpm/services/health_monitor.py +0 -893
- claude_mpm/services/infrastructure/graceful_degradation.py +0 -616
- claude_mpm/services/infrastructure/health_monitor.py +0 -775
- claude_mpm/services/infrastructure/memory_dashboard.py +0 -479
- claude_mpm/services/infrastructure/memory_guardian.py +0 -944
- claude_mpm/services/infrastructure/restart_protection.py +0 -642
- claude_mpm/services/infrastructure/state_manager.py +0 -774
- claude_mpm/services/mcp_gateway/manager.py +0 -334
- claude_mpm/services/optimized_hook_service.py +0 -542
- claude_mpm/services/project_analyzer.py +0 -864
- claude_mpm/services/project_registry.py +0 -608
- claude_mpm/services/standalone_socketio_server.py +0 -1300
- claude_mpm/services/ticket_manager_di.py +0 -318
- claude_mpm/services/ticketing_service_original.py +0 -510
- claude_mpm/utils/paths.py +0 -395
- claude_mpm/utils/platform_memory.py +0 -524
- claude_mpm-3.9.11.dist-info/RECORD +0 -306
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/WHEEL +0 -0
- {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,  | 
| 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__( | 
| 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__( | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 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( | 
| 110 | 
            -
                        name = self.process_info.get( | 
| 111 | 
            -
                        create_time = self.process_info.get( | 
| 112 | 
            -
                        memory_info = self.process_info.get( | 
| 113 | 
            -
             | 
| 114 | 
            -
                        lines.extend( | 
| 115 | 
            -
                             | 
| 116 | 
            -
             | 
| 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( | 
| 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( | 
| 125 | 
            -
                            memory_mb = memory_info[ | 
| 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 | 
            -
                             | 
| 132 | 
            -
             | 
| 133 | 
            -
             | 
| 134 | 
            -
             | 
| 135 | 
            -
             | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 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 | 
            -
                         | 
| 159 | 
            -
             | 
| 160 | 
            -
             | 
| 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__( | 
| 174 | 
            -
             | 
| 175 | 
            -
             | 
| 176 | 
            -
             | 
| 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( | 
| 213 | 
            -
                        name = self.conflicting_process.get( | 
| 214 | 
            -
                        cmdline = self.conflicting_process.get( | 
| 215 | 
            -
             | 
| 216 | 
            -
                        lines.extend( | 
| 217 | 
            -
                             | 
| 218 | 
            -
             | 
| 219 | 
            -
             | 
| 220 | 
            -
             | 
| 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 | 
            -
                         | 
| 228 | 
            -
             | 
| 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 | 
            -
             | 
| 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 | 
            -
             | 
| 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 | 
            -
                             | 
| 251 | 
            -
             | 
| 252 | 
            -
             | 
| 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 | 
            -
                             | 
| 257 | 
            -
             | 
| 258 | 
            -
             | 
| 259 | 
            -
             | 
| 260 | 
            -
             | 
| 261 | 
            -
             | 
| 262 | 
            -
             | 
| 263 | 
            -
                         | 
| 264 | 
            -
             | 
| 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__( | 
| 278 | 
            -
             | 
| 279 | 
            -
             | 
| 280 | 
            -
             | 
| 281 | 
            -
             | 
| 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( | 
| 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 | 
            -
                             | 
| 330 | 
            -
             | 
| 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 | 
            -
                             | 
| 336 | 
            -
             | 
| 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 | 
            -
                         | 
| 343 | 
            -
             | 
| 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 | 
            -
                             | 
| 358 | 
            -
             | 
| 359 | 
            -
             | 
| 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 | 
            -
                             | 
| 368 | 
            -
             | 
| 369 | 
            -
             | 
| 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 | 
            -
                         | 
| 378 | 
            -
             | 
| 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__( | 
| 392 | 
            -
             | 
| 393 | 
            -
             | 
| 394 | 
            -
             | 
| 395 | 
            -
             | 
| 396 | 
            -
             | 
| 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( | 
| 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 | 
            -
                             | 
| 443 | 
            -
             | 
| 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 [ | 
| 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 | 
            -
                         | 
| 453 | 
            -
             | 
| 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 | 
            -
                             | 
| 472 | 
            -
             | 
| 473 | 
            -
             | 
| 474 | 
            -
             | 
| 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 | 
            -
                             | 
| 479 | 
            -
             | 
| 480 | 
            -
             | 
| 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 | 
            -
                             | 
| 485 | 
            -
             | 
| 486 | 
            -
             | 
| 487 | 
            -
             | 
| 488 | 
            -
             | 
| 489 | 
            -
             | 
| 490 | 
            -
             | 
| 491 | 
            -
             | 
| 492 | 
            -
             | 
| 493 | 
            -
                         | 
| 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__( | 
| 507 | 
            -
             | 
| 508 | 
            -
             | 
| 509 | 
            -
             | 
| 510 | 
            -
             | 
| 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 | 
            -
             | 
| 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 [ | 
| 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 | 
            -
                             | 
| 564 | 
            -
             | 
| 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( | 
| 568 | 
            -
                            threshold = info.get( | 
| 569 | 
            -
                            lines.append( | 
| 570 | 
            -
             | 
| 571 | 
            -
             | 
| 572 | 
            -
             | 
| 573 | 
            -
             | 
| 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 | 
            -
                             | 
| 588 | 
            -
             | 
| 589 | 
            -
             | 
| 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 | 
            -
                             | 
| 594 | 
            -
             | 
| 595 | 
            -
             | 
| 596 | 
            -
             | 
| 597 | 
            -
             | 
| 598 | 
            -
             | 
| 599 | 
            -
                         | 
| 600 | 
            -
             | 
| 601 | 
            -
             | 
| 602 | 
            -
             | 
| 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 | 
            -
                             | 
| 607 | 
            -
             | 
| 608 | 
            -
             | 
| 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 | 
            -
                         | 
| 614 | 
            -
             | 
| 615 | 
            -
             | 
| 616 | 
            -
             | 
| 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 | 
            -
                     | 
| 674 | 
            -
             | 
| 675 | 
            -
             | 
| 676 | 
            -
             | 
| 677 | 
            -
                 | 
| 748 | 
            +
             | 
| 749 | 
            +
                lines.extend(
         | 
| 750 | 
            +
                    [
         | 
| 751 | 
            +
                        f"",
         | 
| 752 | 
            +
                        f"═══════════════════════════════════════════════════════════════",
         | 
| 753 | 
            +
                    ]
         | 
| 754 | 
            +
                )
         | 
| 755 | 
            +
             | 
| 756 | 
            +
                return "\n".join(lines)
         |