claude-mpm 4.1.0__py3-none-any.whl → 4.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/__main__.py +1 -1
- claude_mpm/agents/BASE_PM.md +74 -46
- claude_mpm/agents/INSTRUCTIONS.md +11 -153
- claude_mpm/agents/WORKFLOW.md +61 -321
- claude_mpm/agents/__init__.py +11 -11
- claude_mpm/agents/agent_loader.py +23 -20
- claude_mpm/agents/agent_loader_integration.py +1 -1
- claude_mpm/agents/agents_metadata.py +27 -0
- claude_mpm/agents/async_agent_loader.py +5 -8
- claude_mpm/agents/base_agent_loader.py +36 -25
- claude_mpm/agents/frontmatter_validator.py +6 -6
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +9 -9
- claude_mpm/agents/templates/api_qa.json +47 -2
- claude_mpm/agents/templates/imagemagick.json +256 -0
- claude_mpm/agents/templates/qa.json +41 -2
- claude_mpm/agents/templates/ticketing.json +5 -5
- claude_mpm/agents/templates/web_qa.json +133 -58
- claude_mpm/agents/templates/web_ui.json +3 -3
- claude_mpm/cli/__init__.py +51 -46
- claude_mpm/cli/__main__.py +1 -1
- claude_mpm/cli/commands/__init__.py +10 -12
- claude_mpm/cli/commands/agent_manager.py +186 -181
- claude_mpm/cli/commands/agents.py +271 -268
- claude_mpm/cli/commands/aggregate.py +30 -29
- claude_mpm/cli/commands/cleanup.py +50 -44
- claude_mpm/cli/commands/cleanup_orphaned_agents.py +25 -25
- claude_mpm/cli/commands/config.py +162 -127
- claude_mpm/cli/commands/doctor.py +52 -62
- claude_mpm/cli/commands/info.py +37 -25
- claude_mpm/cli/commands/mcp.py +3 -7
- claude_mpm/cli/commands/mcp_command_router.py +14 -18
- claude_mpm/cli/commands/mcp_install_commands.py +28 -23
- claude_mpm/cli/commands/mcp_pipx_config.py +58 -49
- claude_mpm/cli/commands/mcp_server_commands.py +23 -17
- claude_mpm/cli/commands/memory.py +192 -141
- claude_mpm/cli/commands/monitor.py +117 -88
- claude_mpm/cli/commands/run.py +120 -84
- claude_mpm/cli/commands/run_config_checker.py +4 -5
- claude_mpm/cli/commands/socketio_monitor.py +17 -19
- claude_mpm/cli/commands/tickets.py +92 -92
- claude_mpm/cli/parser.py +1 -5
- claude_mpm/cli/parsers/__init__.py +1 -1
- claude_mpm/cli/parsers/agent_manager_parser.py +50 -98
- claude_mpm/cli/parsers/agents_parser.py +2 -3
- claude_mpm/cli/parsers/base_parser.py +7 -5
- claude_mpm/cli/parsers/mcp_parser.py +4 -2
- claude_mpm/cli/parsers/monitor_parser.py +26 -18
- claude_mpm/cli/shared/__init__.py +10 -10
- claude_mpm/cli/shared/argument_patterns.py +57 -71
- claude_mpm/cli/shared/base_command.py +61 -53
- claude_mpm/cli/shared/error_handling.py +62 -58
- claude_mpm/cli/shared/output_formatters.py +78 -77
- claude_mpm/cli/startup_logging.py +204 -172
- claude_mpm/cli/utils.py +10 -11
- claude_mpm/cli_module/__init__.py +1 -1
- claude_mpm/cli_module/args.py +1 -1
- claude_mpm/cli_module/migration_example.py +5 -5
- claude_mpm/config/__init__.py +9 -9
- claude_mpm/config/agent_config.py +15 -14
- claude_mpm/config/experimental_features.py +4 -4
- claude_mpm/config/paths.py +0 -1
- claude_mpm/config/socketio_config.py +5 -6
- claude_mpm/constants.py +1 -2
- claude_mpm/core/__init__.py +8 -8
- claude_mpm/core/agent_name_normalizer.py +1 -1
- claude_mpm/core/agent_registry.py +20 -23
- claude_mpm/core/agent_session_manager.py +3 -3
- claude_mpm/core/base_service.py +7 -15
- claude_mpm/core/cache.py +4 -6
- claude_mpm/core/claude_runner.py +85 -113
- claude_mpm/core/config.py +43 -28
- claude_mpm/core/config_aliases.py +0 -9
- claude_mpm/core/config_constants.py +52 -30
- claude_mpm/core/constants.py +0 -1
- claude_mpm/core/container.py +18 -27
- claude_mpm/core/exceptions.py +2 -2
- claude_mpm/core/factories.py +10 -12
- claude_mpm/core/framework_loader.py +581 -280
- claude_mpm/core/hook_manager.py +26 -22
- claude_mpm/core/hook_performance_config.py +58 -47
- claude_mpm/core/injectable_service.py +1 -1
- claude_mpm/core/interactive_session.py +61 -152
- claude_mpm/core/interfaces.py +1 -100
- claude_mpm/core/lazy.py +5 -5
- claude_mpm/core/log_manager.py +587 -0
- claude_mpm/core/logger.py +125 -8
- claude_mpm/core/logging_config.py +15 -15
- claude_mpm/core/minimal_framework_loader.py +5 -8
- claude_mpm/core/oneshot_session.py +15 -33
- claude_mpm/core/optimized_agent_loader.py +4 -6
- claude_mpm/core/optimized_startup.py +2 -1
- claude_mpm/core/output_style_manager.py +147 -106
- claude_mpm/core/pm_hook_interceptor.py +0 -1
- claude_mpm/core/service_registry.py +11 -8
- claude_mpm/core/session_manager.py +1 -2
- claude_mpm/core/shared/__init__.py +1 -1
- claude_mpm/core/shared/config_loader.py +101 -97
- claude_mpm/core/shared/path_resolver.py +72 -68
- claude_mpm/core/shared/singleton_manager.py +56 -50
- claude_mpm/core/socketio_pool.py +26 -6
- claude_mpm/core/tool_access_control.py +4 -5
- claude_mpm/core/typing_utils.py +50 -59
- claude_mpm/core/unified_agent_registry.py +14 -19
- claude_mpm/core/unified_config.py +4 -6
- claude_mpm/core/unified_paths.py +197 -109
- claude_mpm/dashboard/open_dashboard.py +2 -4
- claude_mpm/experimental/cli_enhancements.py +51 -36
- claude_mpm/generators/agent_profile_generator.py +2 -4
- claude_mpm/hooks/base_hook.py +1 -2
- claude_mpm/hooks/claude_hooks/connection_pool.py +72 -26
- claude_mpm/hooks/claude_hooks/event_handlers.py +93 -38
- claude_mpm/hooks/claude_hooks/hook_handler.py +130 -76
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
- claude_mpm/hooks/claude_hooks/memory_integration.py +2 -4
- claude_mpm/hooks/claude_hooks/response_tracking.py +15 -11
- claude_mpm/hooks/claude_hooks/tool_analysis.py +12 -18
- claude_mpm/hooks/memory_integration_hook.py +5 -5
- claude_mpm/hooks/tool_call_interceptor.py +1 -1
- claude_mpm/hooks/validation_hooks.py +4 -4
- claude_mpm/init.py +4 -9
- claude_mpm/models/__init__.py +2 -2
- claude_mpm/models/agent_session.py +11 -14
- claude_mpm/scripts/mcp_server.py +20 -11
- claude_mpm/scripts/mcp_wrapper.py +5 -5
- claude_mpm/scripts/mpm_doctor.py +321 -0
- claude_mpm/scripts/socketio_daemon.py +28 -25
- claude_mpm/scripts/socketio_daemon_hardened.py +298 -258
- claude_mpm/scripts/socketio_server_manager.py +116 -95
- claude_mpm/services/__init__.py +49 -49
- claude_mpm/services/agent_capabilities_service.py +12 -18
- claude_mpm/services/agents/__init__.py +22 -22
- claude_mpm/services/agents/agent_builder.py +140 -119
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +9 -9
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +19 -20
- claude_mpm/services/agents/deployment/agent_definition_factory.py +1 -5
- claude_mpm/services/agents/deployment/agent_deployment.py +136 -106
- claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -8
- claude_mpm/services/agents/deployment/agent_environment_manager.py +2 -7
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +6 -10
- claude_mpm/services/agents/deployment/agent_format_converter.py +11 -15
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +2 -3
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -5
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +13 -19
- claude_mpm/services/agents/deployment/agent_restore_handler.py +0 -1
- claude_mpm/services/agents/deployment/agent_template_builder.py +26 -35
- claude_mpm/services/agents/deployment/agent_validator.py +0 -1
- claude_mpm/services/agents/deployment/agent_version_manager.py +7 -9
- claude_mpm/services/agents/deployment/agent_versioning.py +3 -3
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +6 -7
- claude_mpm/services/agents/deployment/async_agent_deployment.py +51 -38
- claude_mpm/services/agents/deployment/config/__init__.py +1 -1
- claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
- claude_mpm/services/agents/deployment/deployment_type_detector.py +1 -1
- claude_mpm/services/agents/deployment/deployment_wrapper.py +18 -18
- claude_mpm/services/agents/deployment/facade/__init__.py +1 -1
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +0 -3
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -4
- claude_mpm/services/agents/deployment/interface_adapter.py +5 -7
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +345 -276
- claude_mpm/services/agents/deployment/pipeline/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +6 -4
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +3 -3
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +14 -13
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +0 -1
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +8 -9
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +1 -1
- claude_mpm/services/agents/deployment/processors/__init__.py +1 -1
- claude_mpm/services/agents/deployment/processors/agent_processor.py +20 -16
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +5 -12
- claude_mpm/services/agents/deployment/results/__init__.py +1 -1
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +1 -1
- claude_mpm/services/agents/deployment/strategies/__init__.py +2 -2
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +1 -7
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +1 -4
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +2 -3
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +3 -7
- claude_mpm/services/agents/deployment/validation/__init__.py +1 -1
- claude_mpm/services/agents/deployment/validation/agent_validator.py +1 -1
- claude_mpm/services/agents/deployment/validation/template_validator.py +2 -2
- claude_mpm/services/agents/deployment/validation/validation_result.py +2 -6
- claude_mpm/services/agents/loading/__init__.py +1 -1
- claude_mpm/services/agents/loading/agent_profile_loader.py +6 -12
- claude_mpm/services/agents/loading/base_agent_manager.py +5 -5
- claude_mpm/services/agents/loading/framework_agent_loader.py +2 -4
- claude_mpm/services/agents/management/__init__.py +1 -1
- claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -3
- claude_mpm/services/agents/management/agent_management_service.py +5 -9
- claude_mpm/services/agents/memory/__init__.py +4 -4
- claude_mpm/services/agents/memory/agent_memory_manager.py +280 -160
- claude_mpm/services/agents/memory/agent_persistence_service.py +0 -2
- claude_mpm/services/agents/memory/content_manager.py +44 -38
- claude_mpm/services/agents/memory/template_generator.py +4 -6
- claude_mpm/services/agents/registry/__init__.py +10 -6
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +30 -27
- claude_mpm/services/agents/registry/modification_tracker.py +3 -6
- claude_mpm/services/async_session_logger.py +1 -2
- claude_mpm/services/claude_session_logger.py +1 -2
- claude_mpm/services/command_deployment_service.py +173 -0
- claude_mpm/services/command_handler_service.py +20 -22
- claude_mpm/services/core/__init__.py +25 -25
- claude_mpm/services/core/base.py +0 -5
- claude_mpm/services/core/interfaces/__init__.py +32 -32
- claude_mpm/services/core/interfaces/agent.py +0 -21
- claude_mpm/services/core/interfaces/communication.py +0 -27
- claude_mpm/services/core/interfaces/infrastructure.py +0 -56
- claude_mpm/services/core/interfaces/service.py +0 -29
- claude_mpm/services/diagnostics/__init__.py +1 -1
- claude_mpm/services/diagnostics/checks/__init__.py +6 -6
- claude_mpm/services/diagnostics/checks/agent_check.py +89 -80
- claude_mpm/services/diagnostics/checks/base_check.py +12 -16
- claude_mpm/services/diagnostics/checks/claude_desktop_check.py +84 -81
- claude_mpm/services/diagnostics/checks/common_issues_check.py +99 -91
- claude_mpm/services/diagnostics/checks/configuration_check.py +82 -77
- claude_mpm/services/diagnostics/checks/filesystem_check.py +67 -68
- claude_mpm/services/diagnostics/checks/installation_check.py +254 -94
- claude_mpm/services/diagnostics/checks/mcp_check.py +90 -88
- claude_mpm/services/diagnostics/checks/monitor_check.py +75 -76
- claude_mpm/services/diagnostics/checks/startup_log_check.py +67 -73
- claude_mpm/services/diagnostics/diagnostic_runner.py +67 -59
- claude_mpm/services/diagnostics/doctor_reporter.py +107 -70
- claude_mpm/services/diagnostics/models.py +21 -19
- claude_mpm/services/event_aggregator.py +10 -17
- claude_mpm/services/event_bus/__init__.py +1 -1
- claude_mpm/services/event_bus/config.py +54 -35
- claude_mpm/services/event_bus/event_bus.py +76 -71
- claude_mpm/services/event_bus/relay.py +74 -64
- claude_mpm/services/events/__init__.py +11 -11
- claude_mpm/services/events/consumers/__init__.py +3 -3
- claude_mpm/services/events/consumers/dead_letter.py +71 -63
- claude_mpm/services/events/consumers/logging.py +39 -37
- claude_mpm/services/events/consumers/metrics.py +56 -57
- claude_mpm/services/events/consumers/socketio.py +82 -81
- claude_mpm/services/events/core.py +110 -99
- claude_mpm/services/events/interfaces.py +56 -72
- claude_mpm/services/events/producers/__init__.py +1 -1
- claude_mpm/services/events/producers/hook.py +38 -38
- claude_mpm/services/events/producers/system.py +46 -44
- claude_mpm/services/exceptions.py +81 -80
- claude_mpm/services/framework_claude_md_generator/__init__.py +2 -4
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -5
- claude_mpm/services/framework_claude_md_generator/content_validator.py +1 -1
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +4 -4
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -1
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -2
- claude_mpm/services/framework_claude_md_generator/version_manager.py +4 -5
- claude_mpm/services/hook_service.py +6 -9
- claude_mpm/services/infrastructure/__init__.py +1 -1
- claude_mpm/services/infrastructure/context_preservation.py +8 -12
- claude_mpm/services/infrastructure/monitoring.py +21 -23
- claude_mpm/services/mcp_gateway/__init__.py +37 -37
- claude_mpm/services/mcp_gateway/auto_configure.py +95 -103
- claude_mpm/services/mcp_gateway/config/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/config/config_loader.py +23 -25
- claude_mpm/services/mcp_gateway/config/config_schema.py +5 -5
- claude_mpm/services/mcp_gateway/config/configuration.py +9 -6
- claude_mpm/services/mcp_gateway/core/__init__.py +10 -10
- claude_mpm/services/mcp_gateway/core/base.py +0 -3
- claude_mpm/services/mcp_gateway/core/interfaces.py +1 -38
- claude_mpm/services/mcp_gateway/core/process_pool.py +99 -93
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +65 -62
- claude_mpm/services/mcp_gateway/core/startup_verification.py +75 -74
- claude_mpm/services/mcp_gateway/main.py +2 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +5 -8
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +1 -1
- claude_mpm/services/mcp_gateway/server/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +12 -19
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +4 -3
- claude_mpm/services/mcp_gateway/server/stdio_server.py +79 -71
- claude_mpm/services/mcp_gateway/tools/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +5 -6
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +13 -22
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +79 -78
- claude_mpm/services/mcp_gateway/tools/hello_world.py +12 -14
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +42 -49
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +51 -55
- claude_mpm/services/memory/__init__.py +3 -3
- claude_mpm/services/memory/builder.py +3 -6
- claude_mpm/services/memory/cache/__init__.py +1 -1
- claude_mpm/services/memory/cache/shared_prompt_cache.py +3 -5
- claude_mpm/services/memory/cache/simple_cache.py +1 -1
- claude_mpm/services/memory/indexed_memory.py +5 -7
- claude_mpm/services/memory/optimizer.py +7 -10
- claude_mpm/services/memory/router.py +8 -9
- claude_mpm/services/memory_hook_service.py +48 -34
- claude_mpm/services/monitor_build_service.py +77 -73
- claude_mpm/services/port_manager.py +130 -108
- claude_mpm/services/project/analyzer.py +12 -10
- claude_mpm/services/project/registry.py +11 -11
- claude_mpm/services/recovery_manager.py +10 -19
- claude_mpm/services/response_tracker.py +0 -1
- claude_mpm/services/runner_configuration_service.py +19 -20
- claude_mpm/services/session_management_service.py +7 -11
- claude_mpm/services/shared/__init__.py +1 -1
- claude_mpm/services/shared/async_service_base.py +58 -50
- claude_mpm/services/shared/config_service_base.py +73 -67
- claude_mpm/services/shared/lifecycle_service_base.py +82 -78
- claude_mpm/services/shared/manager_base.py +94 -82
- claude_mpm/services/shared/service_factory.py +96 -98
- claude_mpm/services/socketio/__init__.py +3 -3
- claude_mpm/services/socketio/client_proxy.py +5 -5
- claude_mpm/services/socketio/event_normalizer.py +199 -181
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +5 -4
- claude_mpm/services/socketio/handlers/connection.py +163 -136
- claude_mpm/services/socketio/handlers/file.py +13 -14
- claude_mpm/services/socketio/handlers/git.py +12 -7
- claude_mpm/services/socketio/handlers/hook.py +49 -44
- claude_mpm/services/socketio/handlers/memory.py +0 -1
- claude_mpm/services/socketio/handlers/project.py +0 -1
- claude_mpm/services/socketio/handlers/registry.py +37 -19
- claude_mpm/services/socketio/migration_utils.py +98 -84
- claude_mpm/services/socketio/server/__init__.py +1 -1
- claude_mpm/services/socketio/server/broadcaster.py +81 -87
- claude_mpm/services/socketio/server/core.py +65 -54
- claude_mpm/services/socketio/server/eventbus_integration.py +95 -56
- claude_mpm/services/socketio/server/main.py +64 -38
- claude_mpm/services/socketio_client_manager.py +10 -12
- claude_mpm/services/subprocess_launcher_service.py +4 -7
- claude_mpm/services/system_instructions_service.py +13 -14
- claude_mpm/services/ticket_manager.py +2 -2
- claude_mpm/services/utility_service.py +5 -13
- claude_mpm/services/version_control/__init__.py +16 -16
- claude_mpm/services/version_control/branch_strategy.py +5 -8
- claude_mpm/services/version_control/conflict_resolution.py +9 -23
- claude_mpm/services/version_control/git_operations.py +5 -7
- claude_mpm/services/version_control/semantic_versioning.py +16 -17
- claude_mpm/services/version_control/version_parser.py +13 -18
- claude_mpm/services/version_service.py +10 -11
- claude_mpm/storage/__init__.py +1 -1
- claude_mpm/storage/state_storage.py +22 -28
- claude_mpm/utils/__init__.py +6 -6
- claude_mpm/utils/agent_dependency_loader.py +47 -33
- claude_mpm/utils/config_manager.py +11 -14
- claude_mpm/utils/dependency_cache.py +1 -1
- claude_mpm/utils/dependency_manager.py +13 -17
- claude_mpm/utils/dependency_strategies.py +8 -10
- claude_mpm/utils/environment_context.py +3 -9
- claude_mpm/utils/error_handler.py +3 -13
- claude_mpm/utils/file_utils.py +1 -1
- claude_mpm/utils/path_operations.py +8 -12
- claude_mpm/utils/robust_installer.py +110 -33
- claude_mpm/utils/subprocess_utils.py +5 -6
- claude_mpm/validation/agent_validator.py +3 -6
- claude_mpm/validation/frontmatter_validator.py +1 -1
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/METADATA +1 -1
- claude_mpm-4.1.2.dist-info/RECORD +498 -0
- claude_mpm-4.1.0.dist-info/RECORD +0 -494
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/top_level.txt +0 -0
|
@@ -7,26 +7,25 @@ formatting for terminal display and JSON export.
|
|
|
7
7
|
|
|
8
8
|
import json
|
|
9
9
|
import sys
|
|
10
|
-
from typing import Dict, List, Optional
|
|
11
10
|
|
|
12
11
|
from .models import DiagnosticResult, DiagnosticStatus, DiagnosticSummary
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class DoctorReporter:
|
|
16
15
|
"""Format and display diagnostic results.
|
|
17
|
-
|
|
16
|
+
|
|
18
17
|
WHY: Consistent, user-friendly output that clearly shows system health
|
|
19
18
|
status and provides actionable fixes for any issues.
|
|
20
19
|
"""
|
|
21
|
-
|
|
20
|
+
|
|
22
21
|
# Status symbols and colors
|
|
23
22
|
STATUS_SYMBOLS = {
|
|
24
23
|
DiagnosticStatus.OK: "✅",
|
|
25
24
|
DiagnosticStatus.WARNING: "⚠️ ",
|
|
26
25
|
DiagnosticStatus.ERROR: "❌",
|
|
27
|
-
DiagnosticStatus.SKIPPED: "⏭️ "
|
|
26
|
+
DiagnosticStatus.SKIPPED: "⏭️ ",
|
|
28
27
|
}
|
|
29
|
-
|
|
28
|
+
|
|
30
29
|
# ANSI color codes
|
|
31
30
|
COLORS = {
|
|
32
31
|
"reset": "\033[0m",
|
|
@@ -35,22 +34,22 @@ class DoctorReporter:
|
|
|
35
34
|
"green": "\033[92m",
|
|
36
35
|
"yellow": "\033[93m",
|
|
37
36
|
"blue": "\033[94m",
|
|
38
|
-
"gray": "\033[90m"
|
|
37
|
+
"gray": "\033[90m",
|
|
39
38
|
}
|
|
40
|
-
|
|
39
|
+
|
|
41
40
|
def __init__(self, use_color: bool = True, verbose: bool = False):
|
|
42
41
|
"""Initialize reporter.
|
|
43
|
-
|
|
42
|
+
|
|
44
43
|
Args:
|
|
45
44
|
use_color: Whether to use ANSI color codes
|
|
46
45
|
verbose: Whether to include detailed information
|
|
47
46
|
"""
|
|
48
47
|
self.use_color = use_color and sys.stdout.isatty()
|
|
49
48
|
self.verbose = verbose
|
|
50
|
-
|
|
49
|
+
|
|
51
50
|
def report(self, summary: DiagnosticSummary, format: str = "terminal"):
|
|
52
51
|
"""Generate and output diagnostic report.
|
|
53
|
-
|
|
52
|
+
|
|
54
53
|
Args:
|
|
55
54
|
summary: DiagnosticSummary with all results
|
|
56
55
|
format: Output format ("terminal", "json", "markdown")
|
|
@@ -61,40 +60,40 @@ class DoctorReporter:
|
|
|
61
60
|
self._report_markdown(summary)
|
|
62
61
|
else:
|
|
63
62
|
self._report_terminal(summary)
|
|
64
|
-
|
|
63
|
+
|
|
65
64
|
def _report_terminal(self, summary: DiagnosticSummary):
|
|
66
65
|
"""Generate terminal-formatted report."""
|
|
67
66
|
# Header
|
|
68
67
|
self._print_header()
|
|
69
|
-
|
|
68
|
+
|
|
70
69
|
# Results by category
|
|
71
70
|
for result in summary.results:
|
|
72
71
|
self._print_result(result)
|
|
73
|
-
|
|
72
|
+
|
|
74
73
|
# Summary
|
|
75
74
|
self._print_summary(summary)
|
|
76
|
-
|
|
75
|
+
|
|
77
76
|
# Fix suggestions
|
|
78
77
|
self._print_fixes(summary)
|
|
79
|
-
|
|
78
|
+
|
|
80
79
|
def _print_header(self):
|
|
81
80
|
"""Print report header."""
|
|
82
81
|
print()
|
|
83
82
|
print(self._color("Claude MPM Doctor Report", "bold"))
|
|
84
83
|
print("=" * 40)
|
|
85
84
|
print()
|
|
86
|
-
|
|
85
|
+
|
|
87
86
|
def _print_result(self, result: DiagnosticResult, indent: int = 0):
|
|
88
87
|
"""Print a single diagnostic result."""
|
|
89
88
|
indent_str = " " * indent
|
|
90
|
-
|
|
89
|
+
|
|
91
90
|
# Status symbol and category
|
|
92
91
|
symbol = self.STATUS_SYMBOLS.get(result.status, "?")
|
|
93
92
|
color = self._get_status_color(result.status)
|
|
94
|
-
|
|
93
|
+
|
|
95
94
|
# Main result line
|
|
96
95
|
line = f"{indent_str}{symbol} {result.category}: "
|
|
97
|
-
|
|
96
|
+
|
|
98
97
|
if result.status == DiagnosticStatus.OK:
|
|
99
98
|
line += self._color("OK", color)
|
|
100
99
|
elif result.status == DiagnosticStatus.WARNING:
|
|
@@ -103,115 +102,149 @@ class DoctorReporter:
|
|
|
103
102
|
line += self._color("Error", color)
|
|
104
103
|
else:
|
|
105
104
|
line += self._color("Skipped", color)
|
|
106
|
-
|
|
105
|
+
|
|
107
106
|
print(line)
|
|
108
|
-
|
|
107
|
+
|
|
109
108
|
# Message
|
|
110
109
|
message_indent = " " + indent_str
|
|
111
110
|
print(f"{message_indent}{result.message}")
|
|
112
|
-
|
|
111
|
+
|
|
113
112
|
# Details (in verbose mode)
|
|
114
113
|
if self.verbose and result.details:
|
|
115
114
|
for key, value in result.details.items():
|
|
116
115
|
if key not in ["error", "issues"]: # Skip complex fields
|
|
117
116
|
print(f"{message_indent}{self._color(key, 'gray')}: {value}")
|
|
118
|
-
|
|
117
|
+
|
|
119
118
|
# Fix suggestion
|
|
120
119
|
if result.fix_command:
|
|
121
120
|
fix_indent = " " + indent_str
|
|
122
|
-
print(
|
|
121
|
+
print(
|
|
122
|
+
f"{fix_indent}{self._color('→ Fix:', 'blue')} Run '{result.fix_command}'"
|
|
123
|
+
)
|
|
123
124
|
if result.fix_description:
|
|
124
125
|
print(f"{fix_indent} {self._color(result.fix_description, 'gray')}")
|
|
125
|
-
|
|
126
|
+
|
|
126
127
|
# Sub-results (in verbose mode)
|
|
127
128
|
if self.verbose and result.sub_results:
|
|
128
129
|
for sub_result in result.sub_results:
|
|
129
130
|
self._print_result(sub_result, indent + 1)
|
|
130
|
-
|
|
131
|
+
|
|
131
132
|
if indent == 0:
|
|
132
133
|
print() # Extra line between top-level results
|
|
133
|
-
|
|
134
|
+
|
|
134
135
|
def _print_summary(self, summary: DiagnosticSummary):
|
|
135
136
|
"""Print summary statistics."""
|
|
136
137
|
print(self._color("─" * 40, "gray"))
|
|
137
|
-
|
|
138
|
-
status_line =
|
|
138
|
+
|
|
139
|
+
status_line = "Summary: "
|
|
139
140
|
parts = []
|
|
140
|
-
|
|
141
|
+
|
|
141
142
|
if summary.ok_count > 0:
|
|
142
143
|
parts.append(self._color(f"{summary.ok_count} OK", "green"))
|
|
143
144
|
if summary.warning_count > 0:
|
|
144
|
-
parts.append(
|
|
145
|
+
parts.append(
|
|
146
|
+
self._color(
|
|
147
|
+
f"{summary.warning_count} Warning{'s' if summary.warning_count != 1 else ''}",
|
|
148
|
+
"yellow",
|
|
149
|
+
)
|
|
150
|
+
)
|
|
145
151
|
if summary.error_count > 0:
|
|
146
|
-
parts.append(
|
|
152
|
+
parts.append(
|
|
153
|
+
self._color(
|
|
154
|
+
f"{summary.error_count} Error{'s' if summary.error_count != 1 else ''}",
|
|
155
|
+
"red",
|
|
156
|
+
)
|
|
157
|
+
)
|
|
147
158
|
if summary.skipped_count > 0:
|
|
148
159
|
parts.append(self._color(f"{summary.skipped_count} Skipped", "gray"))
|
|
149
|
-
|
|
160
|
+
|
|
150
161
|
status_line += " | ".join(parts)
|
|
151
162
|
print(status_line)
|
|
152
|
-
|
|
163
|
+
|
|
153
164
|
# Overall health
|
|
154
165
|
overall = summary.overall_status
|
|
155
166
|
if overall == DiagnosticStatus.OK:
|
|
156
167
|
print(self._color("\n✅ System is healthy!", "green"))
|
|
157
168
|
elif overall == DiagnosticStatus.WARNING:
|
|
158
|
-
print(
|
|
169
|
+
print(
|
|
170
|
+
self._color(
|
|
171
|
+
"\n⚠️ System has minor issues that should be addressed.", "yellow"
|
|
172
|
+
)
|
|
173
|
+
)
|
|
159
174
|
else:
|
|
160
|
-
print(
|
|
161
|
-
|
|
175
|
+
print(
|
|
176
|
+
self._color(
|
|
177
|
+
"\n❌ System has critical issues that need immediate attention!",
|
|
178
|
+
"red",
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
|
|
162
182
|
def _print_fixes(self, summary: DiagnosticSummary):
|
|
163
183
|
"""Print consolidated fix suggestions."""
|
|
164
184
|
fixes = []
|
|
165
|
-
|
|
185
|
+
|
|
166
186
|
for result in summary.results:
|
|
167
187
|
if result.fix_command and result.has_issues:
|
|
168
|
-
fixes.append(
|
|
169
|
-
|
|
188
|
+
fixes.append(
|
|
189
|
+
(result.category, result.fix_command, result.fix_description)
|
|
190
|
+
)
|
|
191
|
+
|
|
170
192
|
if fixes:
|
|
171
193
|
print()
|
|
172
194
|
print(self._color("Suggested Fixes:", "bold"))
|
|
173
195
|
print(self._color("─" * 40, "gray"))
|
|
174
|
-
|
|
196
|
+
|
|
175
197
|
for i, (category, command, description) in enumerate(fixes, 1):
|
|
176
198
|
print(f"{i}. {category}:")
|
|
177
199
|
print(f" {self._color(command, 'blue')}")
|
|
178
200
|
if description:
|
|
179
201
|
print(f" {self._color(description, 'gray')}")
|
|
180
202
|
print()
|
|
181
|
-
|
|
203
|
+
|
|
182
204
|
if self.verbose:
|
|
183
|
-
print(
|
|
205
|
+
print(
|
|
206
|
+
self._color(
|
|
207
|
+
"Run 'claude-mpm doctor --fix' to attempt automatic fixes",
|
|
208
|
+
"gray",
|
|
209
|
+
)
|
|
210
|
+
)
|
|
184
211
|
else:
|
|
185
|
-
print(
|
|
186
|
-
|
|
212
|
+
print(
|
|
213
|
+
self._color(
|
|
214
|
+
"Run 'claude-mpm doctor --verbose' for more details", "gray"
|
|
215
|
+
)
|
|
216
|
+
)
|
|
217
|
+
|
|
187
218
|
def _report_json(self, summary: DiagnosticSummary):
|
|
188
219
|
"""Generate JSON-formatted report."""
|
|
189
220
|
output = summary.to_dict()
|
|
190
|
-
|
|
221
|
+
|
|
191
222
|
# Add metadata
|
|
192
223
|
output["metadata"] = {
|
|
193
224
|
"tool": "claude-mpm doctor",
|
|
194
225
|
"version": self._get_version(),
|
|
195
|
-
"verbose": self.verbose
|
|
226
|
+
"verbose": self.verbose,
|
|
196
227
|
}
|
|
197
|
-
|
|
228
|
+
|
|
198
229
|
# Add fix suggestions
|
|
199
230
|
fixes = []
|
|
200
231
|
for result in summary.results:
|
|
201
232
|
if result.fix_command and result.has_issues:
|
|
202
|
-
fixes.append(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
233
|
+
fixes.append(
|
|
234
|
+
{
|
|
235
|
+
"category": result.category,
|
|
236
|
+
"command": result.fix_command,
|
|
237
|
+
"description": result.fix_description,
|
|
238
|
+
}
|
|
239
|
+
)
|
|
207
240
|
output["fixes"] = fixes
|
|
208
|
-
|
|
241
|
+
|
|
209
242
|
print(json.dumps(output, indent=2))
|
|
210
|
-
|
|
243
|
+
|
|
211
244
|
def _report_markdown(self, summary: DiagnosticSummary):
|
|
212
245
|
"""Generate Markdown-formatted report."""
|
|
213
246
|
print("# Claude MPM Doctor Report\n")
|
|
214
|
-
|
|
247
|
+
|
|
215
248
|
# Summary table
|
|
216
249
|
print("## Summary\n")
|
|
217
250
|
print("| Status | Count |")
|
|
@@ -221,31 +254,34 @@ class DoctorReporter:
|
|
|
221
254
|
print(f"| ❌ Error | {summary.error_count} |")
|
|
222
255
|
print(f"| ⏭️ Skipped | {summary.skipped_count} |")
|
|
223
256
|
print()
|
|
224
|
-
|
|
257
|
+
|
|
225
258
|
# Detailed results
|
|
226
259
|
print("## Diagnostic Results\n")
|
|
227
|
-
|
|
260
|
+
|
|
228
261
|
for result in summary.results:
|
|
229
262
|
symbol = self.STATUS_SYMBOLS.get(result.status, "?")
|
|
230
263
|
print(f"### {symbol} {result.category}\n")
|
|
231
264
|
print(f"**Status:** {result.status.value}")
|
|
232
265
|
print(f"**Message:** {result.message}\n")
|
|
233
|
-
|
|
266
|
+
|
|
234
267
|
if result.fix_command:
|
|
235
268
|
print(f"**Fix:** `{result.fix_command}`")
|
|
236
269
|
if result.fix_description:
|
|
237
270
|
print(f"_{result.fix_description}_\n")
|
|
238
|
-
|
|
271
|
+
|
|
239
272
|
if self.verbose and result.details:
|
|
240
273
|
print("**Details:**")
|
|
241
274
|
for key, value in result.details.items():
|
|
242
275
|
print(f"- {key}: {value}")
|
|
243
276
|
print()
|
|
244
|
-
|
|
277
|
+
|
|
245
278
|
# Fixes section
|
|
246
|
-
fixes = [
|
|
247
|
-
|
|
248
|
-
|
|
279
|
+
fixes = [
|
|
280
|
+
(r.category, r.fix_command, r.fix_description)
|
|
281
|
+
for r in summary.results
|
|
282
|
+
if r.fix_command and r.has_issues
|
|
283
|
+
]
|
|
284
|
+
|
|
249
285
|
if fixes:
|
|
250
286
|
print("## Suggested Fixes\n")
|
|
251
287
|
for category, command, description in fixes:
|
|
@@ -253,31 +289,32 @@ class DoctorReporter:
|
|
|
253
289
|
if description:
|
|
254
290
|
print(f" - {description}")
|
|
255
291
|
print()
|
|
256
|
-
|
|
292
|
+
|
|
257
293
|
def _color(self, text: str, color: str) -> str:
|
|
258
294
|
"""Apply color to text if colors are enabled."""
|
|
259
295
|
if not self.use_color:
|
|
260
296
|
return text
|
|
261
|
-
|
|
297
|
+
|
|
262
298
|
color_code = self.COLORS.get(color, "")
|
|
263
299
|
reset_code = self.COLORS["reset"]
|
|
264
300
|
return f"{color_code}{text}{reset_code}"
|
|
265
|
-
|
|
301
|
+
|
|
266
302
|
def _get_status_color(self, status: DiagnosticStatus) -> str:
|
|
267
303
|
"""Get color for a status."""
|
|
268
304
|
color_map = {
|
|
269
305
|
DiagnosticStatus.OK: "green",
|
|
270
306
|
DiagnosticStatus.WARNING: "yellow",
|
|
271
307
|
DiagnosticStatus.ERROR: "red",
|
|
272
|
-
DiagnosticStatus.SKIPPED: "gray"
|
|
308
|
+
DiagnosticStatus.SKIPPED: "gray",
|
|
273
309
|
}
|
|
274
310
|
return color_map.get(status, "reset")
|
|
275
|
-
|
|
311
|
+
|
|
276
312
|
def _get_version(self) -> str:
|
|
277
313
|
"""Get claude-mpm version."""
|
|
278
314
|
try:
|
|
279
315
|
from ..version_service import VersionService
|
|
316
|
+
|
|
280
317
|
service = VersionService()
|
|
281
318
|
return service.get_version()
|
|
282
319
|
except Exception:
|
|
283
|
-
return "unknown"
|
|
320
|
+
return "unknown"
|
|
@@ -12,6 +12,7 @@ from typing import Any, Dict, List, Optional
|
|
|
12
12
|
|
|
13
13
|
class DiagnosticStatus(Enum):
|
|
14
14
|
"""Status levels for diagnostic results."""
|
|
15
|
+
|
|
15
16
|
OK = "ok"
|
|
16
17
|
WARNING = "warning"
|
|
17
18
|
ERROR = "error"
|
|
@@ -21,18 +22,19 @@ class DiagnosticStatus(Enum):
|
|
|
21
22
|
@dataclass
|
|
22
23
|
class DiagnosticResult:
|
|
23
24
|
"""Result from a diagnostic check.
|
|
24
|
-
|
|
25
|
+
|
|
25
26
|
WHY: Standardized result format ensures consistent reporting
|
|
26
27
|
and makes it easy to aggregate and display results.
|
|
27
28
|
"""
|
|
29
|
+
|
|
28
30
|
category: str # e.g., "Installation", "Agents", "MCP Server"
|
|
29
31
|
status: DiagnosticStatus
|
|
30
32
|
message: str
|
|
31
33
|
details: Dict[str, Any] = field(default_factory=dict)
|
|
32
34
|
fix_command: Optional[str] = None
|
|
33
35
|
fix_description: Optional[str] = None
|
|
34
|
-
sub_results: List[
|
|
35
|
-
|
|
36
|
+
sub_results: List["DiagnosticResult"] = field(default_factory=list)
|
|
37
|
+
|
|
36
38
|
def to_dict(self) -> Dict[str, Any]:
|
|
37
39
|
"""Convert to dictionary for JSON serialization."""
|
|
38
40
|
return {
|
|
@@ -42,14 +44,14 @@ class DiagnosticResult:
|
|
|
42
44
|
"details": self.details,
|
|
43
45
|
"fix_command": self.fix_command,
|
|
44
46
|
"fix_description": self.fix_description,
|
|
45
|
-
"sub_results": [r.to_dict() for r in self.sub_results]
|
|
47
|
+
"sub_results": [r.to_dict() for r in self.sub_results],
|
|
46
48
|
}
|
|
47
|
-
|
|
49
|
+
|
|
48
50
|
@property
|
|
49
51
|
def has_issues(self) -> bool:
|
|
50
52
|
"""Check if this result indicates any issues."""
|
|
51
53
|
return self.status in (DiagnosticStatus.WARNING, DiagnosticStatus.ERROR)
|
|
52
|
-
|
|
54
|
+
|
|
53
55
|
@property
|
|
54
56
|
def severity_level(self) -> int:
|
|
55
57
|
"""Get numeric severity level for sorting."""
|
|
@@ -57,7 +59,7 @@ class DiagnosticResult:
|
|
|
57
59
|
DiagnosticStatus.OK: 0,
|
|
58
60
|
DiagnosticStatus.SKIPPED: 1,
|
|
59
61
|
DiagnosticStatus.WARNING: 2,
|
|
60
|
-
DiagnosticStatus.ERROR: 3
|
|
62
|
+
DiagnosticStatus.ERROR: 3,
|
|
61
63
|
}
|
|
62
64
|
return severity_map.get(self.status, 0)
|
|
63
65
|
|
|
@@ -65,22 +67,23 @@ class DiagnosticResult:
|
|
|
65
67
|
@dataclass
|
|
66
68
|
class DiagnosticSummary:
|
|
67
69
|
"""Summary of all diagnostic results.
|
|
68
|
-
|
|
70
|
+
|
|
69
71
|
WHY: Provides a high-level overview of system health
|
|
70
72
|
and quick access to issues that need attention.
|
|
71
73
|
"""
|
|
74
|
+
|
|
72
75
|
total_checks: int = 0
|
|
73
76
|
ok_count: int = 0
|
|
74
77
|
warning_count: int = 0
|
|
75
78
|
error_count: int = 0
|
|
76
79
|
skipped_count: int = 0
|
|
77
80
|
results: List[DiagnosticResult] = field(default_factory=list)
|
|
78
|
-
|
|
81
|
+
|
|
79
82
|
def add_result(self, result: DiagnosticResult):
|
|
80
83
|
"""Add a result to the summary."""
|
|
81
84
|
self.results.append(result)
|
|
82
85
|
self.total_checks += 1
|
|
83
|
-
|
|
86
|
+
|
|
84
87
|
if result.status == DiagnosticStatus.OK:
|
|
85
88
|
self.ok_count += 1
|
|
86
89
|
elif result.status == DiagnosticStatus.WARNING:
|
|
@@ -89,22 +92,21 @@ class DiagnosticSummary:
|
|
|
89
92
|
self.error_count += 1
|
|
90
93
|
elif result.status == DiagnosticStatus.SKIPPED:
|
|
91
94
|
self.skipped_count += 1
|
|
92
|
-
|
|
95
|
+
|
|
93
96
|
@property
|
|
94
97
|
def has_issues(self) -> bool:
|
|
95
98
|
"""Check if there are any warnings or errors."""
|
|
96
99
|
return self.warning_count > 0 or self.error_count > 0
|
|
97
|
-
|
|
100
|
+
|
|
98
101
|
@property
|
|
99
102
|
def overall_status(self) -> DiagnosticStatus:
|
|
100
103
|
"""Get overall system status."""
|
|
101
104
|
if self.error_count > 0:
|
|
102
105
|
return DiagnosticStatus.ERROR
|
|
103
|
-
|
|
106
|
+
if self.warning_count > 0:
|
|
104
107
|
return DiagnosticStatus.WARNING
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
+
return DiagnosticStatus.OK
|
|
109
|
+
|
|
108
110
|
def to_dict(self) -> Dict[str, Any]:
|
|
109
111
|
"""Convert to dictionary for JSON serialization."""
|
|
110
112
|
return {
|
|
@@ -114,7 +116,7 @@ class DiagnosticSummary:
|
|
|
114
116
|
"warnings": self.warning_count,
|
|
115
117
|
"errors": self.error_count,
|
|
116
118
|
"skipped": self.skipped_count,
|
|
117
|
-
"overall_status": self.overall_status.value
|
|
119
|
+
"overall_status": self.overall_status.value,
|
|
118
120
|
},
|
|
119
|
-
"results": [r.to_dict() for r in self.results]
|
|
120
|
-
}
|
|
121
|
+
"results": [r.to_dict() for r in self.results],
|
|
122
|
+
}
|
|
@@ -13,7 +13,6 @@ aggregator to run alongside the dashboard without any conflicts.
|
|
|
13
13
|
|
|
14
14
|
import asyncio
|
|
15
15
|
import json
|
|
16
|
-
import os
|
|
17
16
|
import signal
|
|
18
17
|
import sys
|
|
19
18
|
import threading
|
|
@@ -30,8 +29,10 @@ except ImportError:
|
|
|
30
29
|
SOCKETIO_AVAILABLE = False
|
|
31
30
|
socketio = None
|
|
32
31
|
|
|
32
|
+
import contextlib
|
|
33
|
+
|
|
33
34
|
from ..core.logger import get_logger
|
|
34
|
-
from ..models.agent_session import AgentSession
|
|
35
|
+
from ..models.agent_session import AgentSession
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
class EventAggregator:
|
|
@@ -61,7 +62,6 @@ class EventAggregator:
|
|
|
61
62
|
self.logger = get_logger("event_aggregator")
|
|
62
63
|
|
|
63
64
|
# Load configuration using ConfigLoader
|
|
64
|
-
from claude_mpm.core.config import Config
|
|
65
65
|
from claude_mpm.core.shared.config_loader import ConfigLoader
|
|
66
66
|
|
|
67
67
|
config_loader = ConfigLoader()
|
|
@@ -136,10 +136,9 @@ class EventAggregator:
|
|
|
136
136
|
if self.connected:
|
|
137
137
|
self.logger.info("Event Aggregator started successfully")
|
|
138
138
|
return True
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return False
|
|
139
|
+
self.logger.error("Failed to connect to Socket.IO server")
|
|
140
|
+
self.running = False
|
|
141
|
+
return False
|
|
143
142
|
|
|
144
143
|
def stop(self):
|
|
145
144
|
"""Stop the aggregator service."""
|
|
@@ -151,12 +150,10 @@ class EventAggregator:
|
|
|
151
150
|
|
|
152
151
|
# Disconnect Socket.IO client
|
|
153
152
|
if self.sio_client and self.connected:
|
|
154
|
-
|
|
153
|
+
with contextlib.suppress(Exception):
|
|
155
154
|
asyncio.run_coroutine_threadsafe(
|
|
156
155
|
self.sio_client.disconnect(), self.client_loop
|
|
157
156
|
).result(timeout=2)
|
|
158
|
-
except:
|
|
159
|
-
pass
|
|
160
157
|
|
|
161
158
|
# Stop the client thread
|
|
162
159
|
if self.client_thread and self.client_thread.is_alive():
|
|
@@ -207,10 +204,8 @@ class EventAggregator:
|
|
|
207
204
|
# Cancel cleanup task
|
|
208
205
|
if self.cleanup_task:
|
|
209
206
|
self.cleanup_task.cancel()
|
|
210
|
-
|
|
207
|
+
with contextlib.suppress(asyncio.CancelledError):
|
|
211
208
|
await self.cleanup_task
|
|
212
|
-
except asyncio.CancelledError:
|
|
213
|
-
pass
|
|
214
209
|
|
|
215
210
|
except Exception as e:
|
|
216
211
|
self.logger.error(f"Connection error: {e}")
|
|
@@ -470,9 +465,7 @@ class EventAggregator:
|
|
|
470
465
|
"sessions_completed": self.sessions_completed,
|
|
471
466
|
"total_events": self.total_events_captured,
|
|
472
467
|
"events_by_type": dict(self.events_by_type),
|
|
473
|
-
"active_session_ids": [
|
|
474
|
-
sid[:8] + "..." for sid in self.active_sessions.keys()
|
|
475
|
-
],
|
|
468
|
+
"active_session_ids": [sid[:8] + "..." for sid in self.active_sessions],
|
|
476
469
|
}
|
|
477
470
|
|
|
478
471
|
def list_sessions(self, limit: int = 10) -> List[Dict[str, Any]]:
|
|
@@ -496,7 +489,7 @@ class EventAggregator:
|
|
|
496
489
|
for filepath in session_files:
|
|
497
490
|
try:
|
|
498
491
|
# Load just the metadata, not the full session
|
|
499
|
-
with open(filepath
|
|
492
|
+
with open(filepath) as f:
|
|
500
493
|
data = json.load(f)
|
|
501
494
|
|
|
502
495
|
sessions.append(
|