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
|
@@ -15,28 +15,27 @@ DESIGN DECISIONS:
|
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
import logging
|
|
18
|
-
import os
|
|
19
18
|
import shutil
|
|
20
19
|
import subprocess
|
|
21
20
|
import sys
|
|
22
21
|
from datetime import datetime
|
|
23
22
|
from pathlib import Path
|
|
24
|
-
from typing import Any, Dict, Optional
|
|
23
|
+
from typing import Any, Dict, Optional
|
|
25
24
|
|
|
26
25
|
from ..core.logger import get_logger
|
|
27
26
|
|
|
28
27
|
|
|
29
28
|
class StartupStatusLogger:
|
|
30
29
|
"""Logs MCP server and monitor setup status during startup."""
|
|
31
|
-
|
|
30
|
+
|
|
32
31
|
def __init__(self, logger_name: str = "startup_status"):
|
|
33
32
|
"""Initialize the startup status logger."""
|
|
34
33
|
self.logger = get_logger(logger_name)
|
|
35
|
-
|
|
34
|
+
|
|
36
35
|
def log_mcp_server_status(self) -> None:
|
|
37
36
|
"""
|
|
38
37
|
Log MCP server installation and configuration status.
|
|
39
|
-
|
|
38
|
+
|
|
40
39
|
Checks:
|
|
41
40
|
- MCP server executable availability
|
|
42
41
|
- MCP server version if available
|
|
@@ -48,7 +47,7 @@ class StartupStatusLogger:
|
|
|
48
47
|
mcp_executable = self._find_mcp_executable()
|
|
49
48
|
if mcp_executable:
|
|
50
49
|
self.logger.info(f"MCP Server: Installed at {mcp_executable}")
|
|
51
|
-
|
|
50
|
+
|
|
52
51
|
# Try to get version
|
|
53
52
|
version = self._get_mcp_version(mcp_executable)
|
|
54
53
|
if version:
|
|
@@ -57,20 +56,22 @@ class StartupStatusLogger:
|
|
|
57
56
|
self.logger.info("MCP Server: Version unknown")
|
|
58
57
|
else:
|
|
59
58
|
self.logger.info("MCP Server: Not found in PATH")
|
|
60
|
-
|
|
59
|
+
|
|
61
60
|
# Check MCP configuration in ~/.claude.json
|
|
62
61
|
config_status = self._check_mcp_configuration()
|
|
63
62
|
if config_status["found"]:
|
|
64
63
|
self.logger.info("MCP Server: Configuration found in ~/.claude.json")
|
|
65
64
|
if config_status["servers_count"] > 0:
|
|
66
|
-
self.logger.info(
|
|
65
|
+
self.logger.info(
|
|
66
|
+
f"MCP Server: {config_status['servers_count']} server(s) configured"
|
|
67
|
+
)
|
|
67
68
|
else:
|
|
68
69
|
self.logger.info("MCP Server: No servers configured")
|
|
69
70
|
self._log_mcp_setup_hint()
|
|
70
71
|
else:
|
|
71
72
|
self.logger.info("MCP Server: No configuration found in ~/.claude.json")
|
|
72
73
|
self._log_mcp_setup_hint()
|
|
73
|
-
|
|
74
|
+
|
|
74
75
|
# Check for claude-mpm MCP gateway status
|
|
75
76
|
gateway_status = self._check_mcp_gateway_status()
|
|
76
77
|
if gateway_status["configured"]:
|
|
@@ -78,20 +79,27 @@ class StartupStatusLogger:
|
|
|
78
79
|
else:
|
|
79
80
|
self.logger.info("MCP Gateway: Claude MPM gateway not configured")
|
|
80
81
|
# Check if this is a pipx installation that could benefit from auto-config
|
|
81
|
-
if
|
|
82
|
-
self.
|
|
83
|
-
|
|
82
|
+
if (
|
|
83
|
+
self._is_pipx_installation()
|
|
84
|
+
and not self._has_auto_config_preference()
|
|
85
|
+
):
|
|
86
|
+
self.logger.info(
|
|
87
|
+
"MCP Gateway: Auto-configuration available for pipx users"
|
|
88
|
+
)
|
|
89
|
+
|
|
84
90
|
except Exception as e:
|
|
85
91
|
self.logger.warning(f"MCP Server: Status check failed - {e}")
|
|
86
|
-
|
|
87
|
-
def log_monitor_setup_status(
|
|
92
|
+
|
|
93
|
+
def log_monitor_setup_status(
|
|
94
|
+
self, monitor_mode: bool = False, websocket_port: int = 8765
|
|
95
|
+
) -> None:
|
|
88
96
|
"""
|
|
89
97
|
Log monitor service initialization status.
|
|
90
|
-
|
|
98
|
+
|
|
91
99
|
Args:
|
|
92
100
|
monitor_mode: Whether monitor mode is enabled
|
|
93
101
|
websocket_port: WebSocket port for monitoring
|
|
94
|
-
|
|
102
|
+
|
|
95
103
|
Checks:
|
|
96
104
|
- Monitor service initialization status
|
|
97
105
|
- Which monitors are enabled/disabled
|
|
@@ -101,235 +109,246 @@ class StartupStatusLogger:
|
|
|
101
109
|
try:
|
|
102
110
|
if monitor_mode:
|
|
103
111
|
self.logger.info("Monitor: Mode enabled")
|
|
104
|
-
|
|
112
|
+
|
|
105
113
|
# Check SocketIO dependencies
|
|
106
114
|
socketio_status = self._check_socketio_dependencies()
|
|
107
115
|
if socketio_status["available"]:
|
|
108
116
|
self.logger.info("Monitor: Socket.IO dependencies available")
|
|
109
117
|
else:
|
|
110
|
-
self.logger.info(
|
|
111
|
-
|
|
118
|
+
self.logger.info(
|
|
119
|
+
f"Monitor: Socket.IO dependencies missing - {socketio_status['error']}"
|
|
120
|
+
)
|
|
121
|
+
|
|
112
122
|
# Check if server is running
|
|
113
123
|
server_running = self._check_socketio_server_running(websocket_port)
|
|
114
124
|
if server_running:
|
|
115
|
-
self.logger.info(
|
|
125
|
+
self.logger.info(
|
|
126
|
+
f"Monitor: Socket.IO server running on port {websocket_port}"
|
|
127
|
+
)
|
|
116
128
|
else:
|
|
117
|
-
self.logger.info(
|
|
118
|
-
|
|
129
|
+
self.logger.info(
|
|
130
|
+
f"Monitor: Socket.IO server will start on port {websocket_port}"
|
|
131
|
+
)
|
|
132
|
+
|
|
119
133
|
# Check response logging configuration
|
|
120
134
|
logging_config = self._check_response_logging_config()
|
|
121
135
|
if logging_config["enabled"]:
|
|
122
|
-
self.logger.info(
|
|
136
|
+
self.logger.info(
|
|
137
|
+
f"Monitor: Response logging enabled to {logging_config['directory']}"
|
|
138
|
+
)
|
|
123
139
|
else:
|
|
124
140
|
self.logger.info("Monitor: Response logging disabled")
|
|
125
|
-
|
|
141
|
+
|
|
126
142
|
else:
|
|
127
143
|
self.logger.info("Monitor: Mode disabled")
|
|
128
|
-
|
|
144
|
+
|
|
129
145
|
# Still check if there's an existing server running
|
|
130
146
|
server_running = self._check_socketio_server_running(websocket_port)
|
|
131
147
|
if server_running:
|
|
132
|
-
self.logger.info(
|
|
133
|
-
|
|
148
|
+
self.logger.info(
|
|
149
|
+
f"Monitor: Background Socket.IO server detected on port {websocket_port}"
|
|
150
|
+
)
|
|
151
|
+
|
|
134
152
|
except Exception as e:
|
|
135
153
|
self.logger.warning(f"Monitor: Status check failed - {e}")
|
|
136
|
-
|
|
154
|
+
|
|
137
155
|
def _find_mcp_executable(self) -> Optional[str]:
|
|
138
156
|
"""Find MCP server executable in PATH."""
|
|
139
157
|
# Common MCP executable names
|
|
140
158
|
executables = ["claude-mpm-mcp", "mcp", "claude-mcp"]
|
|
141
|
-
|
|
159
|
+
|
|
142
160
|
for exe_name in executables:
|
|
143
161
|
exe_path = shutil.which(exe_name)
|
|
144
162
|
if exe_path:
|
|
145
163
|
return exe_path
|
|
146
|
-
|
|
164
|
+
|
|
147
165
|
# Check if it's installed as a Python package
|
|
148
166
|
try:
|
|
149
167
|
result = subprocess.run(
|
|
150
168
|
[sys.executable, "-m", "claude_mpm.scripts.mcp_server", "--version"],
|
|
151
169
|
capture_output=True,
|
|
152
170
|
text=True,
|
|
153
|
-
timeout=5
|
|
171
|
+
timeout=5,
|
|
172
|
+
check=False,
|
|
154
173
|
)
|
|
155
174
|
if result.returncode == 0:
|
|
156
175
|
return f"{sys.executable} -m claude_mpm.scripts.mcp_server"
|
|
157
176
|
except Exception:
|
|
158
177
|
pass
|
|
159
|
-
|
|
178
|
+
|
|
160
179
|
return None
|
|
161
|
-
|
|
180
|
+
|
|
162
181
|
def _get_mcp_version(self, executable: str) -> Optional[str]:
|
|
163
182
|
"""Get MCP server version."""
|
|
164
183
|
try:
|
|
165
184
|
# Try --version flag
|
|
166
185
|
result = subprocess.run(
|
|
167
|
-
executable.split()
|
|
186
|
+
[*executable.split(), "--version"],
|
|
168
187
|
capture_output=True,
|
|
169
188
|
text=True,
|
|
170
|
-
timeout=5
|
|
189
|
+
timeout=5,
|
|
190
|
+
check=False,
|
|
171
191
|
)
|
|
172
192
|
if result.returncode == 0:
|
|
173
193
|
# Extract version from output
|
|
174
194
|
output = result.stdout.strip()
|
|
175
195
|
if output:
|
|
176
196
|
return output
|
|
177
|
-
|
|
197
|
+
|
|
178
198
|
# Try version command
|
|
179
199
|
result = subprocess.run(
|
|
180
|
-
executable.split()
|
|
200
|
+
[*executable.split(), "version"],
|
|
181
201
|
capture_output=True,
|
|
182
202
|
text=True,
|
|
183
|
-
timeout=5
|
|
203
|
+
timeout=5,
|
|
204
|
+
check=False,
|
|
184
205
|
)
|
|
185
206
|
if result.returncode == 0:
|
|
186
207
|
output = result.stdout.strip()
|
|
187
208
|
if output:
|
|
188
209
|
return output
|
|
189
|
-
|
|
210
|
+
|
|
190
211
|
except Exception:
|
|
191
212
|
pass
|
|
192
|
-
|
|
213
|
+
|
|
193
214
|
return None
|
|
194
|
-
|
|
215
|
+
|
|
195
216
|
def _check_mcp_configuration(self) -> Dict[str, Any]:
|
|
196
217
|
"""Check MCP configuration in ~/.claude.json."""
|
|
197
218
|
claude_json_path = Path.home() / ".claude.json"
|
|
198
|
-
|
|
199
|
-
result = {
|
|
200
|
-
|
|
201
|
-
"servers_count": 0,
|
|
202
|
-
"error": None
|
|
203
|
-
}
|
|
204
|
-
|
|
219
|
+
|
|
220
|
+
result = {"found": False, "servers_count": 0, "error": None}
|
|
221
|
+
|
|
205
222
|
try:
|
|
206
223
|
if not claude_json_path.exists():
|
|
207
224
|
return result
|
|
208
|
-
|
|
225
|
+
|
|
209
226
|
import json
|
|
210
|
-
|
|
227
|
+
|
|
228
|
+
with open(claude_json_path) as f:
|
|
211
229
|
config = json.load(f)
|
|
212
|
-
|
|
230
|
+
|
|
213
231
|
result["found"] = True
|
|
214
|
-
|
|
232
|
+
|
|
215
233
|
# Check for MCP servers configuration
|
|
216
234
|
mcp_config = config.get("mcpServers", {})
|
|
217
235
|
result["servers_count"] = len(mcp_config)
|
|
218
|
-
|
|
236
|
+
|
|
219
237
|
except Exception as e:
|
|
220
238
|
result["error"] = str(e)
|
|
221
|
-
|
|
239
|
+
|
|
222
240
|
return result
|
|
223
|
-
|
|
241
|
+
|
|
224
242
|
def _check_mcp_gateway_status(self) -> Dict[str, Any]:
|
|
225
243
|
"""Check Claude MPM MCP gateway configuration status."""
|
|
226
|
-
result = {
|
|
227
|
-
|
|
228
|
-
"error": None
|
|
229
|
-
}
|
|
230
|
-
|
|
244
|
+
result = {"configured": False, "error": None}
|
|
245
|
+
|
|
231
246
|
try:
|
|
232
247
|
# Check if MCP gateway startup verification is available
|
|
233
|
-
from ..services.mcp_gateway.core.startup_verification import
|
|
248
|
+
from ..services.mcp_gateway.core.startup_verification import (
|
|
249
|
+
is_mcp_gateway_configured,
|
|
250
|
+
)
|
|
251
|
+
|
|
234
252
|
result["configured"] = is_mcp_gateway_configured()
|
|
235
253
|
except ImportError:
|
|
236
254
|
# MCP gateway not available
|
|
237
255
|
pass
|
|
238
256
|
except Exception as e:
|
|
239
257
|
result["error"] = str(e)
|
|
240
|
-
|
|
258
|
+
|
|
241
259
|
return result
|
|
242
|
-
|
|
260
|
+
|
|
243
261
|
def _check_socketio_dependencies(self) -> Dict[str, Any]:
|
|
244
262
|
"""Check if Socket.IO dependencies are available."""
|
|
245
|
-
result = {
|
|
246
|
-
|
|
247
|
-
"error": None
|
|
248
|
-
}
|
|
249
|
-
|
|
263
|
+
result = {"available": False, "error": None}
|
|
264
|
+
|
|
250
265
|
try:
|
|
251
|
-
import socketio
|
|
252
266
|
import aiohttp
|
|
253
267
|
import engineio
|
|
268
|
+
import socketio
|
|
269
|
+
|
|
254
270
|
result["available"] = True
|
|
255
271
|
except ImportError as e:
|
|
256
272
|
result["error"] = f"Missing dependencies: {e}"
|
|
257
273
|
except Exception as e:
|
|
258
274
|
result["error"] = str(e)
|
|
259
|
-
|
|
275
|
+
|
|
260
276
|
return result
|
|
261
|
-
|
|
277
|
+
|
|
262
278
|
def _check_socketio_server_running(self, port: int) -> bool:
|
|
263
279
|
"""Check if Socket.IO server is running on specified port."""
|
|
264
280
|
try:
|
|
265
281
|
import socket
|
|
282
|
+
|
|
266
283
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
267
284
|
s.settimeout(1)
|
|
268
|
-
result = s.connect_ex((
|
|
285
|
+
result = s.connect_ex(("localhost", port))
|
|
269
286
|
return result == 0
|
|
270
287
|
except Exception:
|
|
271
288
|
return False
|
|
272
|
-
|
|
289
|
+
|
|
273
290
|
def _check_response_logging_config(self) -> Dict[str, Any]:
|
|
274
291
|
"""Check response logging configuration."""
|
|
275
|
-
result = {
|
|
276
|
-
|
|
277
|
-
"directory": None,
|
|
278
|
-
"error": None
|
|
279
|
-
}
|
|
280
|
-
|
|
292
|
+
result = {"enabled": False, "directory": None, "error": None}
|
|
293
|
+
|
|
281
294
|
try:
|
|
282
295
|
from ..core.shared.config_loader import ConfigLoader
|
|
283
|
-
|
|
296
|
+
|
|
284
297
|
config_loader = ConfigLoader()
|
|
285
298
|
config = config_loader.load_main_config()
|
|
286
|
-
|
|
299
|
+
|
|
287
300
|
# Check response logging configuration
|
|
288
301
|
response_logging = config.get("response_logging", {})
|
|
289
302
|
result["enabled"] = response_logging.get("enabled", False)
|
|
290
|
-
|
|
303
|
+
|
|
291
304
|
if result["enabled"]:
|
|
292
|
-
log_dir = response_logging.get(
|
|
305
|
+
log_dir = response_logging.get(
|
|
306
|
+
"session_directory", ".claude-mpm/responses"
|
|
307
|
+
)
|
|
293
308
|
if not Path(log_dir).is_absolute():
|
|
294
309
|
log_dir = Path.cwd() / log_dir
|
|
295
310
|
result["directory"] = str(log_dir)
|
|
296
|
-
|
|
311
|
+
|
|
297
312
|
except Exception as e:
|
|
298
313
|
result["error"] = str(e)
|
|
299
|
-
|
|
314
|
+
|
|
300
315
|
return result
|
|
301
|
-
|
|
316
|
+
|
|
302
317
|
def _is_pipx_installation(self) -> bool:
|
|
303
318
|
"""Check if this is a pipx installation."""
|
|
304
319
|
try:
|
|
305
320
|
# Check if running from pipx
|
|
306
321
|
if "pipx" in sys.executable.lower():
|
|
307
322
|
return True
|
|
308
|
-
|
|
323
|
+
|
|
309
324
|
# Check module path
|
|
310
325
|
import claude_mpm
|
|
326
|
+
|
|
311
327
|
module_path = Path(claude_mpm.__file__).parent
|
|
312
328
|
if "pipx" in str(module_path):
|
|
313
329
|
return True
|
|
314
330
|
except Exception:
|
|
315
331
|
pass
|
|
316
|
-
|
|
332
|
+
|
|
317
333
|
return False
|
|
318
|
-
|
|
334
|
+
|
|
319
335
|
def _has_auto_config_preference(self) -> bool:
|
|
320
336
|
"""Check if user has already been asked about auto-configuration."""
|
|
321
337
|
try:
|
|
322
338
|
from ..config.paths import paths
|
|
323
|
-
|
|
339
|
+
|
|
340
|
+
preference_file = (
|
|
341
|
+
paths.claude_mpm_dir_hidden / "mcp_auto_config_preference.json"
|
|
342
|
+
)
|
|
324
343
|
return preference_file.exists()
|
|
325
344
|
except Exception:
|
|
326
345
|
return False
|
|
327
|
-
|
|
346
|
+
|
|
328
347
|
def _log_mcp_setup_hint(self) -> None:
|
|
329
348
|
"""Log helpful hints for MCP setup."""
|
|
330
349
|
# Check if installed via pipx
|
|
331
350
|
is_pipx = self._check_pipx_installation()
|
|
332
|
-
|
|
351
|
+
|
|
333
352
|
if is_pipx:
|
|
334
353
|
self.logger.info("💡 TIP: It looks like you installed claude-mpm via pipx")
|
|
335
354
|
self.logger.info(" To configure MCP for Claude Code with pipx:")
|
|
@@ -341,198 +360,211 @@ class StartupStatusLogger:
|
|
|
341
360
|
self.logger.info(" 1. See docs/MCP_SETUP.md for setup instructions")
|
|
342
361
|
self.logger.info(" 2. Run: claude-mpm doctor --check mcp to verify")
|
|
343
362
|
self.logger.info(" 3. Restart Claude Code after configuration")
|
|
344
|
-
|
|
363
|
+
|
|
345
364
|
def _check_pipx_installation(self) -> bool:
|
|
346
365
|
"""Check if claude-mpm was installed via pipx."""
|
|
347
366
|
try:
|
|
348
367
|
# Check if running from a pipx venv
|
|
349
368
|
if "pipx" in sys.executable.lower():
|
|
350
369
|
return True
|
|
351
|
-
|
|
370
|
+
|
|
352
371
|
# Check if claude-mpm-mcp command exists and is from pipx
|
|
353
372
|
mcp_cmd = shutil.which("claude-mpm-mcp")
|
|
354
373
|
if mcp_cmd and "pipx" in mcp_cmd.lower():
|
|
355
374
|
return True
|
|
356
|
-
|
|
375
|
+
|
|
357
376
|
# Try to check pipx list
|
|
358
377
|
result = subprocess.run(
|
|
359
|
-
["pipx", "list"],
|
|
360
|
-
capture_output=True,
|
|
361
|
-
text=True,
|
|
362
|
-
timeout=2
|
|
378
|
+
["pipx", "list"], capture_output=True, text=True, timeout=2, check=False
|
|
363
379
|
)
|
|
364
380
|
if result.returncode == 0 and "claude-mpm" in result.stdout:
|
|
365
381
|
return True
|
|
366
|
-
|
|
382
|
+
|
|
367
383
|
except Exception:
|
|
368
384
|
pass
|
|
369
|
-
|
|
385
|
+
|
|
370
386
|
return False
|
|
371
387
|
|
|
372
388
|
|
|
373
389
|
def setup_startup_logging(project_root: Optional[Path] = None) -> Path:
|
|
374
390
|
"""
|
|
375
391
|
Set up logging to both console and file for startup.
|
|
376
|
-
|
|
392
|
+
|
|
377
393
|
WHY: Capture all startup logs (INFO, WARNING, ERROR, DEBUG) to timestamped
|
|
378
394
|
files for later analysis by the doctor command. This helps diagnose
|
|
379
395
|
startup issues that users may not notice in the console output.
|
|
380
|
-
|
|
396
|
+
|
|
381
397
|
DESIGN DECISIONS:
|
|
382
398
|
- Use ISO-like timestamp format for easy sorting and reading
|
|
383
399
|
- Store in .claude-mpm/logs/startup/ directory
|
|
384
400
|
- Keep all historical startup logs for pattern analysis
|
|
385
401
|
- Add file handler to root logger to capture ALL module logs
|
|
386
|
-
|
|
402
|
+
|
|
387
403
|
Args:
|
|
388
404
|
project_root: Root directory for the project (defaults to cwd)
|
|
389
|
-
|
|
405
|
+
|
|
390
406
|
Returns:
|
|
391
407
|
Path to the created log file
|
|
392
408
|
"""
|
|
393
409
|
if project_root is None:
|
|
394
410
|
project_root = Path.cwd()
|
|
395
|
-
|
|
411
|
+
|
|
396
412
|
# Create log directory
|
|
397
413
|
log_dir = project_root / ".claude-mpm" / "logs" / "startup"
|
|
398
414
|
log_dir.mkdir(parents=True, exist_ok=True)
|
|
399
|
-
|
|
415
|
+
|
|
400
416
|
# Generate timestamp for log file
|
|
401
417
|
timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
|
402
418
|
log_file = log_dir / f"startup-{timestamp}.log"
|
|
403
|
-
|
|
419
|
+
|
|
404
420
|
# Create file handler with detailed formatting
|
|
405
|
-
file_handler = logging.FileHandler(log_file, encoding=
|
|
421
|
+
file_handler = logging.FileHandler(log_file, encoding="utf-8")
|
|
406
422
|
file_handler.setLevel(logging.DEBUG) # Capture all levels to file
|
|
407
|
-
|
|
423
|
+
|
|
408
424
|
# Format with timestamp, logger name, level, and message
|
|
409
425
|
formatter = logging.Formatter(
|
|
410
|
-
|
|
411
|
-
datefmt=
|
|
426
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
427
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
412
428
|
)
|
|
413
429
|
file_handler.setFormatter(formatter)
|
|
414
|
-
|
|
430
|
+
|
|
415
431
|
# Add to claude_mpm logger to capture all our logs
|
|
416
432
|
# (Don't add to root logger to avoid duplicates from propagation)
|
|
417
433
|
claude_logger = logging.getLogger("claude_mpm")
|
|
418
434
|
claude_logger.addHandler(file_handler)
|
|
419
435
|
claude_logger.setLevel(logging.DEBUG) # Ensure all levels are captured
|
|
420
|
-
|
|
436
|
+
|
|
421
437
|
# Log startup header
|
|
422
438
|
logger = get_logger("startup")
|
|
423
|
-
logger.info("="*60)
|
|
439
|
+
logger.info("=" * 60)
|
|
424
440
|
logger.info(f"Claude MPM Startup - {datetime.now().isoformat()}")
|
|
425
441
|
logger.info(f"Log file: {log_file}")
|
|
426
|
-
logger.info("="*60)
|
|
427
|
-
|
|
442
|
+
logger.info("=" * 60)
|
|
443
|
+
|
|
428
444
|
# Log system information
|
|
429
445
|
logger.info(f"Python: {sys.version}")
|
|
430
446
|
logger.info(f"Platform: {sys.platform}")
|
|
431
447
|
logger.info(f"CWD: {Path.cwd()}")
|
|
432
448
|
logger.info(f"Project root: {project_root}")
|
|
433
|
-
|
|
449
|
+
|
|
434
450
|
return log_file
|
|
435
451
|
|
|
436
452
|
|
|
437
|
-
def cleanup_old_startup_logs(
|
|
438
|
-
|
|
439
|
-
|
|
453
|
+
def cleanup_old_startup_logs(
|
|
454
|
+
project_root: Optional[Path] = None, keep_count: Optional[int] = None
|
|
455
|
+
) -> int:
|
|
440
456
|
"""
|
|
441
|
-
Clean up old startup log files.
|
|
442
|
-
|
|
443
|
-
WHY:
|
|
444
|
-
|
|
445
|
-
|
|
457
|
+
Clean up old startup log files using time-based retention.
|
|
458
|
+
|
|
459
|
+
WHY: This function now delegates to LogManager for unified log management
|
|
460
|
+
with time-based retention instead of count-based.
|
|
461
|
+
|
|
446
462
|
DESIGN DECISIONS:
|
|
447
|
-
-
|
|
448
|
-
-
|
|
449
|
-
-
|
|
450
|
-
|
|
463
|
+
- Delegates to LogManager for consistency
|
|
464
|
+
- Converts count to hours (48 hours default)
|
|
465
|
+
- Maintains backward compatibility
|
|
466
|
+
|
|
451
467
|
Args:
|
|
452
468
|
project_root: Root directory for the project
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
469
|
+
keep_count: Ignored (kept for backward compatibility)
|
|
470
|
+
|
|
456
471
|
Returns:
|
|
457
472
|
Number of log files deleted
|
|
458
473
|
"""
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
return
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
474
|
+
try:
|
|
475
|
+
from ..core.log_manager import get_log_manager
|
|
476
|
+
|
|
477
|
+
log_manager = get_log_manager()
|
|
478
|
+
|
|
479
|
+
# Use LogManager's time-based cleanup (48 hours default)
|
|
480
|
+
return log_manager.cleanup_old_startup_logs(project_root)
|
|
481
|
+
except ImportError:
|
|
482
|
+
# Fallback to old implementation if LogManager not available
|
|
483
|
+
# Get retention count from configuration if not specified
|
|
484
|
+
if keep_count is None:
|
|
485
|
+
from claude_mpm.core.config_constants import ConfigConstants
|
|
486
|
+
|
|
487
|
+
keep_count = (
|
|
488
|
+
ConfigConstants.get_logging_setting("startup_logs_retention_count")
|
|
489
|
+
or 10
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
if project_root is None:
|
|
493
|
+
project_root = Path.cwd()
|
|
494
|
+
|
|
495
|
+
log_dir = project_root / ".claude-mpm" / "logs" / "startup"
|
|
496
|
+
|
|
497
|
+
if not log_dir.exists():
|
|
498
|
+
return 0
|
|
499
|
+
|
|
500
|
+
# Get all startup log files
|
|
501
|
+
log_files = sorted(
|
|
502
|
+
log_dir.glob("startup-*.log"), key=lambda p: p.stat().st_mtime, reverse=True
|
|
503
|
+
) # Newest first
|
|
504
|
+
|
|
505
|
+
if len(log_files) <= keep_count:
|
|
506
|
+
return 0 # Already within limit
|
|
507
|
+
|
|
508
|
+
# Delete older files beyond keep_count
|
|
509
|
+
deleted_count = 0
|
|
510
|
+
for log_file in log_files[
|
|
511
|
+
keep_count:
|
|
512
|
+
]: # Keep only the most recent keep_count files
|
|
481
513
|
try:
|
|
482
514
|
log_file.unlink()
|
|
483
515
|
deleted_count += 1
|
|
484
516
|
except Exception:
|
|
485
517
|
pass # Ignore deletion errors
|
|
486
|
-
|
|
487
|
-
|
|
518
|
+
|
|
519
|
+
return deleted_count
|
|
488
520
|
|
|
489
521
|
|
|
490
522
|
def get_latest_startup_log(project_root: Optional[Path] = None) -> Optional[Path]:
|
|
491
523
|
"""
|
|
492
524
|
Get the path to the most recent startup log file.
|
|
493
|
-
|
|
525
|
+
|
|
494
526
|
Args:
|
|
495
527
|
project_root: Root directory for the project
|
|
496
|
-
|
|
528
|
+
|
|
497
529
|
Returns:
|
|
498
530
|
Path to latest log file or None if no logs exist
|
|
499
531
|
"""
|
|
500
532
|
if project_root is None:
|
|
501
533
|
project_root = Path.cwd()
|
|
502
|
-
|
|
534
|
+
|
|
503
535
|
log_dir = project_root / ".claude-mpm" / "logs" / "startup"
|
|
504
|
-
|
|
536
|
+
|
|
505
537
|
if not log_dir.exists():
|
|
506
538
|
return None
|
|
507
|
-
|
|
508
|
-
log_files = sorted(
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
539
|
+
|
|
540
|
+
log_files = sorted(
|
|
541
|
+
log_dir.glob("startup-*.log"), key=lambda p: p.stat().st_mtime, reverse=True
|
|
542
|
+
)
|
|
543
|
+
|
|
512
544
|
return log_files[0] if log_files else None
|
|
513
545
|
|
|
514
546
|
|
|
515
547
|
def log_startup_status(monitor_mode: bool = False, websocket_port: int = 8765) -> None:
|
|
516
548
|
"""
|
|
517
549
|
Log comprehensive startup status for MCP server and monitor setup.
|
|
518
|
-
|
|
550
|
+
|
|
519
551
|
This function should be called during application startup to provide
|
|
520
552
|
detailed information about MCP and monitor setup status.
|
|
521
|
-
|
|
553
|
+
|
|
522
554
|
Args:
|
|
523
555
|
monitor_mode: Whether monitor mode is enabled
|
|
524
556
|
websocket_port: WebSocket port for monitoring
|
|
525
557
|
"""
|
|
526
558
|
try:
|
|
527
559
|
status_logger = StartupStatusLogger("cli")
|
|
528
|
-
|
|
560
|
+
|
|
529
561
|
# Log MCP server status
|
|
530
562
|
status_logger.log_mcp_server_status()
|
|
531
|
-
|
|
563
|
+
|
|
532
564
|
# Log monitor setup status
|
|
533
565
|
status_logger.log_monitor_setup_status(monitor_mode, websocket_port)
|
|
534
|
-
|
|
566
|
+
|
|
535
567
|
except Exception as e:
|
|
536
568
|
# Don't let logging failures prevent startup
|
|
537
569
|
logger = get_logger("cli")
|
|
538
|
-
logger.debug(f"Startup status logging failed: {e}")
|
|
570
|
+
logger.debug(f"Startup status logging failed: {e}")
|