claude-mpm 4.7.4__py3-none-any.whl → 4.18.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/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +118 -0
- claude_mpm/agents/BASE_ENGINEER.md +286 -0
- claude_mpm/agents/BASE_PM.md +106 -1
- claude_mpm/agents/OUTPUT_STYLE.md +329 -11
- claude_mpm/agents/PM_INSTRUCTIONS.md +397 -459
- claude_mpm/agents/agent_loader.py +17 -5
- claude_mpm/agents/frontmatter_validator.py +284 -253
- claude_mpm/agents/templates/README.md +465 -0
- claude_mpm/agents/templates/agent-manager.json +4 -1
- claude_mpm/agents/templates/agentic-coder-optimizer.json +13 -3
- claude_mpm/agents/templates/api_qa.json +11 -2
- claude_mpm/agents/templates/circuit_breakers.md +638 -0
- claude_mpm/agents/templates/clerk-ops.json +12 -2
- claude_mpm/agents/templates/code_analyzer.json +8 -2
- claude_mpm/agents/templates/content-agent.json +358 -0
- claude_mpm/agents/templates/dart_engineer.json +15 -2
- claude_mpm/agents/templates/data_engineer.json +15 -2
- claude_mpm/agents/templates/documentation.json +10 -2
- claude_mpm/agents/templates/engineer.json +21 -1
- claude_mpm/agents/templates/gcp_ops_agent.json +12 -2
- claude_mpm/agents/templates/git_file_tracking.md +584 -0
- claude_mpm/agents/templates/golang_engineer.json +270 -0
- claude_mpm/agents/templates/imagemagick.json +4 -1
- claude_mpm/agents/templates/java_engineer.json +346 -0
- claude_mpm/agents/templates/local_ops_agent.json +1227 -6
- claude_mpm/agents/templates/memory_manager.json +4 -1
- claude_mpm/agents/templates/nextjs_engineer.json +141 -133
- claude_mpm/agents/templates/ops.json +12 -2
- claude_mpm/agents/templates/php-engineer.json +270 -174
- claude_mpm/agents/templates/pm_examples.md +474 -0
- claude_mpm/agents/templates/pm_red_flags.md +240 -0
- claude_mpm/agents/templates/product_owner.json +338 -0
- claude_mpm/agents/templates/project_organizer.json +14 -4
- claude_mpm/agents/templates/prompt-engineer.json +13 -2
- claude_mpm/agents/templates/python_engineer.json +174 -81
- claude_mpm/agents/templates/qa.json +11 -2
- claude_mpm/agents/templates/react_engineer.json +16 -3
- claude_mpm/agents/templates/refactoring_engineer.json +12 -2
- claude_mpm/agents/templates/research.json +34 -21
- claude_mpm/agents/templates/response_format.md +583 -0
- claude_mpm/agents/templates/ruby-engineer.json +129 -192
- claude_mpm/agents/templates/rust_engineer.json +270 -0
- claude_mpm/agents/templates/security.json +10 -2
- claude_mpm/agents/templates/svelte-engineer.json +225 -0
- claude_mpm/agents/templates/ticketing.json +10 -2
- claude_mpm/agents/templates/typescript_engineer.json +116 -125
- claude_mpm/agents/templates/validation_templates.md +312 -0
- claude_mpm/agents/templates/vercel_ops_agent.json +12 -2
- claude_mpm/agents/templates/version_control.json +12 -2
- claude_mpm/agents/templates/web_qa.json +11 -2
- claude_mpm/agents/templates/web_ui.json +15 -2
- claude_mpm/cli/__init__.py +34 -614
- claude_mpm/cli/commands/agent_manager.py +25 -12
- claude_mpm/cli/commands/agent_state_manager.py +186 -0
- claude_mpm/cli/commands/agents.py +235 -148
- claude_mpm/cli/commands/agents_detect.py +380 -0
- claude_mpm/cli/commands/agents_recommend.py +309 -0
- claude_mpm/cli/commands/aggregate.py +7 -3
- claude_mpm/cli/commands/analyze.py +9 -4
- claude_mpm/cli/commands/analyze_code.py +7 -2
- claude_mpm/cli/commands/auto_configure.py +570 -0
- claude_mpm/cli/commands/config.py +47 -13
- claude_mpm/cli/commands/configure.py +419 -1571
- claude_mpm/cli/commands/configure_agent_display.py +261 -0
- claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
- claude_mpm/cli/commands/configure_hook_manager.py +225 -0
- claude_mpm/cli/commands/configure_models.py +18 -0
- claude_mpm/cli/commands/configure_navigation.py +167 -0
- claude_mpm/cli/commands/configure_paths.py +104 -0
- claude_mpm/cli/commands/configure_persistence.py +254 -0
- claude_mpm/cli/commands/configure_startup_manager.py +646 -0
- claude_mpm/cli/commands/configure_template_editor.py +497 -0
- claude_mpm/cli/commands/configure_validators.py +73 -0
- claude_mpm/cli/commands/local_deploy.py +537 -0
- claude_mpm/cli/commands/memory.py +54 -20
- claude_mpm/cli/commands/mpm_init.py +585 -196
- claude_mpm/cli/commands/mpm_init_handler.py +37 -3
- claude_mpm/cli/commands/search.py +170 -4
- claude_mpm/cli/commands/upgrade.py +152 -0
- claude_mpm/cli/executor.py +202 -0
- claude_mpm/cli/helpers.py +105 -0
- claude_mpm/cli/interactive/__init__.py +3 -0
- claude_mpm/cli/interactive/skills_wizard.py +491 -0
- claude_mpm/cli/parsers/__init__.py +7 -1
- claude_mpm/cli/parsers/agents_parser.py +9 -0
- claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
- claude_mpm/cli/parsers/base_parser.py +110 -3
- claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +65 -5
- claude_mpm/cli/shared/output_formatters.py +28 -19
- claude_mpm/cli/startup.py +481 -0
- claude_mpm/cli/utils.py +52 -1
- claude_mpm/commands/mpm-agents-detect.md +168 -0
- claude_mpm/commands/mpm-agents-recommend.md +214 -0
- claude_mpm/commands/mpm-agents.md +75 -1
- claude_mpm/commands/mpm-auto-configure.md +217 -0
- claude_mpm/commands/mpm-help.md +163 -0
- claude_mpm/commands/mpm-init.md +148 -3
- claude_mpm/commands/mpm-version.md +113 -0
- claude_mpm/commands/mpm.md +1 -0
- claude_mpm/config/agent_config.py +2 -2
- claude_mpm/config/model_config.py +428 -0
- claude_mpm/constants.py +1 -0
- claude_mpm/core/base_service.py +13 -12
- claude_mpm/core/enums.py +452 -0
- claude_mpm/core/factories.py +1 -1
- claude_mpm/core/instruction_reinforcement_hook.py +2 -1
- claude_mpm/core/interactive_session.py +9 -3
- claude_mpm/core/log_manager.py +2 -0
- claude_mpm/core/logging_config.py +6 -2
- claude_mpm/core/oneshot_session.py +8 -4
- claude_mpm/core/optimized_agent_loader.py +3 -3
- claude_mpm/core/output_style_manager.py +12 -192
- claude_mpm/core/service_registry.py +5 -1
- claude_mpm/core/types.py +2 -9
- claude_mpm/core/typing_utils.py +7 -6
- claude_mpm/dashboard/static/js/dashboard.js +0 -14
- claude_mpm/dashboard/templates/index.html +3 -41
- claude_mpm/hooks/__init__.py +20 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +4 -2
- claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +23 -2
- claude_mpm/hooks/failure_learning/__init__.py +60 -0
- claude_mpm/hooks/failure_learning/failure_detection_hook.py +235 -0
- claude_mpm/hooks/failure_learning/fix_detection_hook.py +217 -0
- claude_mpm/hooks/failure_learning/learning_extraction_hook.py +286 -0
- claude_mpm/hooks/instruction_reinforcement.py +7 -2
- claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
- claude_mpm/hooks/kuzu_memory_hook.py +37 -12
- claude_mpm/hooks/kuzu_response_hook.py +183 -0
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/services/agents/__init__.py +18 -5
- claude_mpm/services/agents/auto_config_manager.py +796 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
- claude_mpm/services/agents/deployment/agent_validator.py +17 -1
- claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
- claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
- claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
- claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
- claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
- claude_mpm/services/agents/local_template_manager.py +1 -1
- claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
- claude_mpm/services/agents/observers.py +547 -0
- claude_mpm/services/agents/recommender.py +568 -0
- claude_mpm/services/agents/registry/modification_tracker.py +5 -2
- claude_mpm/services/command_handler_service.py +11 -5
- claude_mpm/services/core/__init__.py +33 -1
- claude_mpm/services/core/interfaces/__init__.py +90 -3
- claude_mpm/services/core/interfaces/agent.py +184 -0
- claude_mpm/services/core/interfaces/health.py +172 -0
- claude_mpm/services/core/interfaces/model.py +281 -0
- claude_mpm/services/core/interfaces/process.py +372 -0
- claude_mpm/services/core/interfaces/project.py +121 -0
- claude_mpm/services/core/interfaces/restart.py +307 -0
- claude_mpm/services/core/interfaces/stability.py +260 -0
- claude_mpm/services/core/memory_manager.py +11 -24
- claude_mpm/services/core/models/__init__.py +79 -0
- claude_mpm/services/core/models/agent_config.py +381 -0
- claude_mpm/services/core/models/health.py +162 -0
- claude_mpm/services/core/models/process.py +235 -0
- claude_mpm/services/core/models/restart.py +302 -0
- claude_mpm/services/core/models/stability.py +264 -0
- claude_mpm/services/core/models/toolchain.py +306 -0
- claude_mpm/services/core/path_resolver.py +23 -7
- claude_mpm/services/diagnostics/__init__.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
- claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
- claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
- claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
- claude_mpm/services/diagnostics/checks/installation_check.py +30 -29
- claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
- claude_mpm/services/diagnostics/checks/mcp_check.py +50 -36
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +38 -33
- claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
- claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
- claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
- claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
- claude_mpm/services/diagnostics/models.py +19 -24
- claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
- claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
- claude_mpm/services/infrastructure/monitoring/base.py +5 -13
- claude_mpm/services/infrastructure/monitoring/network.py +7 -6
- claude_mpm/services/infrastructure/monitoring/process.py +13 -12
- claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
- claude_mpm/services/infrastructure/monitoring/service.py +16 -15
- claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
- claude_mpm/services/local_ops/__init__.py +163 -0
- claude_mpm/services/local_ops/crash_detector.py +257 -0
- claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
- claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
- claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
- claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
- claude_mpm/services/local_ops/health_manager.py +430 -0
- claude_mpm/services/local_ops/log_monitor.py +396 -0
- claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
- claude_mpm/services/local_ops/process_manager.py +595 -0
- claude_mpm/services/local_ops/resource_monitor.py +331 -0
- claude_mpm/services/local_ops/restart_manager.py +401 -0
- claude_mpm/services/local_ops/restart_policy.py +387 -0
- claude_mpm/services/local_ops/state_manager.py +372 -0
- claude_mpm/services/local_ops/unified_manager.py +600 -0
- claude_mpm/services/mcp_config_manager.py +9 -4
- claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
- claude_mpm/services/mcp_gateway/core/base.py +18 -31
- claude_mpm/services/mcp_gateway/main.py +30 -0
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +206 -32
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +30 -28
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +25 -5
- claude_mpm/services/mcp_service_verifier.py +1 -1
- claude_mpm/services/memory/failure_tracker.py +563 -0
- claude_mpm/services/memory_hook_service.py +165 -4
- claude_mpm/services/model/__init__.py +147 -0
- claude_mpm/services/model/base_provider.py +365 -0
- claude_mpm/services/model/claude_provider.py +412 -0
- claude_mpm/services/model/model_router.py +453 -0
- claude_mpm/services/model/ollama_provider.py +415 -0
- claude_mpm/services/monitor/daemon_manager.py +3 -2
- claude_mpm/services/monitor/handlers/dashboard.py +2 -1
- claude_mpm/services/monitor/handlers/hooks.py +2 -1
- claude_mpm/services/monitor/management/lifecycle.py +3 -2
- claude_mpm/services/monitor/server.py +2 -1
- claude_mpm/services/project/__init__.py +23 -0
- claude_mpm/services/project/detection_strategies.py +719 -0
- claude_mpm/services/project/toolchain_analyzer.py +581 -0
- claude_mpm/services/self_upgrade_service.py +342 -0
- claude_mpm/services/session_management_service.py +3 -2
- claude_mpm/services/session_manager.py +205 -1
- claude_mpm/services/shared/async_service_base.py +16 -27
- claude_mpm/services/shared/lifecycle_service_base.py +1 -14
- claude_mpm/services/socketio/handlers/__init__.py +5 -2
- claude_mpm/services/socketio/handlers/hook.py +13 -2
- claude_mpm/services/socketio/handlers/registry.py +4 -2
- claude_mpm/services/socketio/server/main.py +10 -8
- claude_mpm/services/subprocess_launcher_service.py +14 -5
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +7 -6
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
- claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
- claude_mpm/services/unified/deployment_strategies/local.py +6 -5
- claude_mpm/services/unified/deployment_strategies/utils.py +6 -5
- claude_mpm/services/unified/deployment_strategies/vercel.py +7 -6
- claude_mpm/services/unified/interfaces.py +3 -1
- claude_mpm/services/unified/unified_analyzer.py +14 -10
- claude_mpm/services/unified/unified_config.py +2 -1
- claude_mpm/services/unified/unified_deployment.py +9 -4
- claude_mpm/services/version_service.py +104 -1
- claude_mpm/skills/__init__.py +21 -0
- claude_mpm/skills/bundled/__init__.py +6 -0
- claude_mpm/skills/bundled/api-documentation.md +393 -0
- claude_mpm/skills/bundled/async-testing.md +571 -0
- claude_mpm/skills/bundled/code-review.md +143 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/docker-containerization.md +194 -0
- claude_mpm/skills/bundled/express-local-dev.md +1429 -0
- claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
- claude_mpm/skills/bundled/git-workflow.md +414 -0
- claude_mpm/skills/bundled/imagemagick.md +204 -0
- claude_mpm/skills/bundled/json-data-handling.md +223 -0
- claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
- claude_mpm/skills/bundled/pdf.md +141 -0
- claude_mpm/skills/bundled/performance-profiling.md +567 -0
- claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
- claude_mpm/skills/bundled/security-scanning.md +327 -0
- claude_mpm/skills/bundled/systematic-debugging.md +473 -0
- claude_mpm/skills/bundled/test-driven-development.md +378 -0
- claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
- claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
- claude_mpm/skills/bundled/xlsx.md +157 -0
- claude_mpm/skills/registry.py +286 -0
- claude_mpm/skills/skill_manager.py +310 -0
- claude_mpm/storage/state_storage.py +15 -15
- claude_mpm/tools/code_tree_analyzer.py +177 -141
- claude_mpm/tools/code_tree_events.py +4 -2
- claude_mpm/utils/agent_dependency_loader.py +40 -20
- claude_mpm/utils/display_helper.py +260 -0
- claude_mpm/utils/git_analyzer.py +407 -0
- claude_mpm/utils/robust_installer.py +73 -19
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/METADATA +129 -12
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/RECORD +295 -193
- claude_mpm/dashboard/static/css/code-tree.css +0 -1639
- claude_mpm/dashboard/static/index-hub-backup.html +0 -713
- claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
- claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
- claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
- claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
- claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
- claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
- claude_mpm/services/project/analyzer_refactored.py +0 -450
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/WHEEL +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unified Local Operations Manager
|
|
3
|
+
=================================
|
|
4
|
+
|
|
5
|
+
WHY: Provides a single, coordinated entry point for all local process management
|
|
6
|
+
capabilities. Orchestrates process lifecycle, health monitoring, auto-restart,
|
|
7
|
+
stability detection, and resource monitoring into a cohesive service.
|
|
8
|
+
|
|
9
|
+
DESIGN DECISION: Aggregates all component managers (ProcessManager, HealthCheckManager,
|
|
10
|
+
RestartManager, MemoryLeakDetector, LogMonitor, ResourceMonitor) with configuration
|
|
11
|
+
loading from YAML. This simplifies integration for both CLI and agents.
|
|
12
|
+
|
|
13
|
+
ARCHITECTURE:
|
|
14
|
+
- Single service that initializes and coordinates all components
|
|
15
|
+
- Configuration-driven setup via .claude-mpm/local-ops-config.yaml
|
|
16
|
+
- Unified status aggregation across all monitoring dimensions
|
|
17
|
+
- Simplified API hiding internal complexity
|
|
18
|
+
|
|
19
|
+
USAGE:
|
|
20
|
+
from claude_mpm.services.local_ops import UnifiedLocalOpsManager, StartConfig
|
|
21
|
+
|
|
22
|
+
# Initialize with project root
|
|
23
|
+
manager = UnifiedLocalOpsManager(
|
|
24
|
+
project_root=Path("/path/to/project")
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Start a deployment with auto-restart
|
|
28
|
+
config = StartConfig(
|
|
29
|
+
command=["npm", "run", "dev"],
|
|
30
|
+
working_directory="/path/to/project",
|
|
31
|
+
port=3000,
|
|
32
|
+
auto_find_port=True,
|
|
33
|
+
)
|
|
34
|
+
deployment = manager.start_deployment(config, auto_restart=True)
|
|
35
|
+
|
|
36
|
+
# Get comprehensive status
|
|
37
|
+
status = manager.get_full_status(deployment.deployment_id)
|
|
38
|
+
|
|
39
|
+
# List all deployments
|
|
40
|
+
deployments = manager.list_deployments()
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
from pathlib import Path
|
|
44
|
+
from typing import Any, Dict, List, Optional
|
|
45
|
+
|
|
46
|
+
import yaml
|
|
47
|
+
|
|
48
|
+
from claude_mpm.core.enums import ServiceState
|
|
49
|
+
from claude_mpm.services.core.base import SyncBaseService
|
|
50
|
+
from claude_mpm.services.core.models.health import DeploymentHealth
|
|
51
|
+
from claude_mpm.services.core.models.process import (
|
|
52
|
+
DeploymentState,
|
|
53
|
+
ProcessInfo,
|
|
54
|
+
StartConfig,
|
|
55
|
+
)
|
|
56
|
+
from claude_mpm.services.core.models.restart import RestartConfig, RestartHistory
|
|
57
|
+
|
|
58
|
+
from .health_manager import HealthCheckManager
|
|
59
|
+
from .log_monitor import LogMonitor
|
|
60
|
+
from .memory_leak_detector import MemoryLeakDetector
|
|
61
|
+
from .process_manager import LocalProcessManager
|
|
62
|
+
from .resource_monitor import ResourceMonitor
|
|
63
|
+
from .restart_manager import RestartManager
|
|
64
|
+
from .state_manager import DeploymentStateManager
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class UnifiedLocalOpsManager(SyncBaseService):
|
|
68
|
+
"""
|
|
69
|
+
Unified manager that coordinates all local operations services.
|
|
70
|
+
|
|
71
|
+
WHY: Provides a single entry point for process management that internally
|
|
72
|
+
coordinates all the individual services. This simplifies usage for both
|
|
73
|
+
CLI commands and agent integration.
|
|
74
|
+
|
|
75
|
+
Components:
|
|
76
|
+
- LocalProcessManager: Process lifecycle management
|
|
77
|
+
- HealthCheckManager: Health monitoring
|
|
78
|
+
- RestartManager: Auto-restart orchestration
|
|
79
|
+
- MemoryLeakDetector: Memory leak detection
|
|
80
|
+
- LogMonitor: Error pattern detection
|
|
81
|
+
- ResourceMonitor: Resource exhaustion prevention
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
def __init__(
|
|
85
|
+
self,
|
|
86
|
+
project_root: Path,
|
|
87
|
+
config_path: Optional[Path] = None,
|
|
88
|
+
config: Optional[Dict[str, Any]] = None,
|
|
89
|
+
):
|
|
90
|
+
"""
|
|
91
|
+
Initialize unified local operations manager.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
project_root: Root directory of the project
|
|
95
|
+
config_path: Optional path to configuration file
|
|
96
|
+
config: Optional configuration dict (overrides file)
|
|
97
|
+
"""
|
|
98
|
+
super().__init__("UnifiedLocalOpsManager")
|
|
99
|
+
|
|
100
|
+
self.project_root = project_root
|
|
101
|
+
self.config_path = (
|
|
102
|
+
config_path or project_root / ".claude-mpm" / "local-ops-config.yaml"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Load configuration
|
|
106
|
+
self.config = self._load_config(config)
|
|
107
|
+
|
|
108
|
+
# Initialize component managers (lazy initialization)
|
|
109
|
+
self._state_manager: Optional[DeploymentStateManager] = None
|
|
110
|
+
self._process_manager: Optional[LocalProcessManager] = None
|
|
111
|
+
self._health_manager: Optional[HealthCheckManager] = None
|
|
112
|
+
self._restart_manager: Optional[RestartManager] = None
|
|
113
|
+
self._memory_detector: Optional[MemoryLeakDetector] = None
|
|
114
|
+
self._log_monitor: Optional[LogMonitor] = None
|
|
115
|
+
self._resource_monitor: Optional[ResourceMonitor] = None
|
|
116
|
+
|
|
117
|
+
def initialize(self) -> bool:
|
|
118
|
+
"""
|
|
119
|
+
Initialize the unified manager and all components.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
True if initialization successful
|
|
123
|
+
"""
|
|
124
|
+
try:
|
|
125
|
+
# Ensure .claude-mpm directory exists
|
|
126
|
+
claude_mpm_dir = self.project_root / ".claude-mpm"
|
|
127
|
+
claude_mpm_dir.mkdir(exist_ok=True)
|
|
128
|
+
|
|
129
|
+
# Initialize state manager
|
|
130
|
+
state_file = claude_mpm_dir / "deployment-state.json"
|
|
131
|
+
self._state_manager = DeploymentStateManager(state_file)
|
|
132
|
+
if not self._state_manager.initialize():
|
|
133
|
+
self.log_error("Failed to initialize state manager")
|
|
134
|
+
return False
|
|
135
|
+
|
|
136
|
+
# Initialize process manager
|
|
137
|
+
self._process_manager = LocalProcessManager(self._state_manager)
|
|
138
|
+
if not self._process_manager.initialize():
|
|
139
|
+
self.log_error("Failed to initialize process manager")
|
|
140
|
+
return False
|
|
141
|
+
|
|
142
|
+
# Initialize health manager
|
|
143
|
+
health_interval = self.config.get("defaults", {}).get(
|
|
144
|
+
"health_check_interval_seconds", 30
|
|
145
|
+
)
|
|
146
|
+
self._health_manager = HealthCheckManager(
|
|
147
|
+
self._process_manager, check_interval=health_interval
|
|
148
|
+
)
|
|
149
|
+
if not self._health_manager.initialize():
|
|
150
|
+
self.log_error("Failed to initialize health manager")
|
|
151
|
+
return False
|
|
152
|
+
|
|
153
|
+
# Initialize restart manager
|
|
154
|
+
restart_config = self._create_restart_config()
|
|
155
|
+
self._restart_manager = RestartManager(
|
|
156
|
+
self._process_manager, self._health_manager, restart_config
|
|
157
|
+
)
|
|
158
|
+
if not self._restart_manager.initialize():
|
|
159
|
+
self.log_error("Failed to initialize restart manager")
|
|
160
|
+
return False
|
|
161
|
+
|
|
162
|
+
# Initialize stability monitors
|
|
163
|
+
self._memory_detector = MemoryLeakDetector(
|
|
164
|
+
threshold_mb_per_minute=self.config.get("stability", {}).get(
|
|
165
|
+
"memory_leak_threshold_mb_per_minute", 10.0
|
|
166
|
+
)
|
|
167
|
+
)
|
|
168
|
+
if not self._memory_detector.initialize():
|
|
169
|
+
self.log_error("Failed to initialize memory leak detector")
|
|
170
|
+
return False
|
|
171
|
+
|
|
172
|
+
# Initialize log monitor if enabled
|
|
173
|
+
if self.config.get("log_monitoring", {}).get("enabled", True):
|
|
174
|
+
self._log_monitor = LogMonitor(
|
|
175
|
+
error_patterns=self.config.get("log_monitoring", {}).get(
|
|
176
|
+
"error_patterns", []
|
|
177
|
+
)
|
|
178
|
+
)
|
|
179
|
+
if not self._log_monitor.initialize():
|
|
180
|
+
self.log_error("Failed to initialize log monitor")
|
|
181
|
+
return False
|
|
182
|
+
|
|
183
|
+
# Initialize resource monitor
|
|
184
|
+
stability_config = self.config.get("stability", {})
|
|
185
|
+
self._resource_monitor = ResourceMonitor(
|
|
186
|
+
fd_threshold_percent=stability_config.get("fd_threshold_percent", 0.8),
|
|
187
|
+
thread_threshold=stability_config.get("thread_threshold", 1000),
|
|
188
|
+
connection_threshold=stability_config.get("connection_threshold", 500),
|
|
189
|
+
disk_threshold_mb=stability_config.get("disk_threshold_mb", 100),
|
|
190
|
+
)
|
|
191
|
+
if not self._resource_monitor.initialize():
|
|
192
|
+
self.log_error("Failed to initialize resource monitor")
|
|
193
|
+
return False
|
|
194
|
+
|
|
195
|
+
self._initialized = True
|
|
196
|
+
self.log_info(
|
|
197
|
+
f"Unified local ops manager initialized for {self.project_root}"
|
|
198
|
+
)
|
|
199
|
+
return True
|
|
200
|
+
|
|
201
|
+
except Exception as e:
|
|
202
|
+
self.log_error(f"Failed to initialize: {e}")
|
|
203
|
+
return False
|
|
204
|
+
|
|
205
|
+
def shutdown(self) -> None:
|
|
206
|
+
"""Shutdown all component managers."""
|
|
207
|
+
if self._health_manager:
|
|
208
|
+
self._health_manager.shutdown()
|
|
209
|
+
if self._restart_manager:
|
|
210
|
+
self._restart_manager.shutdown()
|
|
211
|
+
if self._memory_detector:
|
|
212
|
+
self._memory_detector.shutdown()
|
|
213
|
+
if self._log_monitor:
|
|
214
|
+
self._log_monitor.shutdown()
|
|
215
|
+
if self._resource_monitor:
|
|
216
|
+
self._resource_monitor.shutdown()
|
|
217
|
+
if self._process_manager:
|
|
218
|
+
self._process_manager.shutdown()
|
|
219
|
+
if self._state_manager:
|
|
220
|
+
self._state_manager.shutdown()
|
|
221
|
+
|
|
222
|
+
self._shutdown = True
|
|
223
|
+
self.log_info("Unified local ops manager shutdown complete")
|
|
224
|
+
|
|
225
|
+
def start_deployment(
|
|
226
|
+
self,
|
|
227
|
+
config: StartConfig,
|
|
228
|
+
auto_restart: bool = False,
|
|
229
|
+
) -> DeploymentState:
|
|
230
|
+
"""
|
|
231
|
+
Start a new local deployment with full orchestration.
|
|
232
|
+
|
|
233
|
+
WHY: Single method that handles process spawning, health monitoring
|
|
234
|
+
setup, and optional auto-restart enablement.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
config: Configuration for the deployment
|
|
238
|
+
auto_restart: If True, enable auto-restart for this deployment
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
DeploymentState with deployment information
|
|
242
|
+
|
|
243
|
+
Raises:
|
|
244
|
+
ProcessSpawnError: If deployment fails to start
|
|
245
|
+
"""
|
|
246
|
+
self._ensure_initialized()
|
|
247
|
+
|
|
248
|
+
# Start the process
|
|
249
|
+
deployment = self._process_manager.start(config)
|
|
250
|
+
|
|
251
|
+
# Start health monitoring for this deployment
|
|
252
|
+
self._health_manager.start_monitoring()
|
|
253
|
+
|
|
254
|
+
# Enable auto-restart if requested
|
|
255
|
+
if auto_restart or self.config.get("defaults", {}).get(
|
|
256
|
+
"auto_restart_enabled", False
|
|
257
|
+
):
|
|
258
|
+
restart_config = self._create_restart_config()
|
|
259
|
+
success = self._restart_manager.enable_auto_restart(
|
|
260
|
+
deployment.deployment_id, restart_config
|
|
261
|
+
)
|
|
262
|
+
if success:
|
|
263
|
+
self.log_info(f"Auto-restart enabled for {deployment.deployment_id}")
|
|
264
|
+
else:
|
|
265
|
+
self.log_warning(
|
|
266
|
+
f"Failed to enable auto-restart for {deployment.deployment_id}"
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
return deployment
|
|
270
|
+
|
|
271
|
+
def stop_deployment(
|
|
272
|
+
self,
|
|
273
|
+
deployment_id: str,
|
|
274
|
+
timeout: int = 10,
|
|
275
|
+
force: bool = False,
|
|
276
|
+
) -> bool:
|
|
277
|
+
"""
|
|
278
|
+
Stop a deployment and clean up resources.
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
deployment_id: Unique deployment identifier
|
|
282
|
+
timeout: Seconds to wait for graceful shutdown
|
|
283
|
+
force: If True, kill immediately without waiting
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
True if stopped successfully
|
|
287
|
+
"""
|
|
288
|
+
self._ensure_initialized()
|
|
289
|
+
|
|
290
|
+
# Disable auto-restart if enabled
|
|
291
|
+
self._restart_manager.disable_auto_restart(deployment_id)
|
|
292
|
+
|
|
293
|
+
# Stop the process
|
|
294
|
+
return self._process_manager.stop(deployment_id, timeout=timeout, force=force)
|
|
295
|
+
|
|
296
|
+
def restart_deployment(
|
|
297
|
+
self,
|
|
298
|
+
deployment_id: str,
|
|
299
|
+
timeout: int = 10,
|
|
300
|
+
) -> DeploymentState:
|
|
301
|
+
"""
|
|
302
|
+
Restart a deployment.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
deployment_id: Unique deployment identifier
|
|
306
|
+
timeout: Seconds to wait for graceful shutdown
|
|
307
|
+
|
|
308
|
+
Returns:
|
|
309
|
+
New DeploymentState after restart
|
|
310
|
+
"""
|
|
311
|
+
self._ensure_initialized()
|
|
312
|
+
return self._process_manager.restart(deployment_id, timeout=timeout)
|
|
313
|
+
|
|
314
|
+
def get_deployment_status(self, deployment_id: str) -> Optional[ProcessInfo]:
|
|
315
|
+
"""
|
|
316
|
+
Get current status of a deployment.
|
|
317
|
+
|
|
318
|
+
Args:
|
|
319
|
+
deployment_id: Unique deployment identifier
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
ProcessInfo with current status, or None if not found
|
|
323
|
+
"""
|
|
324
|
+
self._ensure_initialized()
|
|
325
|
+
return self._process_manager.get_status(deployment_id)
|
|
326
|
+
|
|
327
|
+
def get_health_status(self, deployment_id: str) -> Optional[DeploymentHealth]:
|
|
328
|
+
"""
|
|
329
|
+
Get health status for a deployment.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
deployment_id: Unique deployment identifier
|
|
333
|
+
|
|
334
|
+
Returns:
|
|
335
|
+
DeploymentHealth with current health, or None if not found
|
|
336
|
+
"""
|
|
337
|
+
self._ensure_initialized()
|
|
338
|
+
return self._health_manager.check_health(deployment_id)
|
|
339
|
+
|
|
340
|
+
def get_restart_history(self, deployment_id: str) -> Optional[RestartHistory]:
|
|
341
|
+
"""
|
|
342
|
+
Get restart history for a deployment.
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
deployment_id: Unique deployment identifier
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
RestartHistory with restart information
|
|
349
|
+
"""
|
|
350
|
+
self._ensure_initialized()
|
|
351
|
+
return self._restart_manager.get_restart_history(deployment_id)
|
|
352
|
+
|
|
353
|
+
def enable_auto_restart(
|
|
354
|
+
self,
|
|
355
|
+
deployment_id: str,
|
|
356
|
+
config: Optional[RestartConfig] = None,
|
|
357
|
+
) -> bool:
|
|
358
|
+
"""
|
|
359
|
+
Enable auto-restart for a deployment.
|
|
360
|
+
|
|
361
|
+
Args:
|
|
362
|
+
deployment_id: Unique deployment identifier
|
|
363
|
+
config: Optional restart configuration
|
|
364
|
+
|
|
365
|
+
Returns:
|
|
366
|
+
True if enabled successfully
|
|
367
|
+
"""
|
|
368
|
+
self._ensure_initialized()
|
|
369
|
+
restart_config = config or self._create_restart_config()
|
|
370
|
+
return self._restart_manager.enable_auto_restart(deployment_id, restart_config)
|
|
371
|
+
|
|
372
|
+
def disable_auto_restart(self, deployment_id: str) -> bool:
|
|
373
|
+
"""
|
|
374
|
+
Disable auto-restart for a deployment.
|
|
375
|
+
|
|
376
|
+
Args:
|
|
377
|
+
deployment_id: Unique deployment identifier
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
True if disabled successfully
|
|
381
|
+
"""
|
|
382
|
+
self._ensure_initialized()
|
|
383
|
+
return self._restart_manager.disable_auto_restart(deployment_id)
|
|
384
|
+
|
|
385
|
+
def list_deployments(
|
|
386
|
+
self,
|
|
387
|
+
status_filter: Optional[ServiceState] = None,
|
|
388
|
+
) -> List[DeploymentState]:
|
|
389
|
+
"""
|
|
390
|
+
List all deployments.
|
|
391
|
+
|
|
392
|
+
Args:
|
|
393
|
+
status_filter: Optional status to filter by
|
|
394
|
+
|
|
395
|
+
Returns:
|
|
396
|
+
List of DeploymentState objects
|
|
397
|
+
"""
|
|
398
|
+
self._ensure_initialized()
|
|
399
|
+
|
|
400
|
+
if status_filter:
|
|
401
|
+
return self._state_manager.get_deployments_by_status(status_filter)
|
|
402
|
+
return self._state_manager.get_all_deployments()
|
|
403
|
+
|
|
404
|
+
def get_full_status(self, deployment_id: str) -> Dict[str, Any]:
|
|
405
|
+
"""
|
|
406
|
+
Get comprehensive status aggregating all monitoring dimensions.
|
|
407
|
+
|
|
408
|
+
WHY: Provides a single view of process state, health, restart history,
|
|
409
|
+
memory trends, and resource usage for complete visibility.
|
|
410
|
+
|
|
411
|
+
Args:
|
|
412
|
+
deployment_id: Unique deployment identifier
|
|
413
|
+
|
|
414
|
+
Returns:
|
|
415
|
+
Dictionary with all status information
|
|
416
|
+
"""
|
|
417
|
+
self._ensure_initialized()
|
|
418
|
+
|
|
419
|
+
status: Dict[str, Any] = {
|
|
420
|
+
"deployment_id": deployment_id,
|
|
421
|
+
"process": None,
|
|
422
|
+
"health": None,
|
|
423
|
+
"restart_history": None,
|
|
424
|
+
"memory_trend": None,
|
|
425
|
+
"log_matches": None,
|
|
426
|
+
"resources": None,
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
# Get process status
|
|
430
|
+
process_info = self.get_deployment_status(deployment_id)
|
|
431
|
+
if process_info:
|
|
432
|
+
status["process"] = {
|
|
433
|
+
"status": process_info.status.value,
|
|
434
|
+
"pid": process_info.process_id,
|
|
435
|
+
"port": process_info.port,
|
|
436
|
+
"uptime_seconds": process_info.uptime_seconds,
|
|
437
|
+
"memory_mb": process_info.memory_mb,
|
|
438
|
+
"cpu_percent": process_info.cpu_percent,
|
|
439
|
+
"is_responding": process_info.is_responding,
|
|
440
|
+
"error_message": process_info.error_message,
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
# Get health status
|
|
444
|
+
health = self.get_health_status(deployment_id)
|
|
445
|
+
if health:
|
|
446
|
+
status["health"] = {
|
|
447
|
+
"status": health.overall_status.value,
|
|
448
|
+
"http_healthy": health.http_healthy,
|
|
449
|
+
"process_healthy": health.process_healthy,
|
|
450
|
+
"resource_healthy": health.resource_healthy,
|
|
451
|
+
"last_check": (
|
|
452
|
+
health.last_check.isoformat() if health.last_check else None
|
|
453
|
+
),
|
|
454
|
+
"failure_reason": health.failure_reason,
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
# Get restart history
|
|
458
|
+
restart_history = self.get_restart_history(deployment_id)
|
|
459
|
+
if restart_history:
|
|
460
|
+
status["restart_history"] = {
|
|
461
|
+
"total_restarts": restart_history.total_restarts,
|
|
462
|
+
"successful_restarts": restart_history.successful_restarts,
|
|
463
|
+
"failed_restarts": restart_history.failed_restarts,
|
|
464
|
+
"circuit_breaker_state": restart_history.circuit_breaker_state.value,
|
|
465
|
+
"auto_restart_enabled": restart_history.auto_restart_enabled,
|
|
466
|
+
"recent_attempts": [
|
|
467
|
+
{
|
|
468
|
+
"timestamp": attempt.timestamp.isoformat(),
|
|
469
|
+
"success": attempt.success,
|
|
470
|
+
"reason": attempt.reason,
|
|
471
|
+
"error_message": attempt.error_message,
|
|
472
|
+
}
|
|
473
|
+
for attempt in restart_history.recent_attempts[-5:] # Last 5
|
|
474
|
+
],
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
# Get memory trend if available
|
|
478
|
+
if self._memory_detector and process_info and process_info.process_id:
|
|
479
|
+
memory_trend = self._memory_detector.detect_leak(process_info.process_id)
|
|
480
|
+
if memory_trend:
|
|
481
|
+
status["memory_trend"] = memory_trend.value
|
|
482
|
+
|
|
483
|
+
# Get log matches if log monitor enabled
|
|
484
|
+
if self._log_monitor and process_info:
|
|
485
|
+
deployment = self._state_manager.get_deployment(deployment_id)
|
|
486
|
+
if deployment:
|
|
487
|
+
log_file = Path(deployment.working_directory) / "app.log"
|
|
488
|
+
if log_file.exists():
|
|
489
|
+
matches = self._log_monitor.check_for_errors(log_file)
|
|
490
|
+
if matches:
|
|
491
|
+
status["log_matches"] = [
|
|
492
|
+
{
|
|
493
|
+
"pattern": match.pattern,
|
|
494
|
+
"line": match.matched_line,
|
|
495
|
+
"line_number": match.line_number,
|
|
496
|
+
"timestamp": match.timestamp.isoformat(),
|
|
497
|
+
}
|
|
498
|
+
for match in matches[:5] # Last 5
|
|
499
|
+
]
|
|
500
|
+
|
|
501
|
+
# Get resource status
|
|
502
|
+
if self._resource_monitor and process_info and process_info.process_id:
|
|
503
|
+
resources = self._resource_monitor.check_resources(process_info.process_id)
|
|
504
|
+
if resources:
|
|
505
|
+
status["resources"] = {
|
|
506
|
+
"file_descriptors": resources.file_descriptors,
|
|
507
|
+
"fd_limit": resources.fd_limit,
|
|
508
|
+
"thread_count": resources.thread_count,
|
|
509
|
+
"connection_count": resources.connection_count,
|
|
510
|
+
"disk_usage_mb": resources.disk_usage_mb,
|
|
511
|
+
"warnings": resources.warnings,
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
return status
|
|
515
|
+
|
|
516
|
+
def _load_config(self, config_override: Optional[Dict[str, Any]]) -> Dict[str, Any]:
|
|
517
|
+
"""
|
|
518
|
+
Load configuration from file or use provided config.
|
|
519
|
+
|
|
520
|
+
Args:
|
|
521
|
+
config_override: Optional configuration dict that overrides file
|
|
522
|
+
|
|
523
|
+
Returns:
|
|
524
|
+
Configuration dictionary
|
|
525
|
+
"""
|
|
526
|
+
# Use override if provided
|
|
527
|
+
if config_override:
|
|
528
|
+
return config_override
|
|
529
|
+
|
|
530
|
+
# Load from file if it exists
|
|
531
|
+
if self.config_path.exists():
|
|
532
|
+
try:
|
|
533
|
+
with self.config_path.open() as f:
|
|
534
|
+
return yaml.safe_load(f) or {}
|
|
535
|
+
except Exception as e:
|
|
536
|
+
self.log_warning(f"Failed to load config from {self.config_path}: {e}")
|
|
537
|
+
|
|
538
|
+
# Return default configuration
|
|
539
|
+
return {
|
|
540
|
+
"version": "1.0",
|
|
541
|
+
"defaults": {
|
|
542
|
+
"health_check_interval_seconds": 30,
|
|
543
|
+
"auto_restart_enabled": False,
|
|
544
|
+
},
|
|
545
|
+
"restart_policy": {
|
|
546
|
+
"max_attempts": 5,
|
|
547
|
+
"initial_backoff_seconds": 2.0,
|
|
548
|
+
"max_backoff_seconds": 300.0,
|
|
549
|
+
"backoff_multiplier": 2.0,
|
|
550
|
+
"circuit_breaker_threshold": 3,
|
|
551
|
+
"circuit_breaker_window_seconds": 300,
|
|
552
|
+
"circuit_breaker_reset_seconds": 600,
|
|
553
|
+
},
|
|
554
|
+
"stability": {
|
|
555
|
+
"memory_leak_threshold_mb_per_minute": 10.0,
|
|
556
|
+
"fd_threshold_percent": 0.8,
|
|
557
|
+
"thread_threshold": 1000,
|
|
558
|
+
"connection_threshold": 500,
|
|
559
|
+
"disk_threshold_mb": 100,
|
|
560
|
+
},
|
|
561
|
+
"log_monitoring": {
|
|
562
|
+
"enabled": True,
|
|
563
|
+
"error_patterns": [
|
|
564
|
+
"OutOfMemoryError",
|
|
565
|
+
"Segmentation fault",
|
|
566
|
+
"Exception:",
|
|
567
|
+
"Error:",
|
|
568
|
+
"FATAL",
|
|
569
|
+
],
|
|
570
|
+
},
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
def _create_restart_config(self) -> RestartConfig:
|
|
574
|
+
"""Create RestartConfig from loaded configuration."""
|
|
575
|
+
restart_policy = self.config.get("restart_policy", {})
|
|
576
|
+
return RestartConfig(
|
|
577
|
+
max_attempts=restart_policy.get("max_attempts", 5),
|
|
578
|
+
initial_backoff_seconds=restart_policy.get("initial_backoff_seconds", 2.0),
|
|
579
|
+
max_backoff_seconds=restart_policy.get("max_backoff_seconds", 300.0),
|
|
580
|
+
backoff_multiplier=restart_policy.get("backoff_multiplier", 2.0),
|
|
581
|
+
circuit_breaker_threshold=restart_policy.get(
|
|
582
|
+
"circuit_breaker_threshold", 3
|
|
583
|
+
),
|
|
584
|
+
circuit_breaker_window_seconds=restart_policy.get(
|
|
585
|
+
"circuit_breaker_window_seconds", 300
|
|
586
|
+
),
|
|
587
|
+
circuit_breaker_reset_seconds=restart_policy.get(
|
|
588
|
+
"circuit_breaker_reset_seconds", 600
|
|
589
|
+
),
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
def _ensure_initialized(self) -> None:
|
|
593
|
+
"""Ensure manager is initialized."""
|
|
594
|
+
if not self._initialized:
|
|
595
|
+
raise RuntimeError(
|
|
596
|
+
"UnifiedLocalOpsManager not initialized. Call initialize() first."
|
|
597
|
+
)
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
__all__ = ["UnifiedLocalOpsManager"]
|
|
@@ -1145,11 +1145,16 @@ class MCPConfigManager:
|
|
|
1145
1145
|
|
|
1146
1146
|
# Check each service for issues
|
|
1147
1147
|
for service_name in self.PIPX_SERVICES:
|
|
1148
|
-
|
|
1148
|
+
# Check if service is enabled in config
|
|
1149
|
+
if not self.should_enable_service(service_name):
|
|
1150
|
+
self.logger.debug(f"Skipping {service_name} (disabled in config)")
|
|
1151
|
+
continue
|
|
1152
|
+
|
|
1153
|
+
self.logger.debug(f"🔍 Checking {service_name} for issues...")
|
|
1149
1154
|
issue_type = self._detect_service_issue(service_name)
|
|
1150
1155
|
if issue_type:
|
|
1151
1156
|
services_to_fix.append((service_name, issue_type))
|
|
1152
|
-
self.logger.
|
|
1157
|
+
self.logger.debug(f" ⚠️ Found issue with {service_name}: {issue_type}")
|
|
1153
1158
|
else:
|
|
1154
1159
|
self.logger.debug(f" ✅ {service_name} is functioning correctly")
|
|
1155
1160
|
|
|
@@ -1492,7 +1497,7 @@ class MCPConfigManager:
|
|
|
1492
1497
|
)
|
|
1493
1498
|
|
|
1494
1499
|
if result.returncode == 0:
|
|
1495
|
-
self.logger.
|
|
1500
|
+
self.logger.debug(f" ✅ Successfully injected {dep}")
|
|
1496
1501
|
# Check if already injected (pipx will complain if package already exists)
|
|
1497
1502
|
elif (
|
|
1498
1503
|
"already satisfied" in result.stderr.lower()
|
|
@@ -1577,7 +1582,7 @@ class MCPConfigManager:
|
|
|
1577
1582
|
)
|
|
1578
1583
|
|
|
1579
1584
|
# Verify the reinstall worked
|
|
1580
|
-
self.logger.
|
|
1585
|
+
self.logger.debug(f" → Verifying {service_name} installation...")
|
|
1581
1586
|
issue = self._detect_service_issue(service_name)
|
|
1582
1587
|
|
|
1583
1588
|
if issue is None:
|
|
@@ -5,7 +5,7 @@ MCP Gateway Core Module
|
|
|
5
5
|
Core interfaces and base classes for the MCP Gateway service.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
from .base import BaseMCPService
|
|
8
|
+
from .base import BaseMCPService
|
|
9
9
|
from .exceptions import (
|
|
10
10
|
MCPCommunicationError,
|
|
11
11
|
MCPConfigurationError,
|
|
@@ -38,7 +38,6 @@ __all__ = [
|
|
|
38
38
|
# Exceptions
|
|
39
39
|
"MCPException",
|
|
40
40
|
"MCPServerError",
|
|
41
|
-
"MCPServiceState",
|
|
42
41
|
"MCPToolNotFoundError",
|
|
43
42
|
"MCPValidationError",
|
|
44
43
|
]
|