claude-mpm 4.13.2__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.
Files changed (250) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_ENGINEER.md +286 -0
  3. claude_mpm/agents/BASE_PM.md +48 -17
  4. claude_mpm/agents/OUTPUT_STYLE.md +329 -11
  5. claude_mpm/agents/PM_INSTRUCTIONS.md +227 -8
  6. claude_mpm/agents/agent_loader.py +17 -5
  7. claude_mpm/agents/frontmatter_validator.py +284 -253
  8. claude_mpm/agents/templates/agentic-coder-optimizer.json +9 -2
  9. claude_mpm/agents/templates/api_qa.json +7 -1
  10. claude_mpm/agents/templates/clerk-ops.json +8 -1
  11. claude_mpm/agents/templates/code_analyzer.json +4 -1
  12. claude_mpm/agents/templates/dart_engineer.json +11 -1
  13. claude_mpm/agents/templates/data_engineer.json +11 -1
  14. claude_mpm/agents/templates/documentation.json +6 -1
  15. claude_mpm/agents/templates/engineer.json +18 -1
  16. claude_mpm/agents/templates/gcp_ops_agent.json +8 -1
  17. claude_mpm/agents/templates/golang_engineer.json +11 -1
  18. claude_mpm/agents/templates/java_engineer.json +12 -2
  19. claude_mpm/agents/templates/local_ops_agent.json +1217 -6
  20. claude_mpm/agents/templates/nextjs_engineer.json +11 -1
  21. claude_mpm/agents/templates/ops.json +8 -1
  22. claude_mpm/agents/templates/php-engineer.json +11 -1
  23. claude_mpm/agents/templates/project_organizer.json +10 -3
  24. claude_mpm/agents/templates/prompt-engineer.json +5 -1
  25. claude_mpm/agents/templates/python_engineer.json +11 -1
  26. claude_mpm/agents/templates/qa.json +7 -1
  27. claude_mpm/agents/templates/react_engineer.json +11 -1
  28. claude_mpm/agents/templates/refactoring_engineer.json +8 -1
  29. claude_mpm/agents/templates/research.json +4 -1
  30. claude_mpm/agents/templates/ruby-engineer.json +11 -1
  31. claude_mpm/agents/templates/rust_engineer.json +11 -1
  32. claude_mpm/agents/templates/security.json +6 -1
  33. claude_mpm/agents/templates/svelte-engineer.json +225 -0
  34. claude_mpm/agents/templates/ticketing.json +6 -1
  35. claude_mpm/agents/templates/typescript_engineer.json +11 -1
  36. claude_mpm/agents/templates/vercel_ops_agent.json +8 -1
  37. claude_mpm/agents/templates/version_control.json +8 -1
  38. claude_mpm/agents/templates/web_qa.json +7 -1
  39. claude_mpm/agents/templates/web_ui.json +11 -1
  40. claude_mpm/cli/__init__.py +34 -706
  41. claude_mpm/cli/commands/agent_manager.py +25 -12
  42. claude_mpm/cli/commands/agent_state_manager.py +186 -0
  43. claude_mpm/cli/commands/agents.py +204 -148
  44. claude_mpm/cli/commands/aggregate.py +7 -3
  45. claude_mpm/cli/commands/analyze.py +9 -4
  46. claude_mpm/cli/commands/analyze_code.py +7 -2
  47. claude_mpm/cli/commands/auto_configure.py +7 -9
  48. claude_mpm/cli/commands/config.py +47 -13
  49. claude_mpm/cli/commands/configure.py +294 -1788
  50. claude_mpm/cli/commands/configure_agent_display.py +261 -0
  51. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  52. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  53. claude_mpm/cli/commands/configure_models.py +18 -0
  54. claude_mpm/cli/commands/configure_navigation.py +167 -0
  55. claude_mpm/cli/commands/configure_paths.py +104 -0
  56. claude_mpm/cli/commands/configure_persistence.py +254 -0
  57. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  58. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  59. claude_mpm/cli/commands/configure_validators.py +73 -0
  60. claude_mpm/cli/commands/local_deploy.py +537 -0
  61. claude_mpm/cli/commands/memory.py +54 -20
  62. claude_mpm/cli/commands/mpm_init.py +39 -25
  63. claude_mpm/cli/commands/mpm_init_handler.py +8 -3
  64. claude_mpm/cli/executor.py +202 -0
  65. claude_mpm/cli/helpers.py +105 -0
  66. claude_mpm/cli/interactive/__init__.py +3 -0
  67. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  68. claude_mpm/cli/parsers/__init__.py +7 -1
  69. claude_mpm/cli/parsers/base_parser.py +98 -3
  70. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  71. claude_mpm/cli/shared/output_formatters.py +28 -19
  72. claude_mpm/cli/startup.py +481 -0
  73. claude_mpm/cli/utils.py +52 -1
  74. claude_mpm/commands/mpm-help.md +3 -0
  75. claude_mpm/commands/mpm-version.md +113 -0
  76. claude_mpm/commands/mpm.md +1 -0
  77. claude_mpm/config/agent_config.py +2 -2
  78. claude_mpm/config/model_config.py +428 -0
  79. claude_mpm/core/base_service.py +13 -12
  80. claude_mpm/core/enums.py +452 -0
  81. claude_mpm/core/factories.py +1 -1
  82. claude_mpm/core/instruction_reinforcement_hook.py +2 -1
  83. claude_mpm/core/interactive_session.py +9 -3
  84. claude_mpm/core/logging_config.py +6 -2
  85. claude_mpm/core/oneshot_session.py +8 -4
  86. claude_mpm/core/optimized_agent_loader.py +3 -3
  87. claude_mpm/core/output_style_manager.py +12 -192
  88. claude_mpm/core/service_registry.py +5 -1
  89. claude_mpm/core/types.py +2 -9
  90. claude_mpm/core/typing_utils.py +7 -6
  91. claude_mpm/dashboard/static/js/dashboard.js +0 -14
  92. claude_mpm/dashboard/templates/index.html +3 -41
  93. claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
  94. claude_mpm/hooks/instruction_reinforcement.py +7 -2
  95. claude_mpm/models/resume_log.py +340 -0
  96. claude_mpm/services/agents/auto_config_manager.py +10 -11
  97. claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
  98. claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
  99. claude_mpm/services/agents/deployment/agent_validator.py +17 -1
  100. claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
  101. claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
  102. claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
  103. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
  104. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
  105. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
  106. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
  107. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
  108. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
  109. claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
  110. claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
  111. claude_mpm/services/agents/local_template_manager.py +1 -1
  112. claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
  113. claude_mpm/services/agents/registry/modification_tracker.py +5 -2
  114. claude_mpm/services/command_handler_service.py +11 -5
  115. claude_mpm/services/core/interfaces/__init__.py +74 -2
  116. claude_mpm/services/core/interfaces/health.py +172 -0
  117. claude_mpm/services/core/interfaces/model.py +281 -0
  118. claude_mpm/services/core/interfaces/process.py +372 -0
  119. claude_mpm/services/core/interfaces/restart.py +307 -0
  120. claude_mpm/services/core/interfaces/stability.py +260 -0
  121. claude_mpm/services/core/models/__init__.py +33 -0
  122. claude_mpm/services/core/models/agent_config.py +12 -28
  123. claude_mpm/services/core/models/health.py +162 -0
  124. claude_mpm/services/core/models/process.py +235 -0
  125. claude_mpm/services/core/models/restart.py +302 -0
  126. claude_mpm/services/core/models/stability.py +264 -0
  127. claude_mpm/services/core/path_resolver.py +23 -7
  128. claude_mpm/services/diagnostics/__init__.py +2 -2
  129. claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
  130. claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
  131. claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
  132. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
  133. claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
  134. claude_mpm/services/diagnostics/checks/installation_check.py +30 -29
  135. claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
  136. claude_mpm/services/diagnostics/checks/mcp_check.py +50 -36
  137. claude_mpm/services/diagnostics/checks/mcp_services_check.py +36 -31
  138. claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
  139. claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
  140. claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
  141. claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
  142. claude_mpm/services/diagnostics/models.py +19 -24
  143. claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
  144. claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
  145. claude_mpm/services/infrastructure/monitoring/base.py +5 -13
  146. claude_mpm/services/infrastructure/monitoring/network.py +7 -6
  147. claude_mpm/services/infrastructure/monitoring/process.py +13 -12
  148. claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
  149. claude_mpm/services/infrastructure/monitoring/service.py +16 -15
  150. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  151. claude_mpm/services/local_ops/__init__.py +163 -0
  152. claude_mpm/services/local_ops/crash_detector.py +257 -0
  153. claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
  154. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  155. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  156. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  157. claude_mpm/services/local_ops/health_manager.py +430 -0
  158. claude_mpm/services/local_ops/log_monitor.py +396 -0
  159. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  160. claude_mpm/services/local_ops/process_manager.py +595 -0
  161. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  162. claude_mpm/services/local_ops/restart_manager.py +401 -0
  163. claude_mpm/services/local_ops/restart_policy.py +387 -0
  164. claude_mpm/services/local_ops/state_manager.py +372 -0
  165. claude_mpm/services/local_ops/unified_manager.py +600 -0
  166. claude_mpm/services/mcp_config_manager.py +9 -4
  167. claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
  168. claude_mpm/services/mcp_gateway/core/base.py +18 -31
  169. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +71 -24
  170. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +30 -28
  171. claude_mpm/services/memory_hook_service.py +4 -1
  172. claude_mpm/services/model/__init__.py +147 -0
  173. claude_mpm/services/model/base_provider.py +365 -0
  174. claude_mpm/services/model/claude_provider.py +412 -0
  175. claude_mpm/services/model/model_router.py +453 -0
  176. claude_mpm/services/model/ollama_provider.py +415 -0
  177. claude_mpm/services/monitor/daemon_manager.py +3 -2
  178. claude_mpm/services/monitor/handlers/dashboard.py +2 -1
  179. claude_mpm/services/monitor/handlers/hooks.py +2 -1
  180. claude_mpm/services/monitor/management/lifecycle.py +3 -2
  181. claude_mpm/services/monitor/server.py +2 -1
  182. claude_mpm/services/session_management_service.py +3 -2
  183. claude_mpm/services/session_manager.py +205 -1
  184. claude_mpm/services/shared/async_service_base.py +16 -27
  185. claude_mpm/services/shared/lifecycle_service_base.py +1 -14
  186. claude_mpm/services/socketio/handlers/__init__.py +5 -2
  187. claude_mpm/services/socketio/handlers/hook.py +13 -2
  188. claude_mpm/services/socketio/handlers/registry.py +4 -2
  189. claude_mpm/services/socketio/server/main.py +10 -8
  190. claude_mpm/services/subprocess_launcher_service.py +14 -5
  191. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +8 -7
  192. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
  193. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
  194. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +7 -6
  195. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
  196. claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
  197. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
  198. claude_mpm/services/unified/deployment_strategies/local.py +6 -5
  199. claude_mpm/services/unified/deployment_strategies/utils.py +6 -5
  200. claude_mpm/services/unified/deployment_strategies/vercel.py +7 -6
  201. claude_mpm/services/unified/interfaces.py +3 -1
  202. claude_mpm/services/unified/unified_analyzer.py +14 -10
  203. claude_mpm/services/unified/unified_config.py +2 -1
  204. claude_mpm/services/unified/unified_deployment.py +9 -4
  205. claude_mpm/services/version_service.py +104 -1
  206. claude_mpm/skills/__init__.py +21 -0
  207. claude_mpm/skills/bundled/__init__.py +6 -0
  208. claude_mpm/skills/bundled/api-documentation.md +393 -0
  209. claude_mpm/skills/bundled/async-testing.md +571 -0
  210. claude_mpm/skills/bundled/code-review.md +143 -0
  211. claude_mpm/skills/bundled/database-migration.md +199 -0
  212. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  213. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  214. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  215. claude_mpm/skills/bundled/git-workflow.md +414 -0
  216. claude_mpm/skills/bundled/imagemagick.md +204 -0
  217. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  218. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  219. claude_mpm/skills/bundled/pdf.md +141 -0
  220. claude_mpm/skills/bundled/performance-profiling.md +567 -0
  221. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  222. claude_mpm/skills/bundled/security-scanning.md +327 -0
  223. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  224. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  225. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  226. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  227. claude_mpm/skills/bundled/xlsx.md +157 -0
  228. claude_mpm/skills/registry.py +286 -0
  229. claude_mpm/skills/skill_manager.py +310 -0
  230. claude_mpm/tools/code_tree_analyzer.py +177 -141
  231. claude_mpm/tools/code_tree_events.py +4 -2
  232. claude_mpm/utils/agent_dependency_loader.py +2 -2
  233. {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/METADATA +117 -8
  234. {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/RECORD +238 -174
  235. claude_mpm/dashboard/static/css/code-tree.css +0 -1639
  236. claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
  237. claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
  238. claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
  239. claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
  240. claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
  241. claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
  242. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
  243. claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
  244. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
  245. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
  246. claude_mpm/services/project/analyzer_refactored.py +0 -450
  247. {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/WHEEL +0 -0
  248. {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/entry_points.txt +0 -0
  249. {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/licenses/LICENSE +0 -0
  250. {claude_mpm-4.13.2.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
- self.logger.info(f"🔍 Checking {service_name} for issues...")
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.info(f" ⚠️ Found issue with {service_name}: {issue_type}")
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.info(f" ✅ Successfully injected {dep}")
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.info(f" → Verifying {service_name} installation...")
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, MCPServiceState
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
  ]