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,264 @@
1
+ """
2
+ Stability Monitoring Data Models for Claude MPM Framework
3
+ ===========================================================
4
+
5
+ WHY: This module defines data structures for stability monitoring operations,
6
+ including memory leak detection, log pattern matching, and resource usage tracking.
7
+
8
+ DESIGN DECISION: Uses dataclasses for immutability and type safety. Provides
9
+ clear data structures for proactive monitoring and crash prevention.
10
+
11
+ ARCHITECTURE:
12
+ - MemoryTrend: Memory usage trend analysis with leak detection
13
+ - LogPatternMatch: Log pattern match with severity and context
14
+ - ResourceUsage: Comprehensive resource usage snapshot
15
+ """
16
+
17
+ from dataclasses import asdict, dataclass, field
18
+ from datetime import datetime
19
+ from typing import Any, Dict, List
20
+
21
+
22
+ @dataclass
23
+ class MemoryTrend:
24
+ """
25
+ Memory usage trend analysis result.
26
+
27
+ WHY: Provides structured data for memory leak detection, including
28
+ historical measurements, slope calculation, and leak detection status.
29
+
30
+ Attributes:
31
+ deployment_id: Unique deployment identifier
32
+ timestamps: List of measurement timestamps
33
+ memory_mb: List of memory measurements in megabytes
34
+ slope_mb_per_minute: Calculated memory growth rate (MB/minute)
35
+ is_leaking: Whether a memory leak was detected
36
+ window_size: Number of measurements in the analysis window
37
+ threshold_mb_per_minute: Leak detection threshold used
38
+ """
39
+
40
+ deployment_id: str
41
+ timestamps: List[datetime] = field(default_factory=list)
42
+ memory_mb: List[float] = field(default_factory=list)
43
+ slope_mb_per_minute: float = 0.0
44
+ is_leaking: bool = False
45
+ window_size: int = 0
46
+ threshold_mb_per_minute: float = 10.0
47
+
48
+ def to_dict(self) -> Dict[str, Any]:
49
+ """
50
+ Convert to dictionary for JSON serialization.
51
+
52
+ Returns:
53
+ Dictionary representation with datetimes converted to ISO format
54
+ """
55
+ data = asdict(self)
56
+ data["timestamps"] = [ts.isoformat() for ts in self.timestamps]
57
+ return data
58
+
59
+ @classmethod
60
+ def from_dict(cls, data: Dict[str, Any]) -> "MemoryTrend":
61
+ """
62
+ Create MemoryTrend from dictionary.
63
+
64
+ Args:
65
+ data: Dictionary from JSON deserialization
66
+
67
+ Returns:
68
+ MemoryTrend instance
69
+ """
70
+ # Convert ISO strings to datetime
71
+ if isinstance(data.get("timestamps"), list):
72
+ data["timestamps"] = [
73
+ datetime.fromisoformat(ts) if isinstance(ts, str) else ts
74
+ for ts in data["timestamps"]
75
+ ]
76
+
77
+ return cls(**data)
78
+
79
+ @property
80
+ def latest_memory_mb(self) -> float:
81
+ """Get the most recent memory measurement."""
82
+ return self.memory_mb[-1] if self.memory_mb else 0.0
83
+
84
+ @property
85
+ def oldest_memory_mb(self) -> float:
86
+ """Get the oldest memory measurement in the window."""
87
+ return self.memory_mb[0] if self.memory_mb else 0.0
88
+
89
+ @property
90
+ def time_span_minutes(self) -> float:
91
+ """Get the time span covered by the measurements in minutes."""
92
+ if len(self.timestamps) < 2:
93
+ return 0.0
94
+ delta = self.timestamps[-1] - self.timestamps[0]
95
+ return delta.total_seconds() / 60.0
96
+
97
+
98
+ @dataclass
99
+ class LogPatternMatch:
100
+ """
101
+ Result of a log pattern match.
102
+
103
+ WHY: Contains all information about a detected error pattern in logs,
104
+ enabling analysis, alerting, and debugging of issues before they cause crashes.
105
+
106
+ Attributes:
107
+ deployment_id: Unique deployment identifier
108
+ pattern: Regex pattern that matched
109
+ line: The log line that matched
110
+ timestamp: When the match was detected
111
+ severity: Error severity level (ERROR, CRITICAL, WARNING)
112
+ line_number: Line number in log file (if available)
113
+ context: Additional context lines (before/after)
114
+ """
115
+
116
+ deployment_id: str
117
+ pattern: str
118
+ line: str
119
+ timestamp: datetime = field(default_factory=datetime.now)
120
+ severity: str = "ERROR"
121
+ line_number: int = 0
122
+ context: List[str] = field(default_factory=list)
123
+
124
+ def to_dict(self) -> Dict[str, Any]:
125
+ """
126
+ Convert to dictionary for JSON serialization.
127
+
128
+ Returns:
129
+ Dictionary representation with datetime converted to ISO format
130
+ """
131
+ data = asdict(self)
132
+ data["timestamp"] = self.timestamp.isoformat()
133
+ return data
134
+
135
+ @classmethod
136
+ def from_dict(cls, data: Dict[str, Any]) -> "LogPatternMatch":
137
+ """
138
+ Create LogPatternMatch from dictionary.
139
+
140
+ Args:
141
+ data: Dictionary from JSON deserialization
142
+
143
+ Returns:
144
+ LogPatternMatch instance
145
+ """
146
+ # Convert ISO string to datetime
147
+ if isinstance(data.get("timestamp"), str):
148
+ data["timestamp"] = datetime.fromisoformat(data["timestamp"])
149
+
150
+ return cls(**data)
151
+
152
+ @property
153
+ def is_critical(self) -> bool:
154
+ """Check if this match represents a critical error."""
155
+ return self.severity == "CRITICAL"
156
+
157
+
158
+ @dataclass
159
+ class ResourceUsage:
160
+ """
161
+ Comprehensive resource usage snapshot.
162
+
163
+ WHY: Provides detailed resource consumption metrics across multiple
164
+ resource types to enable preemptive action before exhaustion.
165
+
166
+ Attributes:
167
+ deployment_id: Unique deployment identifier
168
+ file_descriptors: Current file descriptor count
169
+ max_file_descriptors: Maximum file descriptors allowed (ulimit -n)
170
+ threads: Current thread count
171
+ connections: Current network connection count
172
+ disk_free_mb: Free disk space in working directory (MB)
173
+ is_critical: Whether any resource exceeds 80% threshold
174
+ timestamp: When the measurement was taken
175
+ details: Additional resource-specific details
176
+ """
177
+
178
+ deployment_id: str
179
+ file_descriptors: int = 0
180
+ max_file_descriptors: int = 0
181
+ threads: int = 0
182
+ connections: int = 0
183
+ disk_free_mb: float = 0.0
184
+ is_critical: bool = False
185
+ timestamp: datetime = field(default_factory=datetime.now)
186
+ details: Dict[str, Any] = field(default_factory=dict)
187
+
188
+ def to_dict(self) -> Dict[str, Any]:
189
+ """
190
+ Convert to dictionary for JSON serialization.
191
+
192
+ Returns:
193
+ Dictionary representation with datetime converted to ISO format
194
+ """
195
+ data = asdict(self)
196
+ data["timestamp"] = self.timestamp.isoformat()
197
+ return data
198
+
199
+ @classmethod
200
+ def from_dict(cls, data: Dict[str, Any]) -> "ResourceUsage":
201
+ """
202
+ Create ResourceUsage from dictionary.
203
+
204
+ Args:
205
+ data: Dictionary from JSON deserialization
206
+
207
+ Returns:
208
+ ResourceUsage instance
209
+ """
210
+ # Convert ISO string to datetime
211
+ if isinstance(data.get("timestamp"), str):
212
+ data["timestamp"] = datetime.fromisoformat(data["timestamp"])
213
+
214
+ return cls(**data)
215
+
216
+ @property
217
+ def fd_usage_percent(self) -> float:
218
+ """Calculate file descriptor usage percentage."""
219
+ if self.max_file_descriptors == 0:
220
+ return 0.0
221
+ return (self.file_descriptors / self.max_file_descriptors) * 100.0
222
+
223
+ @property
224
+ def is_fd_critical(self) -> bool:
225
+ """Check if file descriptor usage is critical (>80%)."""
226
+ return self.fd_usage_percent >= 80.0 # >= instead of > for 80% exactly
227
+
228
+ def get_critical_resources(self) -> List[str]:
229
+ """
230
+ Get list of resources at critical levels.
231
+
232
+ Returns:
233
+ List of resource names exceeding 80% threshold
234
+ """
235
+ critical = []
236
+
237
+ if self.is_fd_critical:
238
+ critical.append(
239
+ f"file_descriptors ({self.file_descriptors}/{self.max_file_descriptors})"
240
+ )
241
+
242
+ # Check thread count (threshold from details if available)
243
+ thread_threshold = self.details.get("thread_threshold", 1000)
244
+ if self.threads > thread_threshold * 0.8:
245
+ critical.append(f"threads ({self.threads})")
246
+
247
+ # Check connection count (threshold from details if available)
248
+ connection_threshold = self.details.get("connection_threshold", 500)
249
+ if self.connections > connection_threshold * 0.8:
250
+ critical.append(f"connections ({self.connections})")
251
+
252
+ # Check disk space (threshold from details if available)
253
+ disk_threshold_mb = self.details.get("disk_threshold_mb", 100)
254
+ if self.disk_free_mb < disk_threshold_mb:
255
+ critical.append(f"disk_space ({self.disk_free_mb:.1f}MB free)")
256
+
257
+ return critical
258
+
259
+
260
+ __all__ = [
261
+ "LogPatternMatch",
262
+ "MemoryTrend",
263
+ "ResourceUsage",
264
+ ]
@@ -13,6 +13,7 @@ that was previously embedded in FrameworkLoader. It manages:
13
13
  The service consolidates path management logic while maintaining backward compatibility.
14
14
  """
15
15
 
16
+ import os
16
17
  import subprocess
17
18
  from enum import Enum
18
19
  from pathlib import Path
@@ -74,10 +75,25 @@ class PathResolver(IPathResolver):
74
75
  return path_obj
75
76
 
76
77
  if base_dir is None:
77
- base_dir = Path.cwd()
78
+ base_dir = self._get_working_dir()
78
79
 
79
80
  return (base_dir / path_obj).resolve()
80
81
 
82
+ def _get_working_dir(self) -> Path:
83
+ """Get working directory respecting CLAUDE_MPM_USER_PWD.
84
+
85
+ When Claude MPM runs from a global installation, CLAUDE_MPM_USER_PWD
86
+ contains the user's actual working directory. This ensures project-local
87
+ paths are resolved correctly.
88
+
89
+ Returns:
90
+ Path: The user's working directory
91
+ """
92
+ user_pwd = os.environ.get("CLAUDE_MPM_USER_PWD")
93
+ if user_pwd:
94
+ return Path(user_pwd)
95
+ return Path.cwd()
96
+
81
97
  def validate_path(self, path: Path, must_exist: bool = False) -> bool:
82
98
  """
83
99
  Validate a path for security and existence.
@@ -129,7 +145,7 @@ class PathResolver(IPathResolver):
129
145
  Project root path or None if not found
130
146
  """
131
147
  if start_path is None:
132
- start_path = Path.cwd()
148
+ start_path = self._get_working_dir()
133
149
 
134
150
  start_path = start_path.resolve()
135
151
 
@@ -265,7 +281,7 @@ class PathResolver(IPathResolver):
265
281
 
266
282
  if agents_dir and agents_dir.exists():
267
283
  discovered_agents_dir = agents_dir
268
- self.logger.info(f"Using custom agents directory: {discovered_agents_dir}")
284
+ self.logger.debug(f"Using custom agents directory: {discovered_agents_dir}")
269
285
  elif framework_path and framework_path != Path("__PACKAGED__"):
270
286
  # Prioritize templates directory over main agents directory
271
287
  templates_dir = (
@@ -299,7 +315,7 @@ class PathResolver(IPathResolver):
299
315
  paths = {"project": None, "user": None, "system": None}
300
316
 
301
317
  # Project-specific instructions
302
- project_path = Path.cwd() / ".claude-mpm" / "INSTRUCTIONS.md"
318
+ project_path = self._get_working_dir() / ".claude-mpm" / "INSTRUCTIONS.md"
303
319
  if project_path.exists():
304
320
  paths["project"] = project_path
305
321
 
@@ -423,11 +439,11 @@ class PathResolver(IPathResolver):
423
439
  """Check common locations for claude-mpm."""
424
440
  candidates = [
425
441
  # Current directory (if we're already in claude-mpm)
426
- Path.cwd(),
442
+ self._get_working_dir(),
427
443
  # Development location
428
444
  Path.home() / "Projects" / "claude-mpm",
429
445
  # Current directory subdirectory
430
- Path.cwd() / "claude-mpm",
446
+ self._get_working_dir() / "claude-mpm",
431
447
  ]
432
448
 
433
449
  for candidate in candidates:
@@ -487,7 +503,7 @@ class PathResolver(IPathResolver):
487
503
  pass
488
504
 
489
505
  # Check if we're in development
490
- if (Path.cwd() / "pyproject.toml").exists():
506
+ if (self._get_working_dir() / "pyproject.toml").exists():
491
507
  return DeploymentContext.DEVELOPMENT
492
508
 
493
509
  return DeploymentContext.UNKNOWN
@@ -13,6 +13,6 @@ DESIGN DECISIONS:
13
13
 
14
14
  from .diagnostic_runner import DiagnosticRunner
15
15
  from .doctor_reporter import DoctorReporter
16
- from .models import DiagnosticResult, DiagnosticStatus
16
+ from .models import DiagnosticResult
17
17
 
18
- __all__ = ["DiagnosticResult", "DiagnosticRunner", "DiagnosticStatus", "DoctorReporter"]
18
+ __all__ = ["DiagnosticResult", "DiagnosticRunner", "DoctorReporter"]
@@ -6,7 +6,8 @@ WHY: Verify that agents are properly deployed, up-to-date, and functioning corre
6
6
 
7
7
  from pathlib import Path
8
8
 
9
- from ..models import DiagnosticResult, DiagnosticStatus
9
+ from ....core.enums import OperationResult, ValidationSeverity
10
+ from ..models import DiagnosticResult
10
11
  from .base_check import BaseDiagnosticCheck
11
12
 
12
13
 
@@ -64,29 +65,29 @@ class AgentCheck(BaseDiagnosticCheck):
64
65
  available_count = details["available_count"]
65
66
 
66
67
  if deployed_count == 0:
67
- status = DiagnosticStatus.ERROR
68
+ status = ValidationSeverity.ERROR
68
69
  message = f"No agents deployed (0/{available_count} available)"
69
70
  fix_command = "claude-mpm agents deploy"
70
71
  fix_description = "Deploy all available agents"
71
72
  elif deployed_count < available_count:
72
- status = DiagnosticStatus.WARNING
73
+ status = ValidationSeverity.WARNING
73
74
  message = f"{deployed_count}/{available_count} agents deployed"
74
75
  fix_command = "claude-mpm agents deploy"
75
76
  fix_description = (
76
77
  f"Deploy remaining {available_count - deployed_count} agents"
77
78
  )
78
- elif any(r.status == DiagnosticStatus.ERROR for r in sub_results):
79
- status = DiagnosticStatus.ERROR
79
+ elif any(r.status == ValidationSeverity.ERROR for r in sub_results):
80
+ status = ValidationSeverity.ERROR
80
81
  message = "Agents have critical issues"
81
82
  fix_command = None
82
83
  fix_description = None
83
- elif any(r.status == DiagnosticStatus.WARNING for r in sub_results):
84
- status = DiagnosticStatus.WARNING
84
+ elif any(r.status == ValidationSeverity.WARNING for r in sub_results):
85
+ status = ValidationSeverity.WARNING
85
86
  message = "Agents have minor issues"
86
87
  fix_command = None
87
88
  fix_description = None
88
89
  else:
89
- status = DiagnosticStatus.OK
90
+ status = OperationResult.SUCCESS
90
91
  message = f"All {deployed_count} agents properly deployed"
91
92
  fix_command = None
92
93
  fix_description = None
@@ -104,7 +105,7 @@ class AgentCheck(BaseDiagnosticCheck):
104
105
  except Exception as e:
105
106
  return DiagnosticResult(
106
107
  category=self.category,
107
- status=DiagnosticStatus.ERROR,
108
+ status=ValidationSeverity.ERROR,
108
109
  message=f"Agent check failed: {e!s}",
109
110
  details={"error": str(e)},
110
111
  )
@@ -127,7 +128,7 @@ class AgentCheck(BaseDiagnosticCheck):
127
128
  # Neither exists, default to user directory for error message
128
129
  return DiagnosticResult(
129
130
  category="Deployed Agents",
130
- status=DiagnosticStatus.ERROR,
131
+ status=ValidationSeverity.ERROR,
131
132
  message="No agents directory found (checked project and user)",
132
133
  details={
133
134
  "project_path": str(project_agents_dir),
@@ -144,7 +145,7 @@ class AgentCheck(BaseDiagnosticCheck):
144
145
  if not agent_files:
145
146
  return DiagnosticResult(
146
147
  category="Deployed Agents",
147
- status=DiagnosticStatus.ERROR,
148
+ status=ValidationSeverity.ERROR,
148
149
  message=f"No agents deployed in {location} directory",
149
150
  details={"path": str(agents_dir), "location": location, "count": 0},
150
151
  fix_command="claude-mpm agents deploy",
@@ -159,7 +160,7 @@ class AgentCheck(BaseDiagnosticCheck):
159
160
  if missing_core:
160
161
  return DiagnosticResult(
161
162
  category="Deployed Agents",
162
- status=DiagnosticStatus.WARNING,
163
+ status=ValidationSeverity.WARNING,
163
164
  message=f"Missing core agents in {location}: {', '.join(missing_core)}",
164
165
  details={
165
166
  "path": str(agents_dir),
@@ -174,7 +175,7 @@ class AgentCheck(BaseDiagnosticCheck):
174
175
 
175
176
  return DiagnosticResult(
176
177
  category="Deployed Agents",
177
- status=DiagnosticStatus.OK,
178
+ status=OperationResult.SUCCESS,
178
179
  message=f"{len(agent_files)} agents deployed ({location} level)",
179
180
  details={
180
181
  "path": str(agents_dir),
@@ -205,7 +206,7 @@ class AgentCheck(BaseDiagnosticCheck):
205
206
  else:
206
207
  return DiagnosticResult(
207
208
  category="Agent Versions",
208
- status=DiagnosticStatus.SKIPPED,
209
+ status=OperationResult.SKIPPED,
209
210
  message="No agents to check",
210
211
  details={},
211
212
  )
@@ -224,7 +225,7 @@ class AgentCheck(BaseDiagnosticCheck):
224
225
  if outdated:
225
226
  return DiagnosticResult(
226
227
  category="Agent Versions",
227
- status=DiagnosticStatus.WARNING,
228
+ status=ValidationSeverity.WARNING,
228
229
  message=f"{len(outdated)} agent(s) outdated",
229
230
  details={"outdated": outdated, "checked": checked},
230
231
  fix_command="claude-mpm agents update",
@@ -234,14 +235,14 @@ class AgentCheck(BaseDiagnosticCheck):
234
235
  if checked == 0:
235
236
  return DiagnosticResult(
236
237
  category="Agent Versions",
237
- status=DiagnosticStatus.WARNING,
238
+ status=ValidationSeverity.WARNING,
238
239
  message="No agents to check",
239
240
  details={"checked": 0},
240
241
  )
241
242
 
242
243
  return DiagnosticResult(
243
244
  category="Agent Versions",
244
- status=DiagnosticStatus.OK,
245
+ status=OperationResult.SUCCESS,
245
246
  message=f"All {checked} agents up-to-date",
246
247
  details={"checked": checked},
247
248
  )
@@ -249,7 +250,7 @@ class AgentCheck(BaseDiagnosticCheck):
249
250
  except Exception as e:
250
251
  return DiagnosticResult(
251
252
  category="Agent Versions",
252
- status=DiagnosticStatus.WARNING,
253
+ status=ValidationSeverity.WARNING,
253
254
  message=f"Could not check versions: {e!s}",
254
255
  details={"error": str(e)},
255
256
  )
@@ -273,7 +274,7 @@ class AgentCheck(BaseDiagnosticCheck):
273
274
  else:
274
275
  return DiagnosticResult(
275
276
  category="Agent Validation",
276
- status=DiagnosticStatus.SKIPPED,
277
+ status=OperationResult.SKIPPED,
277
278
  message="No agents to validate",
278
279
  details={},
279
280
  )
@@ -301,14 +302,14 @@ class AgentCheck(BaseDiagnosticCheck):
301
302
  if invalid:
302
303
  return DiagnosticResult(
303
304
  category="Agent Validation",
304
- status=DiagnosticStatus.WARNING,
305
+ status=ValidationSeverity.WARNING,
305
306
  message=f"{len(invalid)} validation issue(s)",
306
307
  details={"issues": invalid, "validated": validated},
307
308
  )
308
309
 
309
310
  return DiagnosticResult(
310
311
  category="Agent Validation",
311
- status=DiagnosticStatus.OK,
312
+ status=OperationResult.SUCCESS,
312
313
  message=f"All {validated} agents valid",
313
314
  details={"validated": validated},
314
315
  )
@@ -316,7 +317,7 @@ class AgentCheck(BaseDiagnosticCheck):
316
317
  except Exception as e:
317
318
  return DiagnosticResult(
318
319
  category="Agent Validation",
319
- status=DiagnosticStatus.WARNING,
320
+ status=ValidationSeverity.WARNING,
320
321
  message=f"Validation failed: {e!s}",
321
322
  details={"error": str(e)},
322
323
  )
@@ -358,14 +359,14 @@ class AgentCheck(BaseDiagnosticCheck):
358
359
  if issues:
359
360
  return DiagnosticResult(
360
361
  category="Common Issues",
361
- status=DiagnosticStatus.WARNING,
362
+ status=ValidationSeverity.WARNING,
362
363
  message=f"{len(issues)} issue(s) found",
363
364
  details={"issues": issues},
364
365
  )
365
366
 
366
367
  return DiagnosticResult(
367
368
  category="Common Issues",
368
- status=DiagnosticStatus.OK,
369
+ status=OperationResult.SUCCESS,
369
370
  message="No common issues detected",
370
371
  details={},
371
372
  )