claude-mpm 3.9.9__py3-none-any.whl → 4.0.3__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 (411) 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 +155 -0
  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 +1 -1
  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 +90 -49
  31. claude_mpm/cli/__main__.py +3 -2
  32. claude_mpm/cli/commands/__init__.py +21 -18
  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 +143 -762
  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 +203 -81
  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 +305 -197
  50. claude_mpm/cli/parser.py +24 -1150
  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 +104 -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 +217 -0
  69. claude_mpm/config/paths.py +94 -208
  70. claude_mpm/config/socketio_config.py +84 -73
  71. claude_mpm/constants.py +36 -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/css/dashboard.css +27 -8
  113. claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
  114. claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
  115. claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
  116. claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
  117. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
  118. claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
  119. claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
  120. claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
  121. claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
  122. claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
  123. claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
  124. claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
  125. claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
  126. claude_mpm/dashboard/static/dist/dashboard.js +2 -0
  127. claude_mpm/dashboard/static/dist/socket-client.js +2 -0
  128. claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
  129. claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
  130. claude_mpm/dashboard/static/js/components/event-viewer.js +74 -70
  131. claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
  132. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +106 -92
  133. claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
  134. claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
  135. claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
  136. claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
  137. claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
  138. claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
  139. claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
  140. claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
  141. claude_mpm/dashboard/static/js/dashboard.js +178 -453
  142. claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
  143. claude_mpm/dashboard/static/js/socket-client.js +120 -54
  144. claude_mpm/dashboard/templates/index.html +40 -50
  145. claude_mpm/experimental/cli_enhancements.py +60 -58
  146. claude_mpm/generators/__init__.py +1 -1
  147. claude_mpm/generators/agent_profile_generator.py +75 -65
  148. claude_mpm/hooks/__init__.py +1 -1
  149. claude_mpm/hooks/base_hook.py +33 -28
  150. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  151. claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
  152. claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
  153. claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
  154. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
  155. claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
  156. claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
  157. claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
  158. claude_mpm/hooks/memory_integration_hook.py +140 -100
  159. claude_mpm/hooks/tool_call_interceptor.py +89 -76
  160. claude_mpm/hooks/validation_hooks.py +57 -49
  161. claude_mpm/init.py +145 -121
  162. claude_mpm/models/__init__.py +9 -9
  163. claude_mpm/models/agent_definition.py +33 -23
  164. claude_mpm/models/agent_session.py +228 -200
  165. claude_mpm/scripts/__init__.py +1 -1
  166. claude_mpm/scripts/socketio_daemon.py +192 -75
  167. claude_mpm/scripts/socketio_server_manager.py +328 -0
  168. claude_mpm/scripts/start_activity_logging.py +25 -22
  169. claude_mpm/services/__init__.py +68 -43
  170. claude_mpm/services/agent_capabilities_service.py +271 -0
  171. claude_mpm/services/agents/__init__.py +23 -32
  172. claude_mpm/services/agents/deployment/__init__.py +3 -3
  173. claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
  174. claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
  175. claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
  176. claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
  177. claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
  178. claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
  179. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
  180. claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
  181. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
  182. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
  183. claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
  184. claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
  185. claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
  186. claude_mpm/services/agents/deployment/agent_validator.py +352 -0
  187. claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
  188. claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
  189. claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
  190. claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
  191. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  192. claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
  193. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  194. claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
  195. claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
  196. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  197. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  198. claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
  199. claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
  200. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  201. claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
  202. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  203. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  204. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  205. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  206. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
  207. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  208. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  209. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
  210. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
  211. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
  212. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
  213. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
  214. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  215. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
  216. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  217. claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
  218. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
  219. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  220. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  221. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  222. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  223. claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
  224. claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
  225. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  226. claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
  227. claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
  228. claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
  229. claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
  230. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  231. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  232. claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
  233. claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
  234. claude_mpm/services/agents/loading/__init__.py +2 -2
  235. claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
  236. claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
  237. claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
  238. claude_mpm/services/agents/management/__init__.py +2 -2
  239. claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
  240. claude_mpm/services/agents/management/agent_management_service.py +209 -156
  241. claude_mpm/services/agents/memory/__init__.py +9 -6
  242. claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
  243. claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
  244. claude_mpm/services/agents/memory/analyzer.py +430 -0
  245. claude_mpm/services/agents/memory/content_manager.py +376 -0
  246. claude_mpm/services/agents/memory/template_generator.py +468 -0
  247. claude_mpm/services/agents/registry/__init__.py +7 -10
  248. claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
  249. claude_mpm/services/agents/registry/modification_tracker.py +351 -285
  250. claude_mpm/services/async_session_logger.py +187 -153
  251. claude_mpm/services/claude_session_logger.py +87 -72
  252. claude_mpm/services/command_handler_service.py +217 -0
  253. claude_mpm/services/communication/__init__.py +3 -2
  254. claude_mpm/services/core/__init__.py +50 -97
  255. claude_mpm/services/core/base.py +60 -53
  256. claude_mpm/services/core/interfaces/__init__.py +188 -0
  257. claude_mpm/services/core/interfaces/agent.py +351 -0
  258. claude_mpm/services/core/interfaces/communication.py +343 -0
  259. claude_mpm/services/core/interfaces/infrastructure.py +413 -0
  260. claude_mpm/services/core/interfaces/service.py +434 -0
  261. claude_mpm/services/core/interfaces.py +19 -944
  262. claude_mpm/services/event_aggregator.py +208 -170
  263. claude_mpm/services/exceptions.py +387 -308
  264. claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
  265. claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
  266. claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
  267. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
  268. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
  269. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
  270. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
  271. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
  272. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  273. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  274. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  275. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  276. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
  277. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  278. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  279. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
  280. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
  281. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  282. claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
  283. claude_mpm/services/hook_service.py +106 -114
  284. claude_mpm/services/infrastructure/__init__.py +7 -5
  285. claude_mpm/services/infrastructure/context_preservation.py +571 -0
  286. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  287. claude_mpm/services/infrastructure/logging.py +83 -76
  288. claude_mpm/services/infrastructure/monitoring.py +547 -404
  289. claude_mpm/services/mcp_gateway/__init__.py +40 -23
  290. claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
  291. claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
  292. claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
  293. claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
  294. claude_mpm/services/mcp_gateway/core/__init__.py +14 -21
  295. claude_mpm/services/mcp_gateway/core/base.py +80 -67
  296. claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
  297. claude_mpm/services/mcp_gateway/core/interfaces.py +97 -93
  298. claude_mpm/services/mcp_gateway/main.py +307 -127
  299. claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
  300. claude_mpm/services/mcp_gateway/registry/service_registry.py +100 -101
  301. claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
  302. claude_mpm/services/mcp_gateway/server/__init__.py +4 -4
  303. claude_mpm/services/mcp_gateway/server/{mcp_server.py → mcp_gateway.py} +149 -153
  304. claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
  305. claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
  306. claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
  307. claude_mpm/services/mcp_gateway/tools/base_adapter.py +110 -121
  308. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
  309. claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
  310. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
  311. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
  312. claude_mpm/services/memory/__init__.py +2 -2
  313. claude_mpm/services/memory/builder.py +451 -362
  314. claude_mpm/services/memory/cache/__init__.py +2 -2
  315. claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
  316. claude_mpm/services/memory/cache/simple_cache.py +107 -93
  317. claude_mpm/services/memory/indexed_memory.py +195 -193
  318. claude_mpm/services/memory/optimizer.py +267 -234
  319. claude_mpm/services/memory/router.py +571 -263
  320. claude_mpm/services/memory_hook_service.py +237 -0
  321. claude_mpm/services/port_manager.py +223 -0
  322. claude_mpm/services/project/__init__.py +3 -3
  323. claude_mpm/services/project/analyzer.py +451 -305
  324. claude_mpm/services/project/registry.py +262 -240
  325. claude_mpm/services/recovery_manager.py +287 -231
  326. claude_mpm/services/response_tracker.py +87 -67
  327. claude_mpm/services/runner_configuration_service.py +587 -0
  328. claude_mpm/services/session_management_service.py +304 -0
  329. claude_mpm/services/socketio/__init__.py +4 -4
  330. claude_mpm/services/socketio/client_proxy.py +174 -0
  331. claude_mpm/services/socketio/handlers/__init__.py +3 -3
  332. claude_mpm/services/socketio/handlers/base.py +44 -30
  333. claude_mpm/services/socketio/handlers/connection.py +145 -65
  334. claude_mpm/services/socketio/handlers/file.py +123 -108
  335. claude_mpm/services/socketio/handlers/git.py +607 -373
  336. claude_mpm/services/socketio/handlers/hook.py +170 -0
  337. claude_mpm/services/socketio/handlers/memory.py +4 -4
  338. claude_mpm/services/socketio/handlers/project.py +4 -4
  339. claude_mpm/services/socketio/handlers/registry.py +53 -38
  340. claude_mpm/services/socketio/server/__init__.py +18 -0
  341. claude_mpm/services/socketio/server/broadcaster.py +252 -0
  342. claude_mpm/services/socketio/server/core.py +399 -0
  343. claude_mpm/services/socketio/server/main.py +323 -0
  344. claude_mpm/services/socketio_client_manager.py +160 -133
  345. claude_mpm/services/socketio_server.py +36 -1885
  346. claude_mpm/services/subprocess_launcher_service.py +316 -0
  347. claude_mpm/services/system_instructions_service.py +258 -0
  348. claude_mpm/services/ticket_manager.py +20 -534
  349. claude_mpm/services/utility_service.py +285 -0
  350. claude_mpm/services/version_control/__init__.py +18 -21
  351. claude_mpm/services/version_control/branch_strategy.py +20 -10
  352. claude_mpm/services/version_control/conflict_resolution.py +37 -13
  353. claude_mpm/services/version_control/git_operations.py +52 -21
  354. claude_mpm/services/version_control/semantic_versioning.py +92 -53
  355. claude_mpm/services/version_control/version_parser.py +145 -125
  356. claude_mpm/services/version_service.py +270 -0
  357. claude_mpm/storage/__init__.py +9 -0
  358. claude_mpm/storage/state_storage.py +552 -0
  359. claude_mpm/ticket_wrapper.py +2 -2
  360. claude_mpm/utils/__init__.py +2 -2
  361. claude_mpm/utils/agent_dependency_loader.py +453 -243
  362. claude_mpm/utils/config_manager.py +157 -118
  363. claude_mpm/utils/console.py +1 -1
  364. claude_mpm/utils/dependency_cache.py +102 -107
  365. claude_mpm/utils/dependency_manager.py +52 -47
  366. claude_mpm/utils/dependency_strategies.py +131 -96
  367. claude_mpm/utils/environment_context.py +110 -102
  368. claude_mpm/utils/error_handler.py +75 -55
  369. claude_mpm/utils/file_utils.py +80 -67
  370. claude_mpm/utils/framework_detection.py +12 -11
  371. claude_mpm/utils/import_migration_example.py +12 -60
  372. claude_mpm/utils/imports.py +48 -45
  373. claude_mpm/utils/path_operations.py +100 -93
  374. claude_mpm/utils/robust_installer.py +172 -164
  375. claude_mpm/utils/session_logging.py +30 -23
  376. claude_mpm/utils/subprocess_utils.py +99 -61
  377. claude_mpm/validation/__init__.py +1 -1
  378. claude_mpm/validation/agent_validator.py +151 -111
  379. claude_mpm/validation/frontmatter_validator.py +92 -71
  380. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/METADATA +51 -2
  381. claude_mpm-4.0.3.dist-info/RECORD +402 -0
  382. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
  383. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/licenses/LICENSE +1 -1
  384. claude_mpm/config/memory_guardian_config.py +0 -325
  385. claude_mpm/core/config_paths.py +0 -150
  386. claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
  387. claude_mpm/deployment_paths.py +0 -261
  388. claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
  389. claude_mpm/models/state_models.py +0 -433
  390. claude_mpm/services/agent/__init__.py +0 -24
  391. claude_mpm/services/agent/deployment.py +0 -2548
  392. claude_mpm/services/agent/management.py +0 -598
  393. claude_mpm/services/agent/registry.py +0 -813
  394. claude_mpm/services/agents/registry/agent_registry.py +0 -813
  395. claude_mpm/services/communication/socketio.py +0 -1935
  396. claude_mpm/services/communication/websocket.py +0 -479
  397. claude_mpm/services/framework_claude_md_generator.py +0 -624
  398. claude_mpm/services/health_monitor.py +0 -893
  399. claude_mpm/services/infrastructure/memory_guardian.py +0 -770
  400. claude_mpm/services/mcp_gateway/server/mcp_server_simple.py +0 -444
  401. claude_mpm/services/optimized_hook_service.py +0 -542
  402. claude_mpm/services/project_analyzer.py +0 -864
  403. claude_mpm/services/project_registry.py +0 -608
  404. claude_mpm/services/standalone_socketio_server.py +0 -1300
  405. claude_mpm/services/ticket_manager_di.py +0 -318
  406. claude_mpm/services/ticketing_service_original.py +0 -510
  407. claude_mpm/utils/paths.py +0 -395
  408. claude_mpm/utils/platform_memory.py +0 -524
  409. claude_mpm-3.9.9.dist-info/RECORD +0 -293
  410. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/WHEEL +0 -0
  411. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,571 @@
1
+ from pathlib import Path
2
+
3
+ """Context Preservation service for handling Claude conversation data.
4
+
5
+ This service specializes in parsing and preserving Claude's conversation
6
+ context, handling large .claude.json files efficiently.
7
+
8
+ Design Principles:
9
+ - Streaming JSON parsing for large files
10
+ - Memory-efficient processing
11
+ - Privacy-preserving extraction
12
+ - Graceful handling of corrupted data
13
+ """
14
+
15
+ import gzip
16
+ import json
17
+ import os
18
+ import shutil
19
+ import tempfile
20
+ from datetime import datetime, timedelta
21
+ from typing import Any, Dict, Iterator, List, Optional, Tuple
22
+
23
+ import ijson # For streaming JSON parsing
24
+ from dataclasses import dataclass, field
25
+
26
+ from claude_mpm.services.core.base import BaseService
27
+
28
+
29
+ @dataclass
30
+ class ConversationContext:
31
+ """Context information for a single conversation."""
32
+
33
+ conversation_id: str
34
+ title: str
35
+ message_count: int
36
+ last_message_time: float
37
+ file_references: List[str] = field(default_factory=list)
38
+ open_tabs: List[str] = field(default_factory=list)
39
+ tags: List[str] = field(default_factory=list)
40
+ is_active: bool = False
41
+
42
+
43
+ @dataclass
44
+ class ConversationState:
45
+ """Claude conversation state and context."""
46
+
47
+ active_conversation_id: Optional[str]
48
+ active_conversation: Optional[ConversationContext]
49
+ recent_conversations: List[ConversationContext]
50
+ total_conversations: int
51
+ total_storage_mb: float
52
+ preferences: Dict[str, Any]
53
+ open_files: List[str]
54
+ recent_files: List[str]
55
+ pinned_files: List[str]
56
+
57
+
58
+ class ContextPreservationService(BaseService):
59
+ """Service for preserving and managing Claude conversation context."""
60
+
61
+ def __init__(self, claude_dir: Optional[Path] = None):
62
+ """Initialize Context Preservation service.
63
+
64
+ Args:
65
+ claude_dir: Claude configuration directory (default: ~/.claude)
66
+ """
67
+ super().__init__("ContextPreservation")
68
+
69
+ # Claude configuration paths
70
+ self.claude_dir = claude_dir or Path.home() / ".claude"
71
+ self.claude_json_path = self.claude_dir / ".claude.json"
72
+ self.claude_backup_dir = self.claude_dir / "backups"
73
+
74
+ # Size thresholds
75
+ self.large_file_threshold_mb = 100
76
+ self.compression_threshold_mb = 50
77
+
78
+ # Context extraction limits
79
+ self.max_conversations_to_extract = 10
80
+ self.max_messages_per_conversation = 100
81
+ self.max_file_references = 1000
82
+
83
+ # Statistics
84
+ self.files_processed = 0
85
+ self.total_size_processed_mb = 0.0
86
+
87
+ self.log_info(f"Context Preservation initialized for: {self.claude_dir}")
88
+
89
+ async def initialize(self) -> bool:
90
+ """Initialize the Context Preservation service.
91
+
92
+ Returns:
93
+ True if initialization successful
94
+ """
95
+ try:
96
+ self.log_info("Initializing Context Preservation service")
97
+
98
+ # Ensure backup directory exists
99
+ self.claude_backup_dir.mkdir(parents=True, exist_ok=True)
100
+
101
+ # Check Claude configuration
102
+ if self.claude_json_path.exists():
103
+ size_mb = self.claude_json_path.stat().st_size / (1024 * 1024)
104
+ self.log_info(f"Found Claude configuration: {size_mb:.2f}MB")
105
+ else:
106
+ self.log_warning("Claude configuration not found")
107
+
108
+ self._initialized = True
109
+ self.log_info("Context Preservation service initialized successfully")
110
+ return True
111
+
112
+ except Exception as e:
113
+ self.log_error(f"Failed to initialize Context Preservation: {e}")
114
+ return False
115
+
116
+ async def parse_claude_json(
117
+ self, extract_full: bool = False
118
+ ) -> Optional[ConversationState]:
119
+ """Parse Claude's .claude.json file safely.
120
+
121
+ Args:
122
+ extract_full: Whether to extract full conversation data
123
+
124
+ Returns:
125
+ ConversationState object or None if parsing failed
126
+ """
127
+ try:
128
+ if not self.claude_json_path.exists():
129
+ self.log_debug("Claude configuration file not found")
130
+ return self._empty_conversation_state()
131
+
132
+ file_size_mb = self.claude_json_path.stat().st_size / (1024 * 1024)
133
+ self.log_info(f"Parsing Claude configuration: {file_size_mb:.2f}MB")
134
+
135
+ # Choose parsing strategy based on file size
136
+ if file_size_mb > self.large_file_threshold_mb:
137
+ self.log_info("Using streaming parser for large file")
138
+ return await self._parse_large_claude_json(extract_full)
139
+ else:
140
+ return await self._parse_standard_claude_json(extract_full)
141
+
142
+ except Exception as e:
143
+ self.log_error(f"Failed to parse Claude JSON: {e}")
144
+ return None
145
+
146
+ async def extract_active_conversation(self) -> Optional[ConversationContext]:
147
+ """Extract only the active conversation context.
148
+
149
+ Returns:
150
+ ConversationContext for active conversation or None
151
+ """
152
+ try:
153
+ if not self.claude_json_path.exists():
154
+ return None
155
+
156
+ # Use streaming to find active conversation
157
+ with open(self.claude_json_path, "rb") as f:
158
+ parser = ijson.parse(f)
159
+
160
+ active_conv_id = None
161
+ in_conversations = False
162
+ current_conv = {}
163
+
164
+ for prefix, event, value in parser:
165
+ # Get active conversation ID
166
+ if prefix == "activeConversationId":
167
+ active_conv_id = value
168
+
169
+ # Parse conversations array
170
+ elif prefix.startswith("conversations.item"):
171
+ if event == "map_key":
172
+ current_key = value
173
+ elif (
174
+ active_conv_id and current_conv.get("id") == active_conv_id
175
+ ):
176
+ # Found active conversation
177
+ return self._create_conversation_context(current_conv)
178
+
179
+ return None
180
+
181
+ except Exception as e:
182
+ self.log_error(f"Failed to extract active conversation: {e}")
183
+ return None
184
+
185
+ async def compress_conversation_history(self, keep_recent_days: int = 7) -> bool:
186
+ """Compress large conversation histories.
187
+
188
+ Args:
189
+ keep_recent_days: Days of recent conversations to keep uncompressed
190
+
191
+ Returns:
192
+ True if compression successful
193
+ """
194
+ try:
195
+ if not self.claude_json_path.exists():
196
+ return False
197
+
198
+ file_size_mb = self.claude_json_path.stat().st_size / (1024 * 1024)
199
+
200
+ if file_size_mb < self.compression_threshold_mb:
201
+ self.log_debug(f"File too small for compression: {file_size_mb:.2f}MB")
202
+ return False
203
+
204
+ self.log_info(f"Compressing conversation history: {file_size_mb:.2f}MB")
205
+
206
+ # Create backup first
207
+ backup_path = await self._create_backup()
208
+
209
+ # Load and filter conversations
210
+ cutoff_time = datetime.now().timestamp() - (keep_recent_days * 86400)
211
+
212
+ with open(self.claude_json_path, "r") as f:
213
+ data = json.load(f)
214
+
215
+ original_count = len(data.get("conversations", []))
216
+
217
+ # Filter conversations
218
+ recent_conversations = []
219
+ archived_conversations = []
220
+
221
+ for conv in data.get("conversations", []):
222
+ updated_at = conv.get("updatedAt", 0) / 1000 # Convert from ms
223
+ if updated_at >= cutoff_time:
224
+ recent_conversations.append(conv)
225
+ else:
226
+ # Create minimal version for archive
227
+ archived_conversations.append(
228
+ {
229
+ "id": conv.get("id"),
230
+ "title": conv.get("title"),
231
+ "createdAt": conv.get("createdAt"),
232
+ "updatedAt": conv.get("updatedAt"),
233
+ "messageCount": len(conv.get("messages", [])),
234
+ "archived": True,
235
+ }
236
+ )
237
+
238
+ # Update data with filtered conversations
239
+ data["conversations"] = recent_conversations
240
+ data["archivedConversations"] = archived_conversations
241
+
242
+ # Write compressed version
243
+ temp_path = self.claude_json_path.with_suffix(".tmp")
244
+ with open(temp_path, "w") as f:
245
+ json.dump(data, f, separators=(",", ":")) # Compact format
246
+
247
+ # Replace original
248
+ temp_path.replace(self.claude_json_path)
249
+
250
+ new_size_mb = self.claude_json_path.stat().st_size / (1024 * 1024)
251
+ reduction_pct = ((file_size_mb - new_size_mb) / file_size_mb) * 100
252
+
253
+ self.log_info(
254
+ f"Compression complete: {original_count} -> {len(recent_conversations)} "
255
+ f"conversations, {file_size_mb:.2f}MB -> {new_size_mb:.2f}MB "
256
+ f"({reduction_pct:.1f}% reduction)"
257
+ )
258
+
259
+ return True
260
+
261
+ except Exception as e:
262
+ self.log_error(f"Failed to compress conversation history: {e}")
263
+ return False
264
+
265
+ async def handle_file_references(self, conversation: Dict[str, Any]) -> List[str]:
266
+ """Extract and validate file references from conversation.
267
+
268
+ Args:
269
+ conversation: Conversation data dictionary
270
+
271
+ Returns:
272
+ List of valid file paths referenced in conversation
273
+ """
274
+ try:
275
+ files = set()
276
+
277
+ # Extract from messages
278
+ for message in conversation.get("messages", [])[
279
+ : self.max_messages_per_conversation
280
+ ]:
281
+ # Extract from content
282
+ content = message.get("content", "")
283
+ if isinstance(content, str):
284
+ files.update(self._extract_file_paths(content))
285
+
286
+ # Extract from attachments
287
+ for attachment in message.get("attachments", []):
288
+ if attachment.get("type") == "file":
289
+ file_path = attachment.get("path")
290
+ if file_path:
291
+ files.add(file_path)
292
+
293
+ # Validate file existence
294
+ valid_files = []
295
+ for file_path in list(files)[: self.max_file_references]:
296
+ try:
297
+ if Path(file_path).exists():
298
+ valid_files.append(file_path)
299
+ except:
300
+ pass # Invalid path
301
+
302
+ return valid_files
303
+
304
+ except Exception as e:
305
+ self.log_error(f"Failed to handle file references: {e}")
306
+ return []
307
+
308
+ async def preserve_user_preferences(self) -> Dict[str, Any]:
309
+ """Extract and preserve user preferences and settings.
310
+
311
+ Returns:
312
+ Dictionary of user preferences
313
+ """
314
+ try:
315
+ if not self.claude_json_path.exists():
316
+ return {}
317
+
318
+ # Use streaming to extract preferences
319
+ preferences = {}
320
+
321
+ with open(self.claude_json_path, "rb") as f:
322
+ parser = ijson.parse(f)
323
+
324
+ for prefix, event, value in parser:
325
+ if prefix.startswith("preferences"):
326
+ # Extract preference key and value
327
+ if event == "map_key":
328
+ current_key = value
329
+ elif event in ("string", "number", "boolean"):
330
+ preferences[current_key] = value
331
+
332
+ self.log_debug(f"Preserved {len(preferences)} user preferences")
333
+ return preferences
334
+
335
+ except Exception as e:
336
+ self.log_error(f"Failed to preserve user preferences: {e}")
337
+ return {}
338
+
339
+ async def _parse_standard_claude_json(
340
+ self, extract_full: bool
341
+ ) -> ConversationState:
342
+ """Parse Claude JSON using standard JSON parser."""
343
+ try:
344
+ with open(self.claude_json_path, "r") as f:
345
+ data = json.load(f)
346
+
347
+ return await self._extract_conversation_state(data, extract_full)
348
+
349
+ except json.JSONDecodeError as e:
350
+ self.log_error(f"JSON decode error: {e}")
351
+ return self._empty_conversation_state()
352
+
353
+ async def _parse_large_claude_json(self, extract_full: bool) -> ConversationState:
354
+ """Parse large Claude JSON using streaming parser."""
355
+ try:
356
+ # Extract key data using streaming
357
+ active_conv_id = None
358
+ conversations = []
359
+ preferences = {}
360
+ open_files = []
361
+
362
+ with open(self.claude_json_path, "rb") as f:
363
+ parser = ijson.parse(f)
364
+
365
+ conversation_count = 0
366
+ current_conv = {}
367
+ in_conversation = False
368
+
369
+ for prefix, event, value in parser:
370
+ # Limit conversations extracted
371
+ if conversation_count >= self.max_conversations_to_extract:
372
+ break
373
+
374
+ # Extract active conversation ID
375
+ if prefix == "activeConversationId":
376
+ active_conv_id = value
377
+
378
+ # Extract conversations
379
+ elif prefix.startswith("conversations.item"):
380
+ if event == "start_map":
381
+ in_conversation = True
382
+ current_conv = {}
383
+ elif event == "end_map":
384
+ if in_conversation and current_conv:
385
+ conversations.append(current_conv)
386
+ conversation_count += 1
387
+ in_conversation = False
388
+ current_conv = {}
389
+ elif in_conversation and event == "map_key":
390
+ current_key = value
391
+ elif in_conversation and current_key:
392
+ current_conv[current_key] = value
393
+
394
+ # Extract open files
395
+ elif prefix.startswith("openFiles.item"):
396
+ if event == "string":
397
+ open_files.append(value)
398
+
399
+ # Find active conversation
400
+ active_conv = None
401
+ recent_convs = []
402
+
403
+ for conv in conversations:
404
+ if conv.get("id") == active_conv_id:
405
+ active_conv = self._create_conversation_context(conv)
406
+ else:
407
+ recent_convs.append(self._create_conversation_context(conv))
408
+
409
+ file_size_mb = self.claude_json_path.stat().st_size / (1024 * 1024)
410
+
411
+ return ConversationState(
412
+ active_conversation_id=active_conv_id,
413
+ active_conversation=active_conv,
414
+ recent_conversations=recent_convs[:5],
415
+ total_conversations=len(conversations),
416
+ total_storage_mb=file_size_mb,
417
+ preferences=preferences,
418
+ open_files=open_files[:100],
419
+ recent_files=[],
420
+ pinned_files=[],
421
+ )
422
+
423
+ except Exception as e:
424
+ self.log_error(f"Failed to parse large Claude JSON: {e}")
425
+ return self._empty_conversation_state()
426
+
427
+ async def _extract_conversation_state(
428
+ self, data: Dict[str, Any], extract_full: bool
429
+ ) -> ConversationState:
430
+ """Extract conversation state from parsed data."""
431
+ try:
432
+ conversations = data.get("conversations", [])
433
+ active_conv_id = data.get("activeConversationId")
434
+
435
+ # Find active conversation
436
+ active_conv = None
437
+ if active_conv_id:
438
+ for conv in conversations:
439
+ if conv.get("id") == active_conv_id:
440
+ active_conv = self._create_conversation_context(conv)
441
+ break
442
+
443
+ # Get recent conversations
444
+ recent_convs = []
445
+ if extract_full:
446
+ sorted_convs = sorted(
447
+ conversations, key=lambda c: c.get("updatedAt", 0), reverse=True
448
+ )[: self.max_conversations_to_extract]
449
+
450
+ for conv in sorted_convs:
451
+ if conv.get("id") != active_conv_id:
452
+ recent_convs.append(self._create_conversation_context(conv))
453
+
454
+ file_size_mb = self.claude_json_path.stat().st_size / (1024 * 1024)
455
+
456
+ return ConversationState(
457
+ active_conversation_id=active_conv_id,
458
+ active_conversation=active_conv,
459
+ recent_conversations=recent_convs,
460
+ total_conversations=len(conversations),
461
+ total_storage_mb=file_size_mb,
462
+ preferences=data.get("preferences", {}),
463
+ open_files=data.get("openFiles", [])[:100],
464
+ recent_files=data.get("recentFiles", [])[:100],
465
+ pinned_files=data.get("pinnedFiles", [])[:50],
466
+ )
467
+
468
+ except Exception as e:
469
+ self.log_error(f"Failed to extract conversation state: {e}")
470
+ return self._empty_conversation_state()
471
+
472
+ def _create_conversation_context(self, conv: Dict[str, Any]) -> ConversationContext:
473
+ """Create ConversationContext from conversation data."""
474
+ return ConversationContext(
475
+ conversation_id=conv.get("id", ""),
476
+ title=conv.get("title", "Untitled"),
477
+ created_at=conv.get("createdAt", 0) / 1000, # Convert from ms
478
+ updated_at=conv.get("updatedAt", 0) / 1000,
479
+ message_count=len(conv.get("messages", [])),
480
+ total_tokens=conv.get("totalTokens", 0),
481
+ max_tokens=conv.get("maxTokens", 100000),
482
+ referenced_files=[], # Would need full extraction
483
+ open_tabs=conv.get("openTabs", []),
484
+ tags=conv.get("tags", []),
485
+ is_active=False,
486
+ )
487
+
488
+ def _empty_conversation_state(self) -> ConversationState:
489
+ """Create empty conversation state."""
490
+ return ConversationState(
491
+ active_conversation_id=None,
492
+ active_conversation=None,
493
+ recent_conversations=[],
494
+ total_conversations=0,
495
+ total_storage_mb=0.0,
496
+ preferences={},
497
+ open_files=[],
498
+ recent_files=[],
499
+ pinned_files=[],
500
+ )
501
+
502
+ def _extract_file_paths(self, content: str) -> List[str]:
503
+ """Extract file paths from message content."""
504
+ import re
505
+
506
+ files = set()
507
+
508
+ # Common file path patterns
509
+ patterns = [
510
+ r'[\'"`]([/\\]?(?:[a-zA-Z]:)?[/\\]?[\w\-_./\\]+\.\w+)[\'"`]',
511
+ r"(?:^|\s)([/\\]?(?:[a-zA-Z]:)?[/\\]?[\w\-_./\\]+\.\w+)(?:\s|$)",
512
+ ]
513
+
514
+ for pattern in patterns:
515
+ matches = re.findall(pattern, content)
516
+ files.update(matches)
517
+
518
+ return list(files)
519
+
520
+ async def _create_backup(self) -> Path:
521
+ """Create backup of Claude configuration."""
522
+ try:
523
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
524
+ backup_name = f"claude_backup_{timestamp}.json"
525
+
526
+ # Compress if large
527
+ file_size_mb = self.claude_json_path.stat().st_size / (1024 * 1024)
528
+ if file_size_mb > self.compression_threshold_mb:
529
+ backup_name += ".gz"
530
+ backup_path = self.claude_backup_dir / backup_name
531
+
532
+ with open(self.claude_json_path, "rb") as f_in:
533
+ with gzip.open(backup_path, "wb") as f_out:
534
+ shutil.copyfileobj(f_in, f_out)
535
+ else:
536
+ backup_path = self.claude_backup_dir / backup_name
537
+ shutil.copy2(self.claude_json_path, backup_path)
538
+
539
+ self.log_info(f"Created backup: {backup_path}")
540
+ return backup_path
541
+
542
+ except Exception as e:
543
+ self.log_error(f"Failed to create backup: {e}")
544
+ raise
545
+
546
+ def get_statistics(self) -> Dict[str, Any]:
547
+ """Get context preservation statistics.
548
+
549
+ Returns:
550
+ Dictionary containing statistics
551
+ """
552
+ claude_size_mb = 0.0
553
+ if self.claude_json_path.exists():
554
+ claude_size_mb = self.claude_json_path.stat().st_size / (1024 * 1024)
555
+
556
+ backup_count = 0
557
+ backup_size_mb = 0.0
558
+ if self.claude_backup_dir.exists():
559
+ backups = list(self.claude_backup_dir.glob("claude_backup_*.json*"))
560
+ backup_count = len(backups)
561
+ backup_size_mb = sum(f.stat().st_size for f in backups) / (1024 * 1024)
562
+
563
+ return {
564
+ "claude_config_exists": self.claude_json_path.exists(),
565
+ "claude_config_size_mb": round(claude_size_mb, 2),
566
+ "is_large_file": claude_size_mb > self.large_file_threshold_mb,
567
+ "backup_count": backup_count,
568
+ "total_backup_size_mb": round(backup_size_mb, 2),
569
+ "files_processed": self.files_processed,
570
+ "total_size_processed_mb": round(self.total_size_processed_mb, 2),
571
+ }