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.
Files changed (308) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +118 -0
  3. claude_mpm/agents/BASE_ENGINEER.md +286 -0
  4. claude_mpm/agents/BASE_PM.md +106 -1
  5. claude_mpm/agents/OUTPUT_STYLE.md +329 -11
  6. claude_mpm/agents/PM_INSTRUCTIONS.md +397 -459
  7. claude_mpm/agents/agent_loader.py +17 -5
  8. claude_mpm/agents/frontmatter_validator.py +284 -253
  9. claude_mpm/agents/templates/README.md +465 -0
  10. claude_mpm/agents/templates/agent-manager.json +4 -1
  11. claude_mpm/agents/templates/agentic-coder-optimizer.json +13 -3
  12. claude_mpm/agents/templates/api_qa.json +11 -2
  13. claude_mpm/agents/templates/circuit_breakers.md +638 -0
  14. claude_mpm/agents/templates/clerk-ops.json +12 -2
  15. claude_mpm/agents/templates/code_analyzer.json +8 -2
  16. claude_mpm/agents/templates/content-agent.json +358 -0
  17. claude_mpm/agents/templates/dart_engineer.json +15 -2
  18. claude_mpm/agents/templates/data_engineer.json +15 -2
  19. claude_mpm/agents/templates/documentation.json +10 -2
  20. claude_mpm/agents/templates/engineer.json +21 -1
  21. claude_mpm/agents/templates/gcp_ops_agent.json +12 -2
  22. claude_mpm/agents/templates/git_file_tracking.md +584 -0
  23. claude_mpm/agents/templates/golang_engineer.json +270 -0
  24. claude_mpm/agents/templates/imagemagick.json +4 -1
  25. claude_mpm/agents/templates/java_engineer.json +346 -0
  26. claude_mpm/agents/templates/local_ops_agent.json +1227 -6
  27. claude_mpm/agents/templates/memory_manager.json +4 -1
  28. claude_mpm/agents/templates/nextjs_engineer.json +141 -133
  29. claude_mpm/agents/templates/ops.json +12 -2
  30. claude_mpm/agents/templates/php-engineer.json +270 -174
  31. claude_mpm/agents/templates/pm_examples.md +474 -0
  32. claude_mpm/agents/templates/pm_red_flags.md +240 -0
  33. claude_mpm/agents/templates/product_owner.json +338 -0
  34. claude_mpm/agents/templates/project_organizer.json +14 -4
  35. claude_mpm/agents/templates/prompt-engineer.json +13 -2
  36. claude_mpm/agents/templates/python_engineer.json +174 -81
  37. claude_mpm/agents/templates/qa.json +11 -2
  38. claude_mpm/agents/templates/react_engineer.json +16 -3
  39. claude_mpm/agents/templates/refactoring_engineer.json +12 -2
  40. claude_mpm/agents/templates/research.json +34 -21
  41. claude_mpm/agents/templates/response_format.md +583 -0
  42. claude_mpm/agents/templates/ruby-engineer.json +129 -192
  43. claude_mpm/agents/templates/rust_engineer.json +270 -0
  44. claude_mpm/agents/templates/security.json +10 -2
  45. claude_mpm/agents/templates/svelte-engineer.json +225 -0
  46. claude_mpm/agents/templates/ticketing.json +10 -2
  47. claude_mpm/agents/templates/typescript_engineer.json +116 -125
  48. claude_mpm/agents/templates/validation_templates.md +312 -0
  49. claude_mpm/agents/templates/vercel_ops_agent.json +12 -2
  50. claude_mpm/agents/templates/version_control.json +12 -2
  51. claude_mpm/agents/templates/web_qa.json +11 -2
  52. claude_mpm/agents/templates/web_ui.json +15 -2
  53. claude_mpm/cli/__init__.py +34 -614
  54. claude_mpm/cli/commands/agent_manager.py +25 -12
  55. claude_mpm/cli/commands/agent_state_manager.py +186 -0
  56. claude_mpm/cli/commands/agents.py +235 -148
  57. claude_mpm/cli/commands/agents_detect.py +380 -0
  58. claude_mpm/cli/commands/agents_recommend.py +309 -0
  59. claude_mpm/cli/commands/aggregate.py +7 -3
  60. claude_mpm/cli/commands/analyze.py +9 -4
  61. claude_mpm/cli/commands/analyze_code.py +7 -2
  62. claude_mpm/cli/commands/auto_configure.py +570 -0
  63. claude_mpm/cli/commands/config.py +47 -13
  64. claude_mpm/cli/commands/configure.py +419 -1571
  65. claude_mpm/cli/commands/configure_agent_display.py +261 -0
  66. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  67. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  68. claude_mpm/cli/commands/configure_models.py +18 -0
  69. claude_mpm/cli/commands/configure_navigation.py +167 -0
  70. claude_mpm/cli/commands/configure_paths.py +104 -0
  71. claude_mpm/cli/commands/configure_persistence.py +254 -0
  72. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  73. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  74. claude_mpm/cli/commands/configure_validators.py +73 -0
  75. claude_mpm/cli/commands/local_deploy.py +537 -0
  76. claude_mpm/cli/commands/memory.py +54 -20
  77. claude_mpm/cli/commands/mpm_init.py +585 -196
  78. claude_mpm/cli/commands/mpm_init_handler.py +37 -3
  79. claude_mpm/cli/commands/search.py +170 -4
  80. claude_mpm/cli/commands/upgrade.py +152 -0
  81. claude_mpm/cli/executor.py +202 -0
  82. claude_mpm/cli/helpers.py +105 -0
  83. claude_mpm/cli/interactive/__init__.py +3 -0
  84. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  85. claude_mpm/cli/parsers/__init__.py +7 -1
  86. claude_mpm/cli/parsers/agents_parser.py +9 -0
  87. claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
  88. claude_mpm/cli/parsers/base_parser.py +110 -3
  89. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  90. claude_mpm/cli/parsers/mpm_init_parser.py +65 -5
  91. claude_mpm/cli/shared/output_formatters.py +28 -19
  92. claude_mpm/cli/startup.py +481 -0
  93. claude_mpm/cli/utils.py +52 -1
  94. claude_mpm/commands/mpm-agents-detect.md +168 -0
  95. claude_mpm/commands/mpm-agents-recommend.md +214 -0
  96. claude_mpm/commands/mpm-agents.md +75 -1
  97. claude_mpm/commands/mpm-auto-configure.md +217 -0
  98. claude_mpm/commands/mpm-help.md +163 -0
  99. claude_mpm/commands/mpm-init.md +148 -3
  100. claude_mpm/commands/mpm-version.md +113 -0
  101. claude_mpm/commands/mpm.md +1 -0
  102. claude_mpm/config/agent_config.py +2 -2
  103. claude_mpm/config/model_config.py +428 -0
  104. claude_mpm/constants.py +1 -0
  105. claude_mpm/core/base_service.py +13 -12
  106. claude_mpm/core/enums.py +452 -0
  107. claude_mpm/core/factories.py +1 -1
  108. claude_mpm/core/instruction_reinforcement_hook.py +2 -1
  109. claude_mpm/core/interactive_session.py +9 -3
  110. claude_mpm/core/log_manager.py +2 -0
  111. claude_mpm/core/logging_config.py +6 -2
  112. claude_mpm/core/oneshot_session.py +8 -4
  113. claude_mpm/core/optimized_agent_loader.py +3 -3
  114. claude_mpm/core/output_style_manager.py +12 -192
  115. claude_mpm/core/service_registry.py +5 -1
  116. claude_mpm/core/types.py +2 -9
  117. claude_mpm/core/typing_utils.py +7 -6
  118. claude_mpm/dashboard/static/js/dashboard.js +0 -14
  119. claude_mpm/dashboard/templates/index.html +3 -41
  120. claude_mpm/hooks/__init__.py +20 -0
  121. claude_mpm/hooks/claude_hooks/event_handlers.py +4 -2
  122. claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
  123. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +23 -2
  124. claude_mpm/hooks/failure_learning/__init__.py +60 -0
  125. claude_mpm/hooks/failure_learning/failure_detection_hook.py +235 -0
  126. claude_mpm/hooks/failure_learning/fix_detection_hook.py +217 -0
  127. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +286 -0
  128. claude_mpm/hooks/instruction_reinforcement.py +7 -2
  129. claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
  130. claude_mpm/hooks/kuzu_memory_hook.py +37 -12
  131. claude_mpm/hooks/kuzu_response_hook.py +183 -0
  132. claude_mpm/models/resume_log.py +340 -0
  133. claude_mpm/services/agents/__init__.py +18 -5
  134. claude_mpm/services/agents/auto_config_manager.py +796 -0
  135. claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
  136. claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
  137. claude_mpm/services/agents/deployment/agent_validator.py +17 -1
  138. claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
  139. claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
  140. claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
  141. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
  142. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
  143. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
  144. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
  145. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
  146. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
  147. claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
  148. claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
  149. claude_mpm/services/agents/local_template_manager.py +1 -1
  150. claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
  151. claude_mpm/services/agents/observers.py +547 -0
  152. claude_mpm/services/agents/recommender.py +568 -0
  153. claude_mpm/services/agents/registry/modification_tracker.py +5 -2
  154. claude_mpm/services/command_handler_service.py +11 -5
  155. claude_mpm/services/core/__init__.py +33 -1
  156. claude_mpm/services/core/interfaces/__init__.py +90 -3
  157. claude_mpm/services/core/interfaces/agent.py +184 -0
  158. claude_mpm/services/core/interfaces/health.py +172 -0
  159. claude_mpm/services/core/interfaces/model.py +281 -0
  160. claude_mpm/services/core/interfaces/process.py +372 -0
  161. claude_mpm/services/core/interfaces/project.py +121 -0
  162. claude_mpm/services/core/interfaces/restart.py +307 -0
  163. claude_mpm/services/core/interfaces/stability.py +260 -0
  164. claude_mpm/services/core/memory_manager.py +11 -24
  165. claude_mpm/services/core/models/__init__.py +79 -0
  166. claude_mpm/services/core/models/agent_config.py +381 -0
  167. claude_mpm/services/core/models/health.py +162 -0
  168. claude_mpm/services/core/models/process.py +235 -0
  169. claude_mpm/services/core/models/restart.py +302 -0
  170. claude_mpm/services/core/models/stability.py +264 -0
  171. claude_mpm/services/core/models/toolchain.py +306 -0
  172. claude_mpm/services/core/path_resolver.py +23 -7
  173. claude_mpm/services/diagnostics/__init__.py +2 -2
  174. claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
  175. claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
  176. claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
  177. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
  178. claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
  179. claude_mpm/services/diagnostics/checks/installation_check.py +30 -29
  180. claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
  181. claude_mpm/services/diagnostics/checks/mcp_check.py +50 -36
  182. claude_mpm/services/diagnostics/checks/mcp_services_check.py +38 -33
  183. claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
  184. claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
  185. claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
  186. claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
  187. claude_mpm/services/diagnostics/models.py +19 -24
  188. claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
  189. claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
  190. claude_mpm/services/infrastructure/monitoring/base.py +5 -13
  191. claude_mpm/services/infrastructure/monitoring/network.py +7 -6
  192. claude_mpm/services/infrastructure/monitoring/process.py +13 -12
  193. claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
  194. claude_mpm/services/infrastructure/monitoring/service.py +16 -15
  195. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  196. claude_mpm/services/local_ops/__init__.py +163 -0
  197. claude_mpm/services/local_ops/crash_detector.py +257 -0
  198. claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
  199. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  200. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  201. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  202. claude_mpm/services/local_ops/health_manager.py +430 -0
  203. claude_mpm/services/local_ops/log_monitor.py +396 -0
  204. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  205. claude_mpm/services/local_ops/process_manager.py +595 -0
  206. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  207. claude_mpm/services/local_ops/restart_manager.py +401 -0
  208. claude_mpm/services/local_ops/restart_policy.py +387 -0
  209. claude_mpm/services/local_ops/state_manager.py +372 -0
  210. claude_mpm/services/local_ops/unified_manager.py +600 -0
  211. claude_mpm/services/mcp_config_manager.py +9 -4
  212. claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
  213. claude_mpm/services/mcp_gateway/core/base.py +18 -31
  214. claude_mpm/services/mcp_gateway/main.py +30 -0
  215. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +206 -32
  216. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +30 -28
  217. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +25 -5
  218. claude_mpm/services/mcp_service_verifier.py +1 -1
  219. claude_mpm/services/memory/failure_tracker.py +563 -0
  220. claude_mpm/services/memory_hook_service.py +165 -4
  221. claude_mpm/services/model/__init__.py +147 -0
  222. claude_mpm/services/model/base_provider.py +365 -0
  223. claude_mpm/services/model/claude_provider.py +412 -0
  224. claude_mpm/services/model/model_router.py +453 -0
  225. claude_mpm/services/model/ollama_provider.py +415 -0
  226. claude_mpm/services/monitor/daemon_manager.py +3 -2
  227. claude_mpm/services/monitor/handlers/dashboard.py +2 -1
  228. claude_mpm/services/monitor/handlers/hooks.py +2 -1
  229. claude_mpm/services/monitor/management/lifecycle.py +3 -2
  230. claude_mpm/services/monitor/server.py +2 -1
  231. claude_mpm/services/project/__init__.py +23 -0
  232. claude_mpm/services/project/detection_strategies.py +719 -0
  233. claude_mpm/services/project/toolchain_analyzer.py +581 -0
  234. claude_mpm/services/self_upgrade_service.py +342 -0
  235. claude_mpm/services/session_management_service.py +3 -2
  236. claude_mpm/services/session_manager.py +205 -1
  237. claude_mpm/services/shared/async_service_base.py +16 -27
  238. claude_mpm/services/shared/lifecycle_service_base.py +1 -14
  239. claude_mpm/services/socketio/handlers/__init__.py +5 -2
  240. claude_mpm/services/socketio/handlers/hook.py +13 -2
  241. claude_mpm/services/socketio/handlers/registry.py +4 -2
  242. claude_mpm/services/socketio/server/main.py +10 -8
  243. claude_mpm/services/subprocess_launcher_service.py +14 -5
  244. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +8 -7
  245. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
  246. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
  247. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +7 -6
  248. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
  249. claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
  250. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
  251. claude_mpm/services/unified/deployment_strategies/local.py +6 -5
  252. claude_mpm/services/unified/deployment_strategies/utils.py +6 -5
  253. claude_mpm/services/unified/deployment_strategies/vercel.py +7 -6
  254. claude_mpm/services/unified/interfaces.py +3 -1
  255. claude_mpm/services/unified/unified_analyzer.py +14 -10
  256. claude_mpm/services/unified/unified_config.py +2 -1
  257. claude_mpm/services/unified/unified_deployment.py +9 -4
  258. claude_mpm/services/version_service.py +104 -1
  259. claude_mpm/skills/__init__.py +21 -0
  260. claude_mpm/skills/bundled/__init__.py +6 -0
  261. claude_mpm/skills/bundled/api-documentation.md +393 -0
  262. claude_mpm/skills/bundled/async-testing.md +571 -0
  263. claude_mpm/skills/bundled/code-review.md +143 -0
  264. claude_mpm/skills/bundled/database-migration.md +199 -0
  265. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  266. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  267. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  268. claude_mpm/skills/bundled/git-workflow.md +414 -0
  269. claude_mpm/skills/bundled/imagemagick.md +204 -0
  270. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  271. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  272. claude_mpm/skills/bundled/pdf.md +141 -0
  273. claude_mpm/skills/bundled/performance-profiling.md +567 -0
  274. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  275. claude_mpm/skills/bundled/security-scanning.md +327 -0
  276. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  277. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  278. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  279. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  280. claude_mpm/skills/bundled/xlsx.md +157 -0
  281. claude_mpm/skills/registry.py +286 -0
  282. claude_mpm/skills/skill_manager.py +310 -0
  283. claude_mpm/storage/state_storage.py +15 -15
  284. claude_mpm/tools/code_tree_analyzer.py +177 -141
  285. claude_mpm/tools/code_tree_events.py +4 -2
  286. claude_mpm/utils/agent_dependency_loader.py +40 -20
  287. claude_mpm/utils/display_helper.py +260 -0
  288. claude_mpm/utils/git_analyzer.py +407 -0
  289. claude_mpm/utils/robust_installer.py +73 -19
  290. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/METADATA +129 -12
  291. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/RECORD +295 -193
  292. claude_mpm/dashboard/static/css/code-tree.css +0 -1639
  293. claude_mpm/dashboard/static/index-hub-backup.html +0 -713
  294. claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
  295. claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
  296. claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
  297. claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
  298. claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
  299. claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
  300. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
  301. claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
  302. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
  303. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
  304. claude_mpm/services/project/analyzer_refactored.py +0 -450
  305. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/WHEEL +0 -0
  306. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/entry_points.txt +0 -0
  307. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/licenses/LICENSE +0 -0
  308. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,235 @@
1
+ """
2
+ Process Management Data Models for Claude MPM Framework
3
+ ========================================================
4
+
5
+ WHY: This module defines data structures for process management operations,
6
+ including deployment state and runtime information.
7
+
8
+ DESIGN DECISION: Uses dataclasses for immutability and type safety. Provides
9
+ serialization methods for state persistence. Process status uses ServiceState
10
+ enum from core.enums (consolidated in Phase 3A Batch 24).
11
+
12
+ ARCHITECTURE:
13
+ - DeploymentState: Complete deployment information for persistence
14
+ - ProcessInfo: Runtime process information
15
+ - StartConfig: Configuration for spawning new processes
16
+
17
+ Note: ProcessStatus enum has been consolidated into ServiceState (core.enums).
18
+ """
19
+
20
+ import json
21
+ from dataclasses import asdict, dataclass, field
22
+ from datetime import datetime
23
+ from pathlib import Path
24
+ from typing import Any, Dict, List, Optional
25
+
26
+ from claude_mpm.core.enums import ServiceState
27
+
28
+
29
+ @dataclass
30
+ class DeploymentState:
31
+ """
32
+ Complete deployment state for persistence.
33
+
34
+ WHY: Contains all information needed to track, manage, and restart
35
+ a deployment. Serializable to JSON for state file storage.
36
+
37
+ Attributes:
38
+ deployment_id: Unique identifier for this deployment
39
+ process_id: OS process ID (PID)
40
+ command: Command and arguments used to start process
41
+ working_directory: Working directory for the process
42
+ environment: Environment variables (beyond inherited ones)
43
+ port: Primary port used by the process (if applicable)
44
+ started_at: Timestamp when process was started
45
+ status: Current ServiceState (process lifecycle state)
46
+ metadata: Additional deployment-specific information
47
+ """
48
+
49
+ deployment_id: str
50
+ process_id: int
51
+ command: List[str]
52
+ working_directory: str
53
+ environment: Dict[str, str] = field(default_factory=dict)
54
+ port: Optional[int] = None
55
+ started_at: datetime = field(default_factory=datetime.now)
56
+ status: ServiceState = ServiceState.STARTING
57
+ metadata: Dict[str, Any] = field(default_factory=dict)
58
+
59
+ def to_dict(self) -> Dict[str, Any]:
60
+ """
61
+ Convert to dictionary for JSON serialization.
62
+
63
+ Returns:
64
+ Dictionary representation with datetime converted to ISO format
65
+ """
66
+ data = asdict(self)
67
+ data["started_at"] = self.started_at.isoformat()
68
+ data["status"] = self.status.value
69
+ return data
70
+
71
+ @classmethod
72
+ def from_dict(cls, data: Dict[str, Any]) -> "DeploymentState":
73
+ """
74
+ Create DeploymentState from dictionary.
75
+
76
+ Args:
77
+ data: Dictionary from JSON deserialization
78
+
79
+ Returns:
80
+ DeploymentState instance
81
+ """
82
+ # Convert ISO string to datetime
83
+ if isinstance(data.get("started_at"), str):
84
+ data["started_at"] = datetime.fromisoformat(data["started_at"])
85
+
86
+ # Convert status string to enum
87
+ if isinstance(data.get("status"), str):
88
+ status_value = data["status"]
89
+ # Handle legacy "crashed" status -> map to ERROR
90
+ if status_value == "crashed":
91
+ data["status"] = (
92
+ ServiceState.ERROR
93
+ ) # CRASHED semantically maps to ERROR state
94
+ else:
95
+ data["status"] = ServiceState(status_value)
96
+
97
+ return cls(**data)
98
+
99
+ def to_json(self) -> str:
100
+ """
101
+ Serialize to JSON string.
102
+
103
+ Returns:
104
+ JSON string representation
105
+ """
106
+ return json.dumps(self.to_dict(), indent=2)
107
+
108
+ @classmethod
109
+ def from_json(cls, json_str: str) -> "DeploymentState":
110
+ """
111
+ Deserialize from JSON string.
112
+
113
+ Args:
114
+ json_str: JSON string
115
+
116
+ Returns:
117
+ DeploymentState instance
118
+ """
119
+ return cls.from_dict(json.loads(json_str))
120
+
121
+
122
+ @dataclass
123
+ class ProcessInfo:
124
+ """
125
+ Runtime process information.
126
+
127
+ WHY: Provides real-time process status including resource usage and
128
+ health information. Separate from DeploymentState to avoid mixing
129
+ persistent state with transient runtime data.
130
+
131
+ Attributes:
132
+ deployment_id: Unique deployment identifier
133
+ process_id: OS process ID
134
+ status: Current ServiceState (process lifecycle state)
135
+ port: Port the process is using
136
+ uptime_seconds: How long the process has been running
137
+ memory_mb: Current memory usage in megabytes
138
+ cpu_percent: Current CPU usage percentage
139
+ is_responding: Whether the process responds to health checks
140
+ error_message: Error message if status is ERROR (crashed)
141
+ """
142
+
143
+ deployment_id: str
144
+ process_id: int
145
+ status: ServiceState
146
+ port: Optional[int] = None
147
+ uptime_seconds: float = 0.0
148
+ memory_mb: float = 0.0
149
+ cpu_percent: float = 0.0
150
+ is_responding: bool = False
151
+ error_message: Optional[str] = None
152
+
153
+ def to_dict(self) -> Dict[str, Any]:
154
+ """Convert to dictionary."""
155
+ data = asdict(self)
156
+ data["status"] = self.status.value
157
+ return data
158
+
159
+
160
+ @dataclass
161
+ class StartConfig:
162
+ """
163
+ Configuration for starting a new process.
164
+
165
+ WHY: Encapsulates all parameters needed to spawn a process. Provides
166
+ validation and sensible defaults.
167
+
168
+ Attributes:
169
+ command: Command and arguments to execute
170
+ working_directory: Working directory for the process
171
+ environment: Environment variables to set (beyond inherited)
172
+ port: Preferred port for the process
173
+ auto_find_port: If True, find alternative port if preferred is unavailable
174
+ metadata: Additional deployment metadata
175
+ deployment_id: Optional explicit deployment ID (generated if not provided)
176
+ """
177
+
178
+ command: List[str]
179
+ working_directory: str
180
+ environment: Dict[str, str] = field(default_factory=dict)
181
+ port: Optional[int] = None
182
+ auto_find_port: bool = True
183
+ metadata: Dict[str, Any] = field(default_factory=dict)
184
+ deployment_id: Optional[str] = None
185
+
186
+ def __post_init__(self):
187
+ """Validate configuration after initialization."""
188
+ if not self.command:
189
+ raise ValueError("Command cannot be empty")
190
+
191
+ if not self.working_directory:
192
+ raise ValueError("Working directory must be specified")
193
+
194
+ # Ensure working_directory is absolute
195
+ self.working_directory = str(Path(self.working_directory).absolute())
196
+
197
+ # Validate port range if specified
198
+ if self.port is not None:
199
+ if not (1024 <= self.port <= 65535):
200
+ raise ValueError(f"Port must be between 1024-65535, got {self.port}")
201
+
202
+ def to_dict(self) -> Dict[str, Any]:
203
+ """Convert to dictionary."""
204
+ return asdict(self)
205
+
206
+
207
+ # Port range constants
208
+ PROTECTED_PORT_RANGES = [
209
+ (8765, 8785), # Claude MPM services (WebSocket, SocketIO, monitors)
210
+ ]
211
+
212
+
213
+ def is_port_protected(port: int) -> bool:
214
+ """
215
+ Check if a port is in a protected range.
216
+
217
+ WHY: Prevents local-ops-agent from interfering with Claude MPM
218
+ system services.
219
+
220
+ Args:
221
+ port: Port number to check
222
+
223
+ Returns:
224
+ True if port is protected
225
+ """
226
+ return any(start <= port <= end for start, end in PROTECTED_PORT_RANGES)
227
+
228
+
229
+ __all__ = [
230
+ "PROTECTED_PORT_RANGES",
231
+ "DeploymentState",
232
+ "ProcessInfo",
233
+ "StartConfig",
234
+ "is_port_protected",
235
+ ]
@@ -0,0 +1,302 @@
1
+ """
2
+ Restart Management Data Models for Claude MPM Framework
3
+ ========================================================
4
+
5
+ WHY: This module defines data structures for auto-restart operations,
6
+ including restart attempts, history tracking, and circuit breaker states.
7
+
8
+ DESIGN DECISION: Uses dataclasses for immutability and type safety. Provides
9
+ serialization methods for state persistence across service restarts.
10
+
11
+ ARCHITECTURE:
12
+ - CircuitBreakerState: Enum of circuit breaker states
13
+ - RestartAttempt: Single restart attempt record
14
+ - RestartHistory: Complete restart history for a deployment
15
+ - RestartConfig: Configuration for restart policies
16
+ """
17
+
18
+ from dataclasses import asdict, dataclass, field
19
+ from datetime import datetime, timezone
20
+ from enum import Enum
21
+ from typing import Any, Dict, List, Optional
22
+
23
+
24
+ class CircuitBreakerState(Enum):
25
+ """
26
+ Circuit breaker state for restart management.
27
+
28
+ WHY: Circuit breaker prevents infinite restart loops by blocking
29
+ restarts after repeated failures within a time window.
30
+
31
+ States:
32
+ CLOSED: Normal operation, restarts allowed
33
+ OPEN: Circuit breaker tripped, restarts blocked
34
+ HALF_OPEN: Testing if service recovered (allows one restart)
35
+ """
36
+
37
+ CLOSED = "closed"
38
+ OPEN = "open"
39
+ HALF_OPEN = "half_open"
40
+
41
+ def allows_restart(self) -> bool:
42
+ """Check if state allows restart attempts."""
43
+ return self in (CircuitBreakerState.CLOSED, CircuitBreakerState.HALF_OPEN)
44
+
45
+
46
+ @dataclass
47
+ class RestartAttempt:
48
+ """
49
+ Record of a single restart attempt.
50
+
51
+ WHY: Tracks detailed information about each restart attempt to enable
52
+ debugging and policy decisions (exponential backoff, circuit breaker).
53
+
54
+ Attributes:
55
+ attempt_number: Sequential attempt number (1-based)
56
+ deployment_id: Unique deployment identifier
57
+ started_at: When the restart was initiated
58
+ completed_at: When the restart finished (None if in progress)
59
+ success: Whether the restart succeeded
60
+ failure_reason: Optional reason for failure
61
+ backoff_seconds: Backoff time before this attempt
62
+ """
63
+
64
+ attempt_number: int
65
+ deployment_id: str
66
+ started_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
67
+ completed_at: Optional[datetime] = None
68
+ success: bool = False
69
+ failure_reason: Optional[str] = None
70
+ backoff_seconds: float = 0.0
71
+
72
+ def to_dict(self) -> Dict[str, Any]:
73
+ """
74
+ Convert to dictionary for JSON serialization.
75
+
76
+ Returns:
77
+ Dictionary representation with datetime converted to ISO format
78
+ """
79
+ return {
80
+ "attempt_number": self.attempt_number,
81
+ "deployment_id": self.deployment_id,
82
+ "started_at": self.started_at.isoformat(),
83
+ "completed_at": (
84
+ self.completed_at.isoformat() if self.completed_at else None
85
+ ),
86
+ "success": self.success,
87
+ "failure_reason": self.failure_reason,
88
+ "backoff_seconds": self.backoff_seconds,
89
+ }
90
+
91
+ @classmethod
92
+ def from_dict(cls, data: Dict[str, Any]) -> "RestartAttempt":
93
+ """
94
+ Create RestartAttempt from dictionary.
95
+
96
+ Args:
97
+ data: Dictionary from JSON deserialization
98
+
99
+ Returns:
100
+ RestartAttempt instance
101
+ """
102
+ # Convert ISO strings to datetime
103
+ if isinstance(data.get("started_at"), str):
104
+ data["started_at"] = datetime.fromisoformat(data["started_at"])
105
+
106
+ if data.get("completed_at") and isinstance(data["completed_at"], str):
107
+ data["completed_at"] = datetime.fromisoformat(data["completed_at"])
108
+
109
+ return cls(**data)
110
+
111
+
112
+ @dataclass
113
+ class RestartHistory:
114
+ """
115
+ Complete restart history for a deployment.
116
+
117
+ WHY: Maintains restart attempt history, circuit breaker state, and
118
+ failure window tracking to enable intelligent restart policies.
119
+
120
+ Attributes:
121
+ deployment_id: Unique deployment identifier
122
+ attempts: List of restart attempts (newest first)
123
+ circuit_breaker_state: Current circuit breaker state
124
+ last_failure_window_start: Start of current failure window
125
+ failure_count_in_window: Number of failures in current window
126
+ """
127
+
128
+ deployment_id: str
129
+ attempts: List[RestartAttempt] = field(default_factory=list)
130
+ circuit_breaker_state: CircuitBreakerState = CircuitBreakerState.CLOSED
131
+ last_failure_window_start: Optional[datetime] = None
132
+ failure_count_in_window: int = 0
133
+
134
+ def to_dict(self) -> Dict[str, Any]:
135
+ """
136
+ Convert to dictionary for JSON serialization.
137
+
138
+ Returns:
139
+ Dictionary representation
140
+ """
141
+ return {
142
+ "deployment_id": self.deployment_id,
143
+ "attempts": [attempt.to_dict() for attempt in self.attempts],
144
+ "circuit_breaker_state": self.circuit_breaker_state.value,
145
+ "last_failure_window_start": (
146
+ self.last_failure_window_start.isoformat()
147
+ if self.last_failure_window_start
148
+ else None
149
+ ),
150
+ "failure_count_in_window": self.failure_count_in_window,
151
+ }
152
+
153
+ @classmethod
154
+ def from_dict(cls, data: Dict[str, Any]) -> "RestartHistory":
155
+ """
156
+ Create RestartHistory from dictionary.
157
+
158
+ Args:
159
+ data: Dictionary from JSON deserialization
160
+
161
+ Returns:
162
+ RestartHistory instance
163
+ """
164
+ # Convert circuit breaker state string to enum
165
+ if isinstance(data.get("circuit_breaker_state"), str):
166
+ data["circuit_breaker_state"] = CircuitBreakerState(
167
+ data["circuit_breaker_state"]
168
+ )
169
+
170
+ # Convert ISO string to datetime
171
+ if data.get("last_failure_window_start") and isinstance(
172
+ data["last_failure_window_start"], str
173
+ ):
174
+ data["last_failure_window_start"] = datetime.fromisoformat(
175
+ data["last_failure_window_start"]
176
+ )
177
+
178
+ # Convert attempt dicts to RestartAttempt objects
179
+ if isinstance(data.get("attempts"), list):
180
+ data["attempts"] = [
181
+ (
182
+ RestartAttempt.from_dict(attempt)
183
+ if isinstance(attempt, dict)
184
+ else attempt
185
+ )
186
+ for attempt in data["attempts"]
187
+ ]
188
+
189
+ return cls(**data)
190
+
191
+ def get_latest_attempt(self) -> Optional[RestartAttempt]:
192
+ """
193
+ Get the most recent restart attempt.
194
+
195
+ Returns:
196
+ Latest RestartAttempt if any, None otherwise
197
+ """
198
+ return self.attempts[0] if self.attempts else None
199
+
200
+ def get_attempt_count(self) -> int:
201
+ """
202
+ Get total number of restart attempts.
203
+
204
+ Returns:
205
+ Number of attempts
206
+ """
207
+ return len(self.attempts)
208
+
209
+ def get_consecutive_failures(self) -> int:
210
+ """
211
+ Get number of consecutive failures from the most recent attempt.
212
+
213
+ Returns:
214
+ Count of consecutive failures
215
+ """
216
+ count = 0
217
+ for attempt in self.attempts:
218
+ if not attempt.success:
219
+ count += 1
220
+ else:
221
+ break
222
+ return count
223
+
224
+
225
+ @dataclass
226
+ class RestartConfig:
227
+ """
228
+ Configuration for restart policies.
229
+
230
+ WHY: Encapsulates all restart policy parameters to enable flexible
231
+ configuration and testing.
232
+
233
+ Attributes:
234
+ max_attempts: Maximum restart attempts before giving up
235
+ initial_backoff_seconds: Initial backoff time (doubles each attempt)
236
+ max_backoff_seconds: Maximum backoff cap (default: 5 minutes)
237
+ backoff_multiplier: Backoff multiplier for exponential backoff
238
+ circuit_breaker_threshold: Failures to trip circuit breaker
239
+ circuit_breaker_window_seconds: Time window for failure counting
240
+ circuit_breaker_reset_seconds: Cooldown before resetting breaker
241
+ health_check_timeout_seconds: Time to wait for health check after restart
242
+ """
243
+
244
+ max_attempts: int = 5
245
+ initial_backoff_seconds: float = 2.0
246
+ max_backoff_seconds: float = 300.0 # 5 minutes
247
+ backoff_multiplier: float = 2.0
248
+ circuit_breaker_threshold: int = 3 # failures to trip breaker
249
+ circuit_breaker_window_seconds: int = 300 # 5 minute window
250
+ circuit_breaker_reset_seconds: int = 600 # 10 minute cooldown
251
+ health_check_timeout_seconds: int = 30 # wait for health check
252
+
253
+ def __post_init__(self):
254
+ """Validate configuration after initialization."""
255
+ if self.max_attempts < 1:
256
+ raise ValueError("max_attempts must be >= 1")
257
+
258
+ if self.initial_backoff_seconds < 0:
259
+ raise ValueError("initial_backoff_seconds must be >= 0")
260
+
261
+ if self.max_backoff_seconds < self.initial_backoff_seconds:
262
+ raise ValueError("max_backoff_seconds must be >= initial_backoff_seconds")
263
+
264
+ if self.backoff_multiplier < 1.0:
265
+ raise ValueError("backoff_multiplier must be >= 1.0")
266
+
267
+ if self.circuit_breaker_threshold < 1:
268
+ raise ValueError("circuit_breaker_threshold must be >= 1")
269
+
270
+ if self.circuit_breaker_window_seconds < 1:
271
+ raise ValueError("circuit_breaker_window_seconds must be >= 1")
272
+
273
+ if self.circuit_breaker_reset_seconds < 1:
274
+ raise ValueError("circuit_breaker_reset_seconds must be >= 1")
275
+
276
+ if self.health_check_timeout_seconds < 1:
277
+ raise ValueError("health_check_timeout_seconds must be >= 1")
278
+
279
+ def to_dict(self) -> Dict[str, Any]:
280
+ """Convert to dictionary."""
281
+ return asdict(self)
282
+
283
+ @classmethod
284
+ def from_dict(cls, data: Dict[str, Any]) -> "RestartConfig":
285
+ """
286
+ Create RestartConfig from dictionary.
287
+
288
+ Args:
289
+ data: Dictionary from JSON deserialization
290
+
291
+ Returns:
292
+ RestartConfig instance
293
+ """
294
+ return cls(**data)
295
+
296
+
297
+ __all__ = [
298
+ "CircuitBreakerState",
299
+ "RestartAttempt",
300
+ "RestartConfig",
301
+ "RestartHistory",
302
+ ]