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,774 +0,0 @@
1
- """State Manager service for capturing and restoring execution state.
2
-
3
- This service handles comprehensive state management for Claude Code,
4
- enabling seamless restarts with preserved context.
5
-
6
- Design Principles:
7
- - Atomic state operations with write-to-temp-then-rename
8
- - Automatic cleanup of old state files
9
- - Privacy-preserving (sanitizes sensitive data)
10
- - Platform-agnostic implementation
11
- - Graceful degradation on failures
12
- """
13
-
14
- import asyncio
15
- import json
16
- import logging
17
- import os
18
- import pickle
19
- import platform
20
- import shutil
21
- import subprocess
22
- import sys
23
- import tempfile
24
- import time
25
- from datetime import datetime, timedelta
26
- from pathlib import Path
27
- from typing import Dict, Any, List, Optional, Tuple
28
- import uuid
29
- import gzip
30
-
31
- from claude_mpm.services.core.base import BaseService
32
- from claude_mpm.models.state_models import (
33
- ProcessState,
34
- ConversationState,
35
- ConversationContext,
36
- ProjectState,
37
- RestartState,
38
- CompleteState,
39
- StateType
40
- )
41
- from claude_mpm.utils.platform_memory import get_process_memory
42
-
43
-
44
- class StateManager(BaseService):
45
- """Service for managing Claude Code execution state across restarts."""
46
-
47
- def __init__(self, state_dir: Optional[Path] = None):
48
- """Initialize State Manager service.
49
-
50
- Args:
51
- state_dir: Directory for storing state files (default: ~/.claude-mpm/state)
52
- """
53
- super().__init__("StateManager")
54
-
55
- # State storage configuration
56
- self.state_dir = state_dir or Path.home() / ".claude-mpm" / "state"
57
- self.state_dir.mkdir(parents=True, exist_ok=True)
58
-
59
- # File naming
60
- self.current_state_file = self.state_dir / "current_state.json"
61
- self.compressed_state_file = self.state_dir / "current_state.json.gz"
62
-
63
- # Retention policy
64
- self.retention_days = 7
65
- self.max_state_files = 50
66
-
67
- # Claude conversation paths
68
- self.claude_config_dir = Path.home() / ".claude"
69
- self.claude_json_path = self.claude_config_dir / ".claude.json"
70
-
71
- # State tracking
72
- self.current_state: Optional[CompleteState] = None
73
- self.last_capture_time: float = 0
74
- self.capture_cooldown = 5.0 # Minimum seconds between captures
75
-
76
- # Statistics
77
- self.capture_count = 0
78
- self.restore_count = 0
79
- self.cleanup_count = 0
80
-
81
- self.log_info(f"State Manager initialized with state directory: {self.state_dir}")
82
-
83
- async def initialize(self) -> bool:
84
- """Initialize the State Manager service.
85
-
86
- Returns:
87
- True if initialization successful
88
- """
89
- try:
90
- self.log_info("Initializing State Manager service")
91
-
92
- # Ensure state directory exists
93
- self.state_dir.mkdir(parents=True, exist_ok=True)
94
-
95
- # Cleanup old states on startup
96
- await self.cleanup_old_states()
97
-
98
- # Try to load existing state
99
- loaded_state = await self.load_state()
100
- if loaded_state:
101
- self.log_info(f"Loaded existing state: {loaded_state.state_id}")
102
- self.current_state = loaded_state
103
-
104
- self._initialized = True
105
- self.log_info("State Manager service initialized successfully")
106
- return True
107
-
108
- except Exception as e:
109
- self.log_error(f"Failed to initialize State Manager: {e}")
110
- return False
111
-
112
- async def shutdown(self) -> None:
113
- """Shutdown the State Manager service gracefully."""
114
- try:
115
- self.log_info("Shutting down State Manager service")
116
-
117
- # Capture final state before shutdown
118
- if self.current_state:
119
- await self.persist_state(self.current_state)
120
-
121
- self._shutdown = True
122
- self.log_info("State Manager service shutdown complete")
123
-
124
- except Exception as e:
125
- self.log_error(f"Error during State Manager shutdown: {e}")
126
-
127
- async def capture_state(self, restart_reason: str = "Manual") -> Optional[CompleteState]:
128
- """Capture current process and conversation state.
129
-
130
- Args:
131
- restart_reason: Reason for the state capture/restart
132
-
133
- Returns:
134
- CompleteState object or None if capture failed
135
- """
136
- try:
137
- # Check cooldown
138
- if time.time() - self.last_capture_time < self.capture_cooldown:
139
- self.log_debug("State capture skipped due to cooldown")
140
- return self.current_state
141
-
142
- self.log_info(f"Capturing state: {restart_reason}")
143
-
144
- # Capture process state
145
- process_state = await self._capture_process_state()
146
-
147
- # Capture conversation state
148
- conversation_state = await self._capture_conversation_state()
149
-
150
- # Capture project state
151
- project_state = await self._capture_project_state()
152
-
153
- # Create restart state
154
- restart_state = self._create_restart_state(restart_reason, process_state)
155
-
156
- # Create complete state
157
- state = CompleteState(
158
- process_state=process_state,
159
- conversation_state=conversation_state,
160
- project_state=project_state,
161
- restart_state=restart_state
162
- )
163
-
164
- # Validate state
165
- issues = state.validate()
166
- if issues:
167
- for issue in issues:
168
- self.log_warning(f"State validation issue: {issue}")
169
-
170
- # Update tracking
171
- self.current_state = state
172
- self.last_capture_time = time.time()
173
- self.capture_count += 1
174
-
175
- self.log_info(f"State captured successfully: {state.state_id}")
176
- return state
177
-
178
- except Exception as e:
179
- self.log_error(f"Failed to capture state: {e}")
180
- return None
181
-
182
- async def restore_state(self, state: Optional[CompleteState] = None) -> bool:
183
- """Restore state after process restart.
184
-
185
- Args:
186
- state: State to restore (default: load from disk)
187
-
188
- Returns:
189
- True if restoration successful
190
- """
191
- try:
192
- # Load state if not provided
193
- if state is None:
194
- state = await self.load_state()
195
- if state is None:
196
- self.log_warning("No state available to restore")
197
- return False
198
-
199
- self.log_info(f"Restoring state: {state.state_id}")
200
-
201
- # Restore working directory
202
- if state.process_state.working_directory:
203
- try:
204
- os.chdir(state.process_state.working_directory)
205
- self.log_debug(f"Restored working directory: {state.process_state.working_directory}")
206
- except Exception as e:
207
- self.log_warning(f"Could not restore working directory: {e}")
208
-
209
- # Restore environment variables (non-sensitive only)
210
- for key, value in state.process_state.environment.items():
211
- if value != '***REDACTED***':
212
- os.environ[key] = value
213
-
214
- # Restore project-specific environment
215
- if state.project_state.environment_vars:
216
- for key, value in state.project_state.environment_vars.items():
217
- if value != '***REDACTED***':
218
- os.environ[key] = value
219
-
220
- # Log restoration summary
221
- self.log_info(f"State restoration complete:")
222
- self.log_info(f" - Working directory: {state.process_state.working_directory}")
223
- self.log_info(f" - Git branch: {state.project_state.git_branch}")
224
- self.log_info(f" - Open files: {len(state.conversation_state.open_files)}")
225
- self.log_info(f" - Active conversation: {state.conversation_state.active_conversation_id}")
226
-
227
- self.restore_count += 1
228
- return True
229
-
230
- except Exception as e:
231
- self.log_error(f"Failed to restore state: {e}")
232
- return False
233
-
234
- async def persist_state(self, state: CompleteState, compress: bool = True) -> bool:
235
- """Save state to disk atomically.
236
-
237
- Args:
238
- state: State to persist
239
- compress: Whether to compress the state file
240
-
241
- Returns:
242
- True if persistence successful
243
- """
244
- try:
245
- self.log_debug(f"Persisting state: {state.state_id}")
246
-
247
- # Convert state to dictionary
248
- state_dict = state.to_dict()
249
-
250
- # Create temporary file
251
- temp_fd, temp_path = tempfile.mkstemp(
252
- dir=self.state_dir,
253
- suffix='.tmp',
254
- prefix='state_'
255
- )
256
-
257
- try:
258
- # Write state to temporary file
259
- if compress:
260
- # Write compressed JSON
261
- with gzip.open(temp_path, 'wt', encoding='utf-8') as f:
262
- json.dump(state_dict, f, indent=2)
263
- target_path = self.compressed_state_file
264
- else:
265
- # Write plain JSON
266
- with os.fdopen(temp_fd, 'w') as f:
267
- json.dump(state_dict, f, indent=2)
268
- target_path = self.current_state_file
269
-
270
- # Atomic rename
271
- temp_path_obj = Path(temp_path)
272
- temp_path_obj.replace(target_path)
273
-
274
- # Also create timestamped backup
275
- backup_name = f"state_{state.state_id}.json"
276
- if compress:
277
- backup_name += ".gz"
278
- backup_path = self.state_dir / backup_name
279
- shutil.copy2(target_path, backup_path)
280
-
281
- self.log_debug(f"State persisted to {target_path}")
282
- return True
283
-
284
- finally:
285
- # Clean up temp file if it still exists
286
- if Path(temp_path).exists():
287
- os.unlink(temp_path)
288
-
289
- except Exception as e:
290
- self.log_error(f"Failed to persist state: {e}")
291
- return False
292
-
293
- async def load_state(self, state_file: Optional[Path] = None) -> Optional[CompleteState]:
294
- """Load state from disk with validation.
295
-
296
- Args:
297
- state_file: Path to state file (default: current_state.json[.gz])
298
-
299
- Returns:
300
- CompleteState object or None if load failed
301
- """
302
- try:
303
- # Determine which file to load
304
- if state_file is None:
305
- if self.compressed_state_file.exists():
306
- state_file = self.compressed_state_file
307
- elif self.current_state_file.exists():
308
- state_file = self.current_state_file
309
- else:
310
- self.log_debug("No state file found")
311
- return None
312
-
313
- self.log_debug(f"Loading state from {state_file}")
314
-
315
- # Read state file
316
- if str(state_file).endswith('.gz'):
317
- with gzip.open(state_file, 'rt', encoding='utf-8') as f:
318
- state_dict = json.load(f)
319
- else:
320
- with open(state_file, 'r') as f:
321
- state_dict = json.load(f)
322
-
323
- # Create state object
324
- state = CompleteState.from_dict(state_dict)
325
-
326
- # Validate state
327
- issues = state.validate()
328
- if issues:
329
- for issue in issues:
330
- self.log_warning(f"State validation issue: {issue}")
331
-
332
- self.log_info(f"Loaded state: {state.state_id}")
333
- return state
334
-
335
- except Exception as e:
336
- self.log_error(f"Failed to load state: {e}")
337
- return None
338
-
339
- async def cleanup_old_states(self) -> int:
340
- """Remove states older than retention period.
341
-
342
- Returns:
343
- Number of files removed
344
- """
345
- try:
346
- self.log_debug("Cleaning up old state files")
347
-
348
- removed_count = 0
349
- cutoff_time = datetime.now() - timedelta(days=self.retention_days)
350
-
351
- # Find all state files
352
- state_files = list(self.state_dir.glob("state_*.json*"))
353
-
354
- # Sort by modification time
355
- state_files.sort(key=lambda f: f.stat().st_mtime)
356
-
357
- # Remove old files
358
- for state_file in state_files:
359
- try:
360
- # Check age
361
- file_time = datetime.fromtimestamp(state_file.stat().st_mtime)
362
- if file_time < cutoff_time:
363
- state_file.unlink()
364
- removed_count += 1
365
- self.log_debug(f"Removed old state file: {state_file.name}")
366
- except Exception as e:
367
- self.log_warning(f"Could not remove state file {state_file}: {e}")
368
-
369
- # Also enforce max file limit
370
- remaining_files = list(self.state_dir.glob("state_*.json*"))
371
- if len(remaining_files) > self.max_state_files:
372
- # Remove oldest files
373
- remaining_files.sort(key=lambda f: f.stat().st_mtime)
374
- for state_file in remaining_files[:-self.max_state_files]:
375
- try:
376
- state_file.unlink()
377
- removed_count += 1
378
- self.log_debug(f"Removed excess state file: {state_file.name}")
379
- except Exception as e:
380
- self.log_warning(f"Could not remove state file {state_file}: {e}")
381
-
382
- if removed_count > 0:
383
- self.log_info(f"Cleaned up {removed_count} old state files")
384
-
385
- self.cleanup_count += removed_count
386
- return removed_count
387
-
388
- except Exception as e:
389
- self.log_error(f"Error during state cleanup: {e}")
390
- return 0
391
-
392
- async def get_conversation_context(self) -> Optional[ConversationState]:
393
- """Extract relevant Claude conversation data.
394
-
395
- Returns:
396
- ConversationState object or None if extraction failed
397
- """
398
- try:
399
- # Check if Claude config exists
400
- if not self.claude_json_path.exists():
401
- self.log_debug("Claude configuration not found")
402
- return ConversationState(
403
- active_conversation_id=None,
404
- active_conversation=None,
405
- recent_conversations=[],
406
- total_conversations=0,
407
- total_storage_mb=0.0,
408
- preferences={},
409
- open_files=[],
410
- recent_files=[],
411
- pinned_files=[]
412
- )
413
-
414
- # Get file size
415
- file_size_mb = self.claude_json_path.stat().st_size / (1024 * 1024)
416
-
417
- # For large files, use streaming approach
418
- if file_size_mb > 100:
419
- self.log_warning(f"Large Claude config file ({file_size_mb:.2f}MB), using minimal extraction")
420
- return self._extract_minimal_conversation_state()
421
-
422
- # Load Claude configuration
423
- with open(self.claude_json_path, 'r') as f:
424
- claude_data = json.load(f)
425
-
426
- # Extract conversation information
427
- conversations = claude_data.get('conversations', [])
428
- active_conv_id = claude_data.get('activeConversationId')
429
-
430
- # Find active conversation
431
- active_conv = None
432
- if active_conv_id:
433
- for conv in conversations:
434
- if conv.get('id') == active_conv_id:
435
- active_conv = ConversationContext(
436
- conversation_id=conv.get('id', ''),
437
- title=conv.get('title', 'Untitled'),
438
- created_at=conv.get('createdAt', 0),
439
- updated_at=conv.get('updatedAt', 0),
440
- message_count=len(conv.get('messages', [])),
441
- total_tokens=conv.get('totalTokens', 0),
442
- max_tokens=conv.get('maxTokens', 100000),
443
- referenced_files=self._extract_referenced_files(conv),
444
- open_tabs=conv.get('openTabs', []),
445
- tags=conv.get('tags', []),
446
- is_active=True
447
- )
448
- break
449
-
450
- # Get recent conversations (last 5)
451
- recent_convs = []
452
- sorted_convs = sorted(
453
- conversations,
454
- key=lambda c: c.get('updatedAt', 0),
455
- reverse=True
456
- )[:5]
457
-
458
- for conv in sorted_convs:
459
- if conv.get('id') != active_conv_id:
460
- recent_convs.append(ConversationContext(
461
- conversation_id=conv.get('id', ''),
462
- title=conv.get('title', 'Untitled'),
463
- created_at=conv.get('createdAt', 0),
464
- updated_at=conv.get('updatedAt', 0),
465
- message_count=len(conv.get('messages', [])),
466
- total_tokens=conv.get('totalTokens', 0),
467
- max_tokens=conv.get('maxTokens', 100000),
468
- referenced_files=self._extract_referenced_files(conv),
469
- open_tabs=conv.get('openTabs', []),
470
- tags=conv.get('tags', []),
471
- is_active=False
472
- ))
473
-
474
- # Extract preferences
475
- preferences = claude_data.get('preferences', {})
476
-
477
- # Extract file state
478
- open_files = claude_data.get('openFiles', [])
479
- recent_files = claude_data.get('recentFiles', [])
480
- pinned_files = claude_data.get('pinnedFiles', [])
481
-
482
- return ConversationState(
483
- active_conversation_id=active_conv_id,
484
- active_conversation=active_conv,
485
- recent_conversations=recent_convs,
486
- total_conversations=len(conversations),
487
- total_storage_mb=file_size_mb,
488
- preferences=preferences,
489
- open_files=open_files,
490
- recent_files=recent_files,
491
- pinned_files=pinned_files
492
- )
493
-
494
- except Exception as e:
495
- self.log_error(f"Failed to extract conversation context: {e}")
496
- return None
497
-
498
- async def _capture_process_state(self) -> ProcessState:
499
- """Capture current process state."""
500
- try:
501
- pid = os.getpid()
502
-
503
- # Get memory info
504
- mem_info = get_process_memory(pid)
505
- memory_mb = mem_info.rss_mb if mem_info else 0.0
506
- cpu_percent = 0.0 # Would need psutil for accurate CPU%
507
-
508
- # Get command line
509
- if platform.system() != 'Windows':
510
- try:
511
- with open(f'/proc/{pid}/cmdline', 'r') as f:
512
- cmdline = f.read().replace('\0', ' ').strip().split()
513
- except:
514
- cmdline = sys.argv
515
- else:
516
- cmdline = sys.argv
517
-
518
- # Get open files (simplified - would need lsof or psutil for full list)
519
- open_files = []
520
-
521
- return ProcessState(
522
- pid=pid,
523
- parent_pid=os.getppid(),
524
- process_name=os.path.basename(sys.executable),
525
- command=cmdline[:1] if cmdline else [],
526
- args=cmdline[1:] if len(cmdline) > 1 else [],
527
- working_directory=os.getcwd(),
528
- environment=dict(os.environ),
529
- memory_mb=memory_mb,
530
- cpu_percent=cpu_percent,
531
- open_files=open_files,
532
- start_time=time.time() - time.process_time(),
533
- capture_time=time.time()
534
- )
535
-
536
- except Exception as e:
537
- self.log_error(f"Error capturing process state: {e}")
538
- # Return minimal state
539
- return ProcessState(
540
- pid=os.getpid(),
541
- parent_pid=os.getppid(),
542
- process_name="claude-mpm",
543
- command=sys.argv[:1],
544
- args=sys.argv[1:],
545
- working_directory=os.getcwd(),
546
- environment={},
547
- memory_mb=0.0,
548
- cpu_percent=0.0,
549
- open_files=[],
550
- start_time=time.time(),
551
- capture_time=time.time()
552
- )
553
-
554
- async def _capture_conversation_state(self) -> ConversationState:
555
- """Capture conversation state from Claude."""
556
- conversation_state = await self.get_conversation_context()
557
- return conversation_state or ConversationState(
558
- active_conversation_id=None,
559
- active_conversation=None,
560
- recent_conversations=[],
561
- total_conversations=0,
562
- total_storage_mb=0.0,
563
- preferences={},
564
- open_files=[],
565
- recent_files=[],
566
- pinned_files=[]
567
- )
568
-
569
- async def _capture_project_state(self) -> ProjectState:
570
- """Capture project and Git state."""
571
- try:
572
- project_path = os.getcwd()
573
- project_name = os.path.basename(project_path)
574
-
575
- # Get Git information
576
- git_branch = None
577
- git_commit = None
578
- git_status = {}
579
- git_remotes = {}
580
-
581
- try:
582
- # Get current branch
583
- result = subprocess.run(
584
- ['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
585
- capture_output=True,
586
- text=True,
587
- cwd=project_path
588
- )
589
- if result.returncode == 0:
590
- git_branch = result.stdout.strip()
591
-
592
- # Get current commit
593
- result = subprocess.run(
594
- ['git', 'rev-parse', 'HEAD'],
595
- capture_output=True,
596
- text=True,
597
- cwd=project_path
598
- )
599
- if result.returncode == 0:
600
- git_commit = result.stdout.strip()[:8]
601
-
602
- # Get status
603
- result = subprocess.run(
604
- ['git', 'status', '--porcelain'],
605
- capture_output=True,
606
- text=True,
607
- cwd=project_path
608
- )
609
- if result.returncode == 0:
610
- staged = []
611
- modified = []
612
- untracked = []
613
-
614
- for line in result.stdout.splitlines():
615
- if line.startswith('??'):
616
- untracked.append(line[3:])
617
- elif line.startswith(' M'):
618
- modified.append(line[3:])
619
- elif line.startswith('M '):
620
- staged.append(line[3:])
621
-
622
- git_status = {
623
- 'staged': staged,
624
- 'modified': modified,
625
- 'untracked': untracked
626
- }
627
-
628
- except Exception as e:
629
- self.log_debug(f"Could not get Git information: {e}")
630
-
631
- # Detect project type
632
- project_type = self._detect_project_type(project_path)
633
-
634
- return ProjectState(
635
- project_path=project_path,
636
- project_name=project_name,
637
- git_branch=git_branch,
638
- git_commit=git_commit,
639
- git_status=git_status,
640
- git_remotes=git_remotes,
641
- modified_files=git_status.get('modified', []),
642
- open_editors=[],
643
- breakpoints={},
644
- project_type=project_type,
645
- dependencies={},
646
- environment_vars={},
647
- last_build_status=None,
648
- last_test_results=None
649
- )
650
-
651
- except Exception as e:
652
- self.log_error(f"Error capturing project state: {e}")
653
- return ProjectState(
654
- project_path=os.getcwd(),
655
- project_name=os.path.basename(os.getcwd()),
656
- git_branch=None,
657
- git_commit=None,
658
- git_status={},
659
- git_remotes={},
660
- modified_files=[],
661
- open_editors=[],
662
- breakpoints={},
663
- project_type='unknown',
664
- dependencies={},
665
- environment_vars={},
666
- last_build_status=None,
667
- last_test_results=None
668
- )
669
-
670
- def _create_restart_state(self, reason: str, process_state: ProcessState) -> RestartState:
671
- """Create restart state information."""
672
- return RestartState(
673
- restart_id=str(uuid.uuid4()),
674
- restart_count=self.capture_count,
675
- timestamp=time.time(),
676
- previous_uptime=time.time() - process_state.start_time,
677
- reason=reason,
678
- trigger='manual', # Will be updated by caller
679
- memory_mb=process_state.memory_mb,
680
- memory_limit_mb=2048.0, # Default limit
681
- cpu_percent=process_state.cpu_percent,
682
- error_type=None,
683
- error_message=None,
684
- error_traceback=None,
685
- recovery_attempted=True,
686
- recovery_successful=False, # Will be updated after restore
687
- data_preserved=['process', 'conversation', 'project']
688
- )
689
-
690
- def _extract_referenced_files(self, conversation: Dict[str, Any]) -> List[str]:
691
- """Extract file references from conversation."""
692
- files = set()
693
-
694
- # Extract from messages
695
- for message in conversation.get('messages', []):
696
- content = message.get('content', '')
697
- # Simple extraction - could be enhanced with regex
698
- if isinstance(content, str):
699
- # Look for file paths
700
- import re
701
- file_pattern = r'[\'"`]([^\'"`]+\.[a-zA-Z0-9]+)[\'"`]'
702
- matches = re.findall(file_pattern, content)
703
- files.update(matches)
704
-
705
- return list(files)[:100] # Limit to prevent huge lists
706
-
707
- def _extract_minimal_conversation_state(self) -> ConversationState:
708
- """Extract minimal conversation state for large files."""
709
- try:
710
- # Just get basic metadata without loading full file
711
- file_size_mb = self.claude_json_path.stat().st_size / (1024 * 1024)
712
-
713
- return ConversationState(
714
- active_conversation_id="large_file",
715
- active_conversation=None,
716
- recent_conversations=[],
717
- total_conversations=-1, # Unknown
718
- total_storage_mb=file_size_mb,
719
- preferences={},
720
- open_files=[],
721
- recent_files=[],
722
- pinned_files=[]
723
- )
724
- except:
725
- return ConversationState(
726
- active_conversation_id=None,
727
- active_conversation=None,
728
- recent_conversations=[],
729
- total_conversations=0,
730
- total_storage_mb=0.0,
731
- preferences={},
732
- open_files=[],
733
- recent_files=[],
734
- pinned_files=[]
735
- )
736
-
737
- def _detect_project_type(self, project_path: str) -> str:
738
- """Detect project type from files present."""
739
- path = Path(project_path)
740
-
741
- if (path / 'pyproject.toml').exists() or (path / 'setup.py').exists():
742
- return 'python'
743
- elif (path / 'package.json').exists():
744
- return 'node'
745
- elif (path / 'go.mod').exists():
746
- return 'go'
747
- elif (path / 'Cargo.toml').exists():
748
- return 'rust'
749
- elif (path / 'pom.xml').exists():
750
- return 'java'
751
- else:
752
- return 'unknown'
753
-
754
- def get_statistics(self) -> Dict[str, Any]:
755
- """Get state manager statistics.
756
-
757
- Returns:
758
- Dictionary containing statistics
759
- """
760
- state_files = list(self.state_dir.glob("state_*.json*"))
761
- total_size_mb = sum(f.stat().st_size for f in state_files) / (1024 * 1024)
762
-
763
- return {
764
- 'capture_count': self.capture_count,
765
- 'restore_count': self.restore_count,
766
- 'cleanup_count': self.cleanup_count,
767
- 'state_files': len(state_files),
768
- 'total_size_mb': round(total_size_mb, 2),
769
- 'state_directory': str(self.state_dir),
770
- 'current_state_id': self.current_state.state_id if self.current_state else None,
771
- 'last_capture_time': self.last_capture_time,
772
- 'retention_days': self.retention_days,
773
- 'max_state_files': self.max_state_files
774
- }