claude-mpm 3.9.11__py3-none-any.whl → 4.0.4__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 (434) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +2 -2
  3. claude_mpm/__main__.py +3 -2
  4. claude_mpm/agents/__init__.py +85 -79
  5. claude_mpm/agents/agent_loader.py +464 -1003
  6. claude_mpm/agents/agent_loader_integration.py +45 -45
  7. claude_mpm/agents/agents_metadata.py +29 -30
  8. claude_mpm/agents/async_agent_loader.py +156 -138
  9. claude_mpm/agents/base_agent.json +1 -1
  10. claude_mpm/agents/base_agent_loader.py +179 -151
  11. claude_mpm/agents/frontmatter_validator.py +229 -130
  12. claude_mpm/agents/schema/agent_schema.json +1 -1
  13. claude_mpm/agents/system_agent_config.py +213 -147
  14. claude_mpm/agents/templates/__init__.py +13 -13
  15. claude_mpm/agents/templates/code_analyzer.json +2 -2
  16. claude_mpm/agents/templates/data_engineer.json +1 -1
  17. claude_mpm/agents/templates/documentation.json +23 -11
  18. claude_mpm/agents/templates/engineer.json +22 -6
  19. claude_mpm/agents/templates/memory_manager.json +1 -1
  20. claude_mpm/agents/templates/ops.json +2 -2
  21. claude_mpm/agents/templates/project_organizer.json +1 -1
  22. claude_mpm/agents/templates/qa.json +1 -1
  23. claude_mpm/agents/templates/refactoring_engineer.json +222 -0
  24. claude_mpm/agents/templates/research.json +20 -14
  25. claude_mpm/agents/templates/security.json +1 -1
  26. claude_mpm/agents/templates/ticketing.json +2 -2
  27. claude_mpm/agents/templates/version_control.json +1 -1
  28. claude_mpm/agents/templates/web_qa.json +3 -1
  29. claude_mpm/agents/templates/web_ui.json +2 -2
  30. claude_mpm/cli/__init__.py +79 -51
  31. claude_mpm/cli/__main__.py +3 -2
  32. claude_mpm/cli/commands/__init__.py +20 -20
  33. claude_mpm/cli/commands/agents.py +279 -247
  34. claude_mpm/cli/commands/aggregate.py +138 -157
  35. claude_mpm/cli/commands/cleanup.py +147 -147
  36. claude_mpm/cli/commands/config.py +93 -76
  37. claude_mpm/cli/commands/info.py +17 -16
  38. claude_mpm/cli/commands/mcp.py +140 -905
  39. claude_mpm/cli/commands/mcp_command_router.py +139 -0
  40. claude_mpm/cli/commands/mcp_config_commands.py +20 -0
  41. claude_mpm/cli/commands/mcp_install_commands.py +20 -0
  42. claude_mpm/cli/commands/mcp_server_commands.py +175 -0
  43. claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
  44. claude_mpm/cli/commands/memory.py +239 -203
  45. claude_mpm/cli/commands/monitor.py +330 -86
  46. claude_mpm/cli/commands/run.py +380 -429
  47. claude_mpm/cli/commands/run_config_checker.py +160 -0
  48. claude_mpm/cli/commands/socketio_monitor.py +235 -0
  49. claude_mpm/cli/commands/tickets.py +363 -220
  50. claude_mpm/cli/parser.py +24 -1156
  51. claude_mpm/cli/parsers/__init__.py +29 -0
  52. claude_mpm/cli/parsers/agents_parser.py +136 -0
  53. claude_mpm/cli/parsers/base_parser.py +331 -0
  54. claude_mpm/cli/parsers/config_parser.py +85 -0
  55. claude_mpm/cli/parsers/mcp_parser.py +152 -0
  56. claude_mpm/cli/parsers/memory_parser.py +138 -0
  57. claude_mpm/cli/parsers/monitor_parser.py +124 -0
  58. claude_mpm/cli/parsers/run_parser.py +147 -0
  59. claude_mpm/cli/parsers/tickets_parser.py +203 -0
  60. claude_mpm/cli/ticket_cli.py +7 -3
  61. claude_mpm/cli/utils.py +55 -37
  62. claude_mpm/cli_module/__init__.py +6 -6
  63. claude_mpm/cli_module/args.py +188 -140
  64. claude_mpm/cli_module/commands.py +79 -70
  65. claude_mpm/cli_module/migration_example.py +38 -60
  66. claude_mpm/config/__init__.py +32 -25
  67. claude_mpm/config/agent_config.py +151 -119
  68. claude_mpm/config/experimental_features.py +71 -73
  69. claude_mpm/config/paths.py +94 -208
  70. claude_mpm/config/socketio_config.py +84 -73
  71. claude_mpm/constants.py +35 -18
  72. claude_mpm/core/__init__.py +9 -6
  73. claude_mpm/core/agent_name_normalizer.py +68 -71
  74. claude_mpm/core/agent_registry.py +372 -521
  75. claude_mpm/core/agent_session_manager.py +74 -63
  76. claude_mpm/core/base_service.py +116 -87
  77. claude_mpm/core/cache.py +119 -153
  78. claude_mpm/core/claude_runner.py +425 -1120
  79. claude_mpm/core/config.py +263 -168
  80. claude_mpm/core/config_aliases.py +69 -61
  81. claude_mpm/core/config_constants.py +292 -0
  82. claude_mpm/core/constants.py +57 -99
  83. claude_mpm/core/container.py +211 -178
  84. claude_mpm/core/exceptions.py +233 -89
  85. claude_mpm/core/factories.py +92 -54
  86. claude_mpm/core/framework_loader.py +378 -220
  87. claude_mpm/core/hook_manager.py +198 -83
  88. claude_mpm/core/hook_performance_config.py +136 -0
  89. claude_mpm/core/injectable_service.py +61 -55
  90. claude_mpm/core/interactive_session.py +165 -155
  91. claude_mpm/core/interfaces.py +221 -195
  92. claude_mpm/core/lazy.py +96 -96
  93. claude_mpm/core/logger.py +133 -107
  94. claude_mpm/core/logging_config.py +185 -157
  95. claude_mpm/core/minimal_framework_loader.py +20 -15
  96. claude_mpm/core/mixins.py +30 -29
  97. claude_mpm/core/oneshot_session.py +215 -181
  98. claude_mpm/core/optimized_agent_loader.py +134 -138
  99. claude_mpm/core/optimized_startup.py +159 -157
  100. claude_mpm/core/pm_hook_interceptor.py +85 -72
  101. claude_mpm/core/service_registry.py +103 -101
  102. claude_mpm/core/session_manager.py +97 -87
  103. claude_mpm/core/socketio_pool.py +212 -158
  104. claude_mpm/core/tool_access_control.py +58 -51
  105. claude_mpm/core/types.py +46 -24
  106. claude_mpm/core/typing_utils.py +166 -82
  107. claude_mpm/core/unified_agent_registry.py +721 -0
  108. claude_mpm/core/unified_config.py +550 -0
  109. claude_mpm/core/unified_paths.py +549 -0
  110. claude_mpm/dashboard/index.html +1 -1
  111. claude_mpm/dashboard/open_dashboard.py +51 -17
  112. claude_mpm/dashboard/static/built/components/agent-inference.js +2 -0
  113. claude_mpm/dashboard/static/built/components/event-processor.js +2 -0
  114. claude_mpm/dashboard/static/built/components/event-viewer.js +2 -0
  115. claude_mpm/dashboard/static/built/components/export-manager.js +2 -0
  116. claude_mpm/dashboard/static/built/components/file-tool-tracker.js +2 -0
  117. claude_mpm/dashboard/static/built/components/hud-library-loader.js +2 -0
  118. claude_mpm/dashboard/static/built/components/hud-manager.js +2 -0
  119. claude_mpm/dashboard/static/built/components/hud-visualizer.js +2 -0
  120. claude_mpm/dashboard/static/built/components/module-viewer.js +2 -0
  121. claude_mpm/dashboard/static/built/components/session-manager.js +2 -0
  122. claude_mpm/dashboard/static/built/components/socket-manager.js +2 -0
  123. claude_mpm/dashboard/static/built/components/ui-state-manager.js +2 -0
  124. claude_mpm/dashboard/static/built/components/working-directory.js +2 -0
  125. claude_mpm/dashboard/static/built/dashboard.js +2 -0
  126. claude_mpm/dashboard/static/built/socket-client.js +2 -0
  127. claude_mpm/dashboard/static/css/dashboard.css +27 -8
  128. claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
  129. claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
  130. claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
  131. claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
  132. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
  133. claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
  134. claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
  135. claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
  136. claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
  137. claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
  138. claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
  139. claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
  140. claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
  141. claude_mpm/dashboard/static/dist/dashboard.js +2 -0
  142. claude_mpm/dashboard/static/dist/socket-client.js +2 -0
  143. claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
  144. claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
  145. claude_mpm/dashboard/static/js/components/event-viewer.js +93 -72
  146. claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
  147. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +110 -96
  148. claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
  149. claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
  150. claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
  151. claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
  152. claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
  153. claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
  154. claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
  155. claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
  156. claude_mpm/dashboard/static/js/dashboard.js +178 -453
  157. claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
  158. claude_mpm/dashboard/static/js/socket-client.js +133 -53
  159. claude_mpm/dashboard/templates/index.html +40 -50
  160. claude_mpm/experimental/cli_enhancements.py +60 -58
  161. claude_mpm/generators/__init__.py +1 -1
  162. claude_mpm/generators/agent_profile_generator.py +75 -65
  163. claude_mpm/hooks/__init__.py +1 -1
  164. claude_mpm/hooks/base_hook.py +33 -28
  165. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  166. claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
  167. claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
  168. claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
  169. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
  170. claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
  171. claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
  172. claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
  173. claude_mpm/hooks/memory_integration_hook.py +140 -100
  174. claude_mpm/hooks/tool_call_interceptor.py +89 -76
  175. claude_mpm/hooks/validation_hooks.py +57 -49
  176. claude_mpm/init.py +145 -121
  177. claude_mpm/models/__init__.py +9 -9
  178. claude_mpm/models/agent_definition.py +33 -23
  179. claude_mpm/models/agent_session.py +228 -200
  180. claude_mpm/scripts/__init__.py +1 -1
  181. claude_mpm/scripts/socketio_daemon.py +192 -75
  182. claude_mpm/scripts/socketio_server_manager.py +328 -0
  183. claude_mpm/scripts/start_activity_logging.py +25 -22
  184. claude_mpm/services/__init__.py +68 -43
  185. claude_mpm/services/agent_capabilities_service.py +271 -0
  186. claude_mpm/services/agents/__init__.py +23 -32
  187. claude_mpm/services/agents/deployment/__init__.py +3 -3
  188. claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
  189. claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
  190. claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
  191. claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
  192. claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
  193. claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
  194. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
  195. claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
  196. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
  197. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
  198. claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
  199. claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
  200. claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
  201. claude_mpm/services/agents/deployment/agent_validator.py +352 -0
  202. claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
  203. claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
  204. claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
  205. claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
  206. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  207. claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
  208. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  209. claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
  210. claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
  211. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  212. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  213. claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
  214. claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
  215. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  216. claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
  217. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  218. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  219. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  220. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  221. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
  222. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  223. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  224. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
  225. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
  226. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
  227. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
  228. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
  229. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  230. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
  231. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  232. claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
  233. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
  234. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  235. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  236. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  237. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  238. claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
  239. claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
  240. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  241. claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
  242. claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
  243. claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
  244. claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
  245. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  246. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  247. claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
  248. claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
  249. claude_mpm/services/agents/loading/__init__.py +2 -2
  250. claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
  251. claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
  252. claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
  253. claude_mpm/services/agents/management/__init__.py +2 -2
  254. claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
  255. claude_mpm/services/agents/management/agent_management_service.py +209 -156
  256. claude_mpm/services/agents/memory/__init__.py +9 -6
  257. claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
  258. claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
  259. claude_mpm/services/agents/memory/analyzer.py +430 -0
  260. claude_mpm/services/agents/memory/content_manager.py +376 -0
  261. claude_mpm/services/agents/memory/template_generator.py +468 -0
  262. claude_mpm/services/agents/registry/__init__.py +7 -10
  263. claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
  264. claude_mpm/services/agents/registry/modification_tracker.py +351 -285
  265. claude_mpm/services/async_session_logger.py +187 -153
  266. claude_mpm/services/claude_session_logger.py +87 -72
  267. claude_mpm/services/command_handler_service.py +217 -0
  268. claude_mpm/services/communication/__init__.py +3 -2
  269. claude_mpm/services/core/__init__.py +50 -97
  270. claude_mpm/services/core/base.py +60 -53
  271. claude_mpm/services/core/interfaces/__init__.py +188 -0
  272. claude_mpm/services/core/interfaces/agent.py +351 -0
  273. claude_mpm/services/core/interfaces/communication.py +343 -0
  274. claude_mpm/services/core/interfaces/infrastructure.py +413 -0
  275. claude_mpm/services/core/interfaces/service.py +434 -0
  276. claude_mpm/services/core/interfaces.py +19 -944
  277. claude_mpm/services/event_aggregator.py +208 -170
  278. claude_mpm/services/exceptions.py +387 -308
  279. claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
  280. claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
  281. claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
  282. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
  283. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
  284. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
  285. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
  286. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
  287. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  288. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  289. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  290. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  291. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
  292. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  293. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  294. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
  295. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
  296. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  297. claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
  298. claude_mpm/services/hook_service.py +106 -114
  299. claude_mpm/services/infrastructure/__init__.py +7 -5
  300. claude_mpm/services/infrastructure/context_preservation.py +233 -199
  301. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  302. claude_mpm/services/infrastructure/logging.py +83 -76
  303. claude_mpm/services/infrastructure/monitoring.py +547 -404
  304. claude_mpm/services/mcp_gateway/__init__.py +30 -13
  305. claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
  306. claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
  307. claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
  308. claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
  309. claude_mpm/services/mcp_gateway/core/__init__.py +13 -20
  310. claude_mpm/services/mcp_gateway/core/base.py +80 -67
  311. claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
  312. claude_mpm/services/mcp_gateway/core/interfaces.py +87 -84
  313. claude_mpm/services/mcp_gateway/main.py +287 -137
  314. claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
  315. claude_mpm/services/mcp_gateway/registry/service_registry.py +97 -94
  316. claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
  317. claude_mpm/services/mcp_gateway/server/__init__.py +2 -2
  318. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +105 -110
  319. claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
  320. claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
  321. claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
  322. claude_mpm/services/mcp_gateway/tools/base_adapter.py +109 -119
  323. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
  324. claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
  325. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
  326. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
  327. claude_mpm/services/memory/__init__.py +2 -2
  328. claude_mpm/services/memory/builder.py +451 -362
  329. claude_mpm/services/memory/cache/__init__.py +2 -2
  330. claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
  331. claude_mpm/services/memory/cache/simple_cache.py +107 -93
  332. claude_mpm/services/memory/indexed_memory.py +195 -193
  333. claude_mpm/services/memory/optimizer.py +267 -234
  334. claude_mpm/services/memory/router.py +571 -263
  335. claude_mpm/services/memory_hook_service.py +237 -0
  336. claude_mpm/services/port_manager.py +575 -0
  337. claude_mpm/services/project/__init__.py +3 -3
  338. claude_mpm/services/project/analyzer.py +451 -305
  339. claude_mpm/services/project/registry.py +262 -240
  340. claude_mpm/services/recovery_manager.py +287 -231
  341. claude_mpm/services/response_tracker.py +87 -67
  342. claude_mpm/services/runner_configuration_service.py +587 -0
  343. claude_mpm/services/session_management_service.py +304 -0
  344. claude_mpm/services/socketio/__init__.py +4 -4
  345. claude_mpm/services/socketio/client_proxy.py +174 -0
  346. claude_mpm/services/socketio/handlers/__init__.py +3 -3
  347. claude_mpm/services/socketio/handlers/base.py +44 -30
  348. claude_mpm/services/socketio/handlers/connection.py +166 -64
  349. claude_mpm/services/socketio/handlers/file.py +123 -108
  350. claude_mpm/services/socketio/handlers/git.py +607 -373
  351. claude_mpm/services/socketio/handlers/hook.py +185 -0
  352. claude_mpm/services/socketio/handlers/memory.py +4 -4
  353. claude_mpm/services/socketio/handlers/project.py +4 -4
  354. claude_mpm/services/socketio/handlers/registry.py +53 -38
  355. claude_mpm/services/socketio/server/__init__.py +18 -0
  356. claude_mpm/services/socketio/server/broadcaster.py +252 -0
  357. claude_mpm/services/socketio/server/core.py +399 -0
  358. claude_mpm/services/socketio/server/main.py +323 -0
  359. claude_mpm/services/socketio_client_manager.py +160 -133
  360. claude_mpm/services/socketio_server.py +36 -1885
  361. claude_mpm/services/subprocess_launcher_service.py +316 -0
  362. claude_mpm/services/system_instructions_service.py +258 -0
  363. claude_mpm/services/ticket_manager.py +19 -533
  364. claude_mpm/services/utility_service.py +285 -0
  365. claude_mpm/services/version_control/__init__.py +18 -21
  366. claude_mpm/services/version_control/branch_strategy.py +20 -10
  367. claude_mpm/services/version_control/conflict_resolution.py +37 -13
  368. claude_mpm/services/version_control/git_operations.py +52 -21
  369. claude_mpm/services/version_control/semantic_versioning.py +92 -53
  370. claude_mpm/services/version_control/version_parser.py +145 -125
  371. claude_mpm/services/version_service.py +270 -0
  372. claude_mpm/storage/__init__.py +2 -2
  373. claude_mpm/storage/state_storage.py +177 -181
  374. claude_mpm/ticket_wrapper.py +2 -2
  375. claude_mpm/utils/__init__.py +2 -2
  376. claude_mpm/utils/agent_dependency_loader.py +453 -243
  377. claude_mpm/utils/config_manager.py +157 -118
  378. claude_mpm/utils/console.py +1 -1
  379. claude_mpm/utils/dependency_cache.py +102 -107
  380. claude_mpm/utils/dependency_manager.py +52 -47
  381. claude_mpm/utils/dependency_strategies.py +131 -96
  382. claude_mpm/utils/environment_context.py +110 -102
  383. claude_mpm/utils/error_handler.py +75 -55
  384. claude_mpm/utils/file_utils.py +80 -67
  385. claude_mpm/utils/framework_detection.py +12 -11
  386. claude_mpm/utils/import_migration_example.py +12 -60
  387. claude_mpm/utils/imports.py +48 -45
  388. claude_mpm/utils/path_operations.py +100 -93
  389. claude_mpm/utils/robust_installer.py +172 -164
  390. claude_mpm/utils/session_logging.py +30 -23
  391. claude_mpm/utils/subprocess_utils.py +99 -61
  392. claude_mpm/validation/__init__.py +1 -1
  393. claude_mpm/validation/agent_validator.py +151 -111
  394. claude_mpm/validation/frontmatter_validator.py +92 -71
  395. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/METADATA +90 -22
  396. claude_mpm-4.0.4.dist-info/RECORD +417 -0
  397. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/entry_points.txt +1 -0
  398. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/licenses/LICENSE +1 -1
  399. claude_mpm/cli/commands/run_guarded.py +0 -511
  400. claude_mpm/config/memory_guardian_config.py +0 -325
  401. claude_mpm/config/memory_guardian_yaml.py +0 -335
  402. claude_mpm/core/config_paths.py +0 -150
  403. claude_mpm/core/memory_aware_runner.py +0 -353
  404. claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
  405. claude_mpm/deployment_paths.py +0 -261
  406. claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
  407. claude_mpm/models/state_models.py +0 -433
  408. claude_mpm/services/agent/__init__.py +0 -24
  409. claude_mpm/services/agent/deployment.py +0 -2548
  410. claude_mpm/services/agent/management.py +0 -598
  411. claude_mpm/services/agent/registry.py +0 -813
  412. claude_mpm/services/agents/registry/agent_registry.py +0 -813
  413. claude_mpm/services/communication/socketio.py +0 -1935
  414. claude_mpm/services/communication/websocket.py +0 -479
  415. claude_mpm/services/framework_claude_md_generator.py +0 -624
  416. claude_mpm/services/health_monitor.py +0 -893
  417. claude_mpm/services/infrastructure/graceful_degradation.py +0 -616
  418. claude_mpm/services/infrastructure/health_monitor.py +0 -775
  419. claude_mpm/services/infrastructure/memory_dashboard.py +0 -479
  420. claude_mpm/services/infrastructure/memory_guardian.py +0 -944
  421. claude_mpm/services/infrastructure/restart_protection.py +0 -642
  422. claude_mpm/services/infrastructure/state_manager.py +0 -774
  423. claude_mpm/services/mcp_gateway/manager.py +0 -334
  424. claude_mpm/services/optimized_hook_service.py +0 -542
  425. claude_mpm/services/project_analyzer.py +0 -864
  426. claude_mpm/services/project_registry.py +0 -608
  427. claude_mpm/services/standalone_socketio_server.py +0 -1300
  428. claude_mpm/services/ticket_manager_di.py +0 -318
  429. claude_mpm/services/ticketing_service_original.py +0 -510
  430. claude_mpm/utils/paths.py +0 -395
  431. claude_mpm/utils/platform_memory.py +0 -524
  432. claude_mpm-3.9.11.dist-info/RECORD +0 -306
  433. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/WHEEL +0 -0
  434. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/top_level.txt +0 -0
@@ -1,775 +0,0 @@
1
- """Health monitoring service for Memory Guardian system.
2
-
3
- Provides comprehensive health checks including system resources, process health,
4
- and integration with existing monitoring infrastructure.
5
- """
6
-
7
- import asyncio
8
- import os
9
- import platform
10
- import psutil
11
- import shutil
12
- import socket
13
- import time
14
- from dataclasses import dataclass
15
- from datetime import datetime
16
- from enum import Enum
17
- from pathlib import Path
18
- from typing import Dict, List, Optional, Any, Callable
19
-
20
- from claude_mpm.services.core.base import BaseService
21
-
22
-
23
- class HealthStatus(Enum):
24
- """Health check status levels."""
25
- HEALTHY = "healthy"
26
- DEGRADED = "degraded"
27
- UNHEALTHY = "unhealthy"
28
- CRITICAL = "critical"
29
-
30
-
31
- class CheckType(Enum):
32
- """Types of health checks."""
33
- SYSTEM_RESOURCES = "system_resources"
34
- CPU_USAGE = "cpu_usage"
35
- MEMORY_USAGE = "memory_usage"
36
- DISK_SPACE = "disk_space"
37
- NETWORK = "network"
38
- PROCESS = "process"
39
- DEPENDENCIES = "dependencies"
40
- CUSTOM = "custom"
41
-
42
-
43
- @dataclass
44
- class HealthCheck:
45
- """Individual health check result."""
46
- name: str
47
- check_type: CheckType
48
- status: HealthStatus
49
- message: str
50
- details: Dict[str, Any]
51
- timestamp: float
52
- duration_ms: float
53
-
54
- def to_dict(self) -> Dict[str, Any]:
55
- """Convert to dictionary."""
56
- return {
57
- 'name': self.name,
58
- 'type': self.check_type.value,
59
- 'status': self.status.value,
60
- 'message': self.message,
61
- 'details': self.details,
62
- 'timestamp': self.timestamp,
63
- 'timestamp_iso': datetime.fromtimestamp(self.timestamp).isoformat(),
64
- 'duration_ms': round(self.duration_ms, 2)
65
- }
66
-
67
-
68
- @dataclass
69
- class SystemHealth:
70
- """Overall system health status."""
71
- status: HealthStatus
72
- checks: List[HealthCheck]
73
- timestamp: float
74
-
75
- @property
76
- def healthy_checks(self) -> int:
77
- """Count of healthy checks."""
78
- return sum(1 for c in self.checks if c.status == HealthStatus.HEALTHY)
79
-
80
- @property
81
- def total_checks(self) -> int:
82
- """Total number of checks."""
83
- return len(self.checks)
84
-
85
- @property
86
- def health_percentage(self) -> float:
87
- """Health percentage (0-100)."""
88
- if self.total_checks == 0:
89
- return 0.0
90
- return (self.healthy_checks / self.total_checks) * 100
91
-
92
- def to_dict(self) -> Dict[str, Any]:
93
- """Convert to dictionary."""
94
- return {
95
- 'status': self.status.value,
96
- 'health_percentage': round(self.health_percentage, 1),
97
- 'healthy_checks': self.healthy_checks,
98
- 'total_checks': self.total_checks,
99
- 'checks': [c.to_dict() for c in self.checks],
100
- 'timestamp': self.timestamp,
101
- 'timestamp_iso': datetime.fromtimestamp(self.timestamp).isoformat()
102
- }
103
-
104
-
105
- class HealthMonitor(BaseService):
106
- """Service for monitoring system and application health."""
107
-
108
- def __init__(
109
- self,
110
- cpu_threshold_percent: float = 80.0,
111
- memory_threshold_percent: float = 90.0,
112
- disk_threshold_percent: float = 90.0,
113
- min_disk_space_gb: float = 1.0,
114
- check_interval_seconds: int = 30,
115
- state_dir: Optional[Path] = None
116
- ):
117
- """Initialize health monitor service.
118
-
119
- Args:
120
- cpu_threshold_percent: CPU usage threshold for degradation
121
- memory_threshold_percent: Memory usage threshold for degradation
122
- disk_threshold_percent: Disk usage threshold for degradation
123
- min_disk_space_gb: Minimum required disk space in GB
124
- check_interval_seconds: Interval between health checks
125
- state_dir: Directory for state files
126
- """
127
- super().__init__("HealthMonitor")
128
-
129
- # Configuration
130
- self.cpu_threshold = cpu_threshold_percent
131
- self.memory_threshold = memory_threshold_percent
132
- self.disk_threshold = disk_threshold_percent
133
- self.min_disk_space_gb = min_disk_space_gb
134
- self.check_interval = check_interval_seconds
135
- self.state_dir = state_dir or Path.home() / ".claude-mpm" / "health"
136
-
137
- # Health check registry
138
- self.health_checks: Dict[str, Callable] = {}
139
- self.custom_checks: List[Callable] = []
140
-
141
- # State tracking
142
- self.last_check: Optional[SystemHealth] = None
143
- self.check_history: List[SystemHealth] = []
144
- self.monitoring_task: Optional[asyncio.Task] = None
145
- self.monitoring_active = False
146
-
147
- # Process monitoring
148
- self.monitored_pid: Optional[int] = None
149
- self.monitored_process: Optional[psutil.Process] = None
150
-
151
- # Register default health checks
152
- self._register_default_checks()
153
-
154
- self.log_info(
155
- f"Health monitor initialized: "
156
- f"CPU={cpu_threshold_percent}%, "
157
- f"Memory={memory_threshold_percent}%, "
158
- f"Disk={disk_threshold_percent}%"
159
- )
160
-
161
- async def initialize(self) -> bool:
162
- """Initialize the health monitor service.
163
-
164
- Returns:
165
- True if initialization successful
166
- """
167
- try:
168
- self.log_info("Initializing health monitor service")
169
-
170
- # Create state directory
171
- self.state_dir.mkdir(parents=True, exist_ok=True)
172
-
173
- # Verify system capabilities
174
- if not self._verify_system_capabilities():
175
- self.log_warning("Some system capabilities unavailable, running in degraded mode")
176
-
177
- # Start monitoring if configured
178
- if self.check_interval > 0:
179
- self.start_monitoring()
180
-
181
- self._initialized = True
182
- self.log_info("Health monitor service initialized successfully")
183
- return True
184
-
185
- except Exception as e:
186
- self.log_error(f"Failed to initialize health monitor: {e}")
187
- return False
188
-
189
- async def shutdown(self) -> None:
190
- """Shutdown the health monitor service."""
191
- try:
192
- self.log_info("Shutting down health monitor service")
193
-
194
- # Stop monitoring
195
- await self.stop_monitoring()
196
-
197
- self._shutdown = True
198
- self.log_info("Health monitor service shutdown complete")
199
-
200
- except Exception as e:
201
- self.log_error(f"Error during health monitor shutdown: {e}")
202
-
203
- def set_monitored_process(self, pid: int) -> bool:
204
- """Set the process to monitor.
205
-
206
- Args:
207
- pid: Process ID to monitor
208
-
209
- Returns:
210
- True if process found and set
211
- """
212
- try:
213
- self.monitored_process = psutil.Process(pid)
214
- self.monitored_pid = pid
215
- self.log_info(f"Monitoring process {pid}")
216
- return True
217
- except psutil.NoSuchProcess:
218
- self.log_error(f"Process {pid} not found")
219
- return False
220
- except Exception as e:
221
- self.log_error(f"Error setting monitored process: {e}")
222
- return False
223
-
224
- async def check_health(self) -> SystemHealth:
225
- """Perform all health checks.
226
-
227
- Returns:
228
- SystemHealth object with results
229
- """
230
- checks = []
231
- start_time = time.time()
232
-
233
- # Run system resource checks
234
- checks.append(await self._check_cpu_usage())
235
- checks.append(await self._check_memory_usage())
236
- checks.append(await self._check_disk_space())
237
-
238
- # Run network check
239
- checks.append(await self._check_network())
240
-
241
- # Run process check if configured
242
- if self.monitored_process:
243
- checks.append(await self._check_process_health())
244
-
245
- # Run dependency checks
246
- checks.append(await self._check_dependencies())
247
-
248
- # Run custom checks
249
- for check_func in self.custom_checks:
250
- try:
251
- result = await check_func()
252
- if isinstance(result, HealthCheck):
253
- checks.append(result)
254
- except Exception as e:
255
- self.log_error(f"Custom health check failed: {e}")
256
-
257
- # Determine overall status
258
- status = self._determine_overall_status(checks)
259
-
260
- # Create health report
261
- health = SystemHealth(
262
- status=status,
263
- checks=checks,
264
- timestamp=start_time
265
- )
266
-
267
- # Update state
268
- self.last_check = health
269
- self.check_history.append(health)
270
-
271
- # Trim history
272
- if len(self.check_history) > 100:
273
- self.check_history = self.check_history[-100:]
274
-
275
- return health
276
-
277
- async def validate_before_start(self) -> tuple[bool, str]:
278
- """Validate system resources before starting monitoring.
279
-
280
- Returns:
281
- Tuple of (valid, message)
282
- """
283
- # Check available memory
284
- mem = psutil.virtual_memory()
285
- if mem.available < 500 * 1024 * 1024: # Less than 500MB
286
- return False, f"Insufficient memory: {mem.available / (1024*1024):.0f}MB available"
287
-
288
- # Check disk space
289
- disk = shutil.disk_usage(self.state_dir)
290
- if disk.free < self.min_disk_space_gb * 1024 * 1024 * 1024:
291
- return False, f"Insufficient disk space: {disk.free / (1024*1024*1024):.1f}GB available"
292
-
293
- # Check CPU load
294
- cpu_percent = psutil.cpu_percent(interval=0.1)
295
- if cpu_percent > 95:
296
- return False, f"CPU overloaded: {cpu_percent:.0f}% usage"
297
-
298
- return True, "System resources adequate"
299
-
300
- def start_monitoring(self) -> None:
301
- """Start continuous health monitoring."""
302
- if self.monitoring_active:
303
- self.log_warning("Health monitoring already active")
304
- return
305
-
306
- self.monitoring_active = True
307
- self.monitoring_task = asyncio.create_task(self._monitoring_loop())
308
- self.log_info("Started health monitoring")
309
-
310
- async def stop_monitoring(self) -> None:
311
- """Stop continuous health monitoring."""
312
- if not self.monitoring_active:
313
- return
314
-
315
- self.monitoring_active = False
316
-
317
- if self.monitoring_task:
318
- self.monitoring_task.cancel()
319
- try:
320
- await self.monitoring_task
321
- except asyncio.CancelledError:
322
- pass
323
- self.monitoring_task = None
324
-
325
- self.log_info("Stopped health monitoring")
326
-
327
- def register_health_check(self, name: str, check_func: Callable) -> None:
328
- """Register a custom health check.
329
-
330
- Args:
331
- name: Name of the health check
332
- check_func: Async function that returns HealthCheck
333
- """
334
- self.custom_checks.append(check_func)
335
- self.log_info(f"Registered custom health check: {name}")
336
-
337
- def get_health_status(self) -> Optional[SystemHealth]:
338
- """Get the last health check result.
339
-
340
- Returns:
341
- Last SystemHealth or None
342
- """
343
- return self.last_check
344
-
345
- def get_health_history(self, limit: int = 10) -> List[SystemHealth]:
346
- """Get health check history.
347
-
348
- Args:
349
- limit: Maximum number of records to return
350
-
351
- Returns:
352
- List of SystemHealth objects
353
- """
354
- return self.check_history[-limit:]
355
-
356
- async def _check_cpu_usage(self) -> HealthCheck:
357
- """Check CPU usage."""
358
- start = time.time()
359
-
360
- try:
361
- cpu_percent = psutil.cpu_percent(interval=0.1)
362
- cpu_count = psutil.cpu_count()
363
-
364
- if cpu_percent >= 95:
365
- status = HealthStatus.CRITICAL
366
- message = f"CPU critically high: {cpu_percent:.1f}%"
367
- elif cpu_percent >= self.cpu_threshold:
368
- status = HealthStatus.DEGRADED
369
- message = f"CPU usage high: {cpu_percent:.1f}%"
370
- else:
371
- status = HealthStatus.HEALTHY
372
- message = f"CPU usage normal: {cpu_percent:.1f}%"
373
-
374
- return HealthCheck(
375
- name="CPU Usage",
376
- check_type=CheckType.CPU_USAGE,
377
- status=status,
378
- message=message,
379
- details={
380
- 'cpu_percent': cpu_percent,
381
- 'cpu_count': cpu_count,
382
- 'threshold': self.cpu_threshold
383
- },
384
- timestamp=start,
385
- duration_ms=(time.time() - start) * 1000
386
- )
387
-
388
- except Exception as e:
389
- return HealthCheck(
390
- name="CPU Usage",
391
- check_type=CheckType.CPU_USAGE,
392
- status=HealthStatus.UNHEALTHY,
393
- message=f"Failed to check CPU: {e}",
394
- details={'error': str(e)},
395
- timestamp=start,
396
- duration_ms=(time.time() - start) * 1000
397
- )
398
-
399
- async def _check_memory_usage(self) -> HealthCheck:
400
- """Check memory usage."""
401
- start = time.time()
402
-
403
- try:
404
- mem = psutil.virtual_memory()
405
-
406
- if mem.percent >= 95:
407
- status = HealthStatus.CRITICAL
408
- message = f"Memory critically high: {mem.percent:.1f}%"
409
- elif mem.percent >= self.memory_threshold:
410
- status = HealthStatus.DEGRADED
411
- message = f"Memory usage high: {mem.percent:.1f}%"
412
- else:
413
- status = HealthStatus.HEALTHY
414
- message = f"Memory usage normal: {mem.percent:.1f}%"
415
-
416
- return HealthCheck(
417
- name="Memory Usage",
418
- check_type=CheckType.MEMORY_USAGE,
419
- status=status,
420
- message=message,
421
- details={
422
- 'memory_percent': mem.percent,
423
- 'available_mb': mem.available / (1024 * 1024),
424
- 'total_mb': mem.total / (1024 * 1024),
425
- 'threshold': self.memory_threshold
426
- },
427
- timestamp=start,
428
- duration_ms=(time.time() - start) * 1000
429
- )
430
-
431
- except Exception as e:
432
- return HealthCheck(
433
- name="Memory Usage",
434
- check_type=CheckType.MEMORY_USAGE,
435
- status=HealthStatus.UNHEALTHY,
436
- message=f"Failed to check memory: {e}",
437
- details={'error': str(e)},
438
- timestamp=start,
439
- duration_ms=(time.time() - start) * 1000
440
- )
441
-
442
- async def _check_disk_space(self) -> HealthCheck:
443
- """Check disk space."""
444
- start = time.time()
445
-
446
- try:
447
- # Check disk where state directory is located
448
- disk = shutil.disk_usage(self.state_dir)
449
- disk_percent = (disk.used / disk.total) * 100
450
- free_gb = disk.free / (1024 * 1024 * 1024)
451
-
452
- if free_gb < self.min_disk_space_gb:
453
- status = HealthStatus.CRITICAL
454
- message = f"Disk space critical: {free_gb:.1f}GB free"
455
- elif disk_percent >= self.disk_threshold:
456
- status = HealthStatus.DEGRADED
457
- message = f"Disk usage high: {disk_percent:.1f}%"
458
- else:
459
- status = HealthStatus.HEALTHY
460
- message = f"Disk space adequate: {free_gb:.1f}GB free"
461
-
462
- return HealthCheck(
463
- name="Disk Space",
464
- check_type=CheckType.DISK_SPACE,
465
- status=status,
466
- message=message,
467
- details={
468
- 'disk_percent': disk_percent,
469
- 'free_gb': free_gb,
470
- 'total_gb': disk.total / (1024 * 1024 * 1024),
471
- 'threshold': self.disk_threshold,
472
- 'min_space_gb': self.min_disk_space_gb,
473
- 'path': str(self.state_dir)
474
- },
475
- timestamp=start,
476
- duration_ms=(time.time() - start) * 1000
477
- )
478
-
479
- except Exception as e:
480
- return HealthCheck(
481
- name="Disk Space",
482
- check_type=CheckType.DISK_SPACE,
483
- status=HealthStatus.UNHEALTHY,
484
- message=f"Failed to check disk: {e}",
485
- details={'error': str(e)},
486
- timestamp=start,
487
- duration_ms=(time.time() - start) * 1000
488
- )
489
-
490
- async def _check_network(self) -> HealthCheck:
491
- """Check network connectivity."""
492
- start = time.time()
493
-
494
- try:
495
- # Try to connect to common DNS servers
496
- test_hosts = [
497
- ('8.8.8.8', 53), # Google DNS
498
- ('1.1.1.1', 53), # Cloudflare DNS
499
- ]
500
-
501
- connected = False
502
- for host, port in test_hosts:
503
- try:
504
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
505
- sock.settimeout(2)
506
- result = sock.connect_ex((host, port))
507
- sock.close()
508
- if result == 0:
509
- connected = True
510
- break
511
- except:
512
- continue
513
-
514
- if connected:
515
- status = HealthStatus.HEALTHY
516
- message = "Network connectivity OK"
517
- else:
518
- status = HealthStatus.DEGRADED
519
- message = "Network connectivity limited"
520
-
521
- return HealthCheck(
522
- name="Network",
523
- check_type=CheckType.NETWORK,
524
- status=status,
525
- message=message,
526
- details={'connected': connected},
527
- timestamp=start,
528
- duration_ms=(time.time() - start) * 1000
529
- )
530
-
531
- except Exception as e:
532
- return HealthCheck(
533
- name="Network",
534
- check_type=CheckType.NETWORK,
535
- status=HealthStatus.UNHEALTHY,
536
- message=f"Failed to check network: {e}",
537
- details={'error': str(e)},
538
- timestamp=start,
539
- duration_ms=(time.time() - start) * 1000
540
- )
541
-
542
- async def _check_process_health(self) -> HealthCheck:
543
- """Check monitored process health."""
544
- start = time.time()
545
-
546
- try:
547
- if not self.monitored_process:
548
- return HealthCheck(
549
- name="Process Health",
550
- check_type=CheckType.PROCESS,
551
- status=HealthStatus.HEALTHY,
552
- message="No process monitored",
553
- details={},
554
- timestamp=start,
555
- duration_ms=(time.time() - start) * 1000
556
- )
557
-
558
- # Check if process is running
559
- if not self.monitored_process.is_running():
560
- return HealthCheck(
561
- name="Process Health",
562
- check_type=CheckType.PROCESS,
563
- status=HealthStatus.CRITICAL,
564
- message=f"Process {self.monitored_pid} not running",
565
- details={'pid': self.monitored_pid},
566
- timestamp=start,
567
- duration_ms=(time.time() - start) * 1000
568
- )
569
-
570
- # Get process info
571
- with self.monitored_process.oneshot():
572
- cpu_percent = self.monitored_process.cpu_percent()
573
- mem_info = self.monitored_process.memory_info()
574
- mem_mb = mem_info.rss / (1024 * 1024)
575
- status_str = self.monitored_process.status()
576
-
577
- # Determine health based on process status
578
- if status_str in ['zombie', 'dead']:
579
- status = HealthStatus.CRITICAL
580
- message = f"Process in {status_str} state"
581
- elif cpu_percent > 90:
582
- status = HealthStatus.DEGRADED
583
- message = f"Process CPU high: {cpu_percent:.1f}%"
584
- else:
585
- status = HealthStatus.HEALTHY
586
- message = f"Process healthy (PID: {self.monitored_pid})"
587
-
588
- return HealthCheck(
589
- name="Process Health",
590
- check_type=CheckType.PROCESS,
591
- status=status,
592
- message=message,
593
- details={
594
- 'pid': self.monitored_pid,
595
- 'cpu_percent': cpu_percent,
596
- 'memory_mb': mem_mb,
597
- 'status': status_str
598
- },
599
- timestamp=start,
600
- duration_ms=(time.time() - start) * 1000
601
- )
602
-
603
- except psutil.NoSuchProcess:
604
- return HealthCheck(
605
- name="Process Health",
606
- check_type=CheckType.PROCESS,
607
- status=HealthStatus.CRITICAL,
608
- message=f"Process {self.monitored_pid} not found",
609
- details={'pid': self.monitored_pid},
610
- timestamp=start,
611
- duration_ms=(time.time() - start) * 1000
612
- )
613
- except Exception as e:
614
- return HealthCheck(
615
- name="Process Health",
616
- check_type=CheckType.PROCESS,
617
- status=HealthStatus.UNHEALTHY,
618
- message=f"Failed to check process: {e}",
619
- details={'error': str(e)},
620
- timestamp=start,
621
- duration_ms=(time.time() - start) * 1000
622
- )
623
-
624
- async def _check_dependencies(self) -> HealthCheck:
625
- """Check critical dependencies."""
626
- start = time.time()
627
-
628
- try:
629
- missing = []
630
-
631
- # Check for psutil (critical dependency)
632
- try:
633
- import psutil
634
- except ImportError:
635
- missing.append('psutil')
636
-
637
- if missing:
638
- status = HealthStatus.DEGRADED
639
- message = f"Missing dependencies: {', '.join(missing)}"
640
- else:
641
- status = HealthStatus.HEALTHY
642
- message = "All dependencies available"
643
-
644
- return HealthCheck(
645
- name="Dependencies",
646
- check_type=CheckType.DEPENDENCIES,
647
- status=status,
648
- message=message,
649
- details={'missing': missing},
650
- timestamp=start,
651
- duration_ms=(time.time() - start) * 1000
652
- )
653
-
654
- except Exception as e:
655
- return HealthCheck(
656
- name="Dependencies",
657
- check_type=CheckType.DEPENDENCIES,
658
- status=HealthStatus.UNHEALTHY,
659
- message=f"Failed to check dependencies: {e}",
660
- details={'error': str(e)},
661
- timestamp=start,
662
- duration_ms=(time.time() - start) * 1000
663
- )
664
-
665
- def _register_default_checks(self) -> None:
666
- """Register default health checks."""
667
- # Default checks are implemented as methods
668
- pass
669
-
670
- def _verify_system_capabilities(self) -> bool:
671
- """Verify system monitoring capabilities.
672
-
673
- Returns:
674
- True if all capabilities available
675
- """
676
- capabilities = {
677
- 'psutil': False,
678
- 'cpu': False,
679
- 'memory': False,
680
- 'disk': False,
681
- 'network': False
682
- }
683
-
684
- try:
685
- import psutil
686
- capabilities['psutil'] = True
687
-
688
- # Test CPU monitoring
689
- try:
690
- psutil.cpu_percent(interval=0.1)
691
- capabilities['cpu'] = True
692
- except:
693
- pass
694
-
695
- # Test memory monitoring
696
- try:
697
- psutil.virtual_memory()
698
- capabilities['memory'] = True
699
- except:
700
- pass
701
-
702
- # Test disk monitoring
703
- try:
704
- shutil.disk_usage('/')
705
- capabilities['disk'] = True
706
- except:
707
- pass
708
-
709
- # Test network monitoring
710
- try:
711
- socket.socket(socket.AF_INET, socket.SOCK_STREAM)
712
- capabilities['network'] = True
713
- except:
714
- pass
715
-
716
- except ImportError:
717
- self.log_warning("psutil not available, running in degraded mode")
718
-
719
- # Log capabilities
720
- for cap, available in capabilities.items():
721
- if not available:
722
- self.log_warning(f"System capability unavailable: {cap}")
723
-
724
- return all(capabilities.values())
725
-
726
- def _determine_overall_status(self, checks: List[HealthCheck]) -> HealthStatus:
727
- """Determine overall health status from individual checks.
728
-
729
- Args:
730
- checks: List of health check results
731
-
732
- Returns:
733
- Overall HealthStatus
734
- """
735
- if not checks:
736
- return HealthStatus.HEALTHY
737
-
738
- # Count status types
739
- critical_count = sum(1 for c in checks if c.status == HealthStatus.CRITICAL)
740
- unhealthy_count = sum(1 for c in checks if c.status == HealthStatus.UNHEALTHY)
741
- degraded_count = sum(1 for c in checks if c.status == HealthStatus.DEGRADED)
742
-
743
- # Determine overall status
744
- if critical_count > 0:
745
- return HealthStatus.CRITICAL
746
- elif unhealthy_count > 0:
747
- return HealthStatus.UNHEALTHY
748
- elif degraded_count > 0:
749
- return HealthStatus.DEGRADED
750
- else:
751
- return HealthStatus.HEALTHY
752
-
753
- async def _monitoring_loop(self) -> None:
754
- """Continuous health monitoring loop."""
755
- try:
756
- while self.monitoring_active:
757
- try:
758
- # Perform health checks
759
- health = await self.check_health()
760
-
761
- # Log if status changed
762
- if self.check_history and len(self.check_history) > 1:
763
- prev_status = self.check_history[-2].status
764
- if health.status != prev_status:
765
- self.log_info(f"Health status changed: {prev_status.value} -> {health.status.value}")
766
-
767
- # Wait for next check
768
- await asyncio.sleep(self.check_interval)
769
-
770
- except Exception as e:
771
- self.log_error(f"Error in health monitoring loop: {e}")
772
- await asyncio.sleep(self.check_interval)
773
-
774
- except asyncio.CancelledError:
775
- self.log_debug("Health monitoring loop cancelled")