claude-mpm 3.9.11__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 (419) 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 +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 +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 +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 -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 +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 +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/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 +233 -199
  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 +30 -13
  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 +13 -20
  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 +87 -84
  298. claude_mpm/services/mcp_gateway/main.py +287 -137
  299. claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
  300. claude_mpm/services/mcp_gateway/registry/service_registry.py +97 -94
  301. claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
  302. claude_mpm/services/mcp_gateway/server/__init__.py +2 -2
  303. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +105 -110
  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 +109 -119
  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 +19 -533
  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 +2 -2
  358. claude_mpm/storage/state_storage.py +177 -181
  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.11.dist-info → claude_mpm-4.0.3.dist-info}/METADATA +27 -1
  381. claude_mpm-4.0.3.dist-info/RECORD +402 -0
  382. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
  383. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/licenses/LICENSE +1 -1
  384. claude_mpm/cli/commands/run_guarded.py +0 -511
  385. claude_mpm/config/memory_guardian_config.py +0 -325
  386. claude_mpm/config/memory_guardian_yaml.py +0 -335
  387. claude_mpm/core/config_paths.py +0 -150
  388. claude_mpm/core/memory_aware_runner.py +0 -353
  389. claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
  390. claude_mpm/deployment_paths.py +0 -261
  391. claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
  392. claude_mpm/models/state_models.py +0 -433
  393. claude_mpm/services/agent/__init__.py +0 -24
  394. claude_mpm/services/agent/deployment.py +0 -2548
  395. claude_mpm/services/agent/management.py +0 -598
  396. claude_mpm/services/agent/registry.py +0 -813
  397. claude_mpm/services/agents/registry/agent_registry.py +0 -813
  398. claude_mpm/services/communication/socketio.py +0 -1935
  399. claude_mpm/services/communication/websocket.py +0 -479
  400. claude_mpm/services/framework_claude_md_generator.py +0 -624
  401. claude_mpm/services/health_monitor.py +0 -893
  402. claude_mpm/services/infrastructure/graceful_degradation.py +0 -616
  403. claude_mpm/services/infrastructure/health_monitor.py +0 -775
  404. claude_mpm/services/infrastructure/memory_dashboard.py +0 -479
  405. claude_mpm/services/infrastructure/memory_guardian.py +0 -944
  406. claude_mpm/services/infrastructure/restart_protection.py +0 -642
  407. claude_mpm/services/infrastructure/state_manager.py +0 -774
  408. claude_mpm/services/mcp_gateway/manager.py +0 -334
  409. claude_mpm/services/optimized_hook_service.py +0 -542
  410. claude_mpm/services/project_analyzer.py +0 -864
  411. claude_mpm/services/project_registry.py +0 -608
  412. claude_mpm/services/standalone_socketio_server.py +0 -1300
  413. claude_mpm/services/ticket_manager_di.py +0 -318
  414. claude_mpm/services/ticketing_service_original.py +0 -510
  415. claude_mpm/utils/paths.py +0 -395
  416. claude_mpm/utils/platform_memory.py +0 -524
  417. claude_mpm-3.9.11.dist-info/RECORD +0 -306
  418. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/WHEEL +0 -0
  419. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,5 @@
1
+ from pathlib import Path
2
+
1
3
  """State Storage module for reliable state persistence.
2
4
 
3
5
  This module provides atomic file operations and various serialization
@@ -12,6 +14,7 @@ Design Principles:
12
14
 
13
15
  import fcntl
14
16
  import gzip
17
+ import hashlib
15
18
  import json
16
19
  import logging
17
20
  import os
@@ -22,272 +25,268 @@ import tempfile
22
25
  import time
23
26
  from contextlib import contextmanager
24
27
  from datetime import datetime
25
- from pathlib import Path
26
- from typing import Any, Dict, Optional, Union, BinaryIO, TextIO
27
- import hashlib
28
+ from typing import Any, BinaryIO, Dict, Optional, TextIO, Union
28
29
 
29
30
 
30
31
  class StateStorage:
31
32
  """Reliable state storage with atomic operations."""
32
-
33
+
33
34
  def __init__(self, storage_dir: Optional[Path] = None):
34
35
  """Initialize State Storage.
35
-
36
+
36
37
  Args:
37
38
  storage_dir: Directory for state storage (default: ~/.claude-mpm/storage)
38
39
  """
39
40
  self.storage_dir = storage_dir or Path.home() / ".claude-mpm" / "storage"
40
41
  self.storage_dir.mkdir(parents=True, exist_ok=True)
41
-
42
+
42
43
  # Logging
43
44
  self.logger = logging.getLogger(__name__)
44
-
45
+
45
46
  # File locking support (Unix-like systems)
46
- self.supports_locking = platform.system() != 'Windows'
47
-
47
+ self.supports_locking = platform.system() != "Windows"
48
+
48
49
  # Statistics
49
50
  self.write_count = 0
50
51
  self.read_count = 0
51
52
  self.error_count = 0
52
-
53
- def write_json(self,
54
- data: Dict[str, Any],
55
- file_path: Union[str, Path],
56
- compress: bool = False,
57
- atomic: bool = True) -> bool:
53
+
54
+ def write_json(
55
+ self,
56
+ data: Dict[str, Any],
57
+ file_path: Union[str, Path],
58
+ compress: bool = False,
59
+ atomic: bool = True,
60
+ ) -> bool:
58
61
  """Write data to JSON file atomically.
59
-
62
+
60
63
  Args:
61
64
  data: Data to serialize
62
65
  file_path: Target file path
63
66
  compress: Whether to compress with gzip
64
67
  atomic: Whether to use atomic write
65
-
68
+
66
69
  Returns:
67
70
  True if write successful
68
71
  """
69
72
  try:
70
73
  file_path = Path(file_path)
71
-
74
+
72
75
  if atomic:
73
76
  return self._atomic_write(
74
- file_path,
75
- data,
76
- serializer='json',
77
- compress=compress
77
+ file_path, data, serializer="json", compress=compress
78
78
  )
79
79
  else:
80
80
  # Direct write (not atomic)
81
81
  if compress:
82
- with gzip.open(file_path, 'wt', encoding='utf-8') as f:
82
+ with gzip.open(file_path, "wt", encoding="utf-8") as f:
83
83
  json.dump(data, f, indent=2, default=str)
84
84
  else:
85
- with open(file_path, 'w') as f:
85
+ with open(file_path, "w") as f:
86
86
  json.dump(data, f, indent=2, default=str)
87
-
87
+
88
88
  self.write_count += 1
89
89
  return True
90
-
90
+
91
91
  except Exception as e:
92
92
  self.logger.error(f"Failed to write JSON to {file_path}: {e}")
93
93
  self.error_count += 1
94
94
  return False
95
-
96
- def read_json(self,
97
- file_path: Union[str, Path],
98
- compressed: Optional[bool] = None) -> Optional[Dict[str, Any]]:
95
+
96
+ def read_json(
97
+ self, file_path: Union[str, Path], compressed: Optional[bool] = None
98
+ ) -> Optional[Dict[str, Any]]:
99
99
  """Read data from JSON file.
100
-
100
+
101
101
  Args:
102
102
  file_path: Source file path
103
103
  compressed: Whether file is compressed (auto-detect if None)
104
-
104
+
105
105
  Returns:
106
106
  Deserialized data or None if read failed
107
107
  """
108
108
  try:
109
109
  file_path = Path(file_path)
110
-
110
+
111
111
  if not file_path.exists():
112
112
  self.logger.debug(f"File not found: {file_path}")
113
113
  return None
114
-
114
+
115
115
  # Auto-detect compression
116
116
  if compressed is None:
117
- compressed = file_path.suffix == '.gz'
118
-
119
- with self._file_lock(file_path, 'r'):
117
+ compressed = file_path.suffix == ".gz"
118
+
119
+ with self._file_lock(file_path, "r"):
120
120
  if compressed:
121
- with gzip.open(file_path, 'rt', encoding='utf-8') as f:
121
+ with gzip.open(file_path, "rt", encoding="utf-8") as f:
122
122
  data = json.load(f)
123
123
  else:
124
- with open(file_path, 'r') as f:
124
+ with open(file_path, "r") as f:
125
125
  data = json.load(f)
126
-
126
+
127
127
  self.read_count += 1
128
128
  return data
129
-
129
+
130
130
  except Exception as e:
131
131
  self.logger.error(f"Failed to read JSON from {file_path}: {e}")
132
132
  self.error_count += 1
133
133
  return None
134
-
135
- def write_pickle(self,
136
- data: Any,
137
- file_path: Union[str, Path],
138
- compress: bool = False,
139
- atomic: bool = True) -> bool:
134
+
135
+ def write_pickle(
136
+ self,
137
+ data: Any,
138
+ file_path: Union[str, Path],
139
+ compress: bool = False,
140
+ atomic: bool = True,
141
+ ) -> bool:
140
142
  """Write data to pickle file atomically.
141
-
143
+
142
144
  Args:
143
145
  data: Data to serialize
144
146
  file_path: Target file path
145
147
  compress: Whether to compress with gzip
146
148
  atomic: Whether to use atomic write
147
-
149
+
148
150
  Returns:
149
151
  True if write successful
150
152
  """
151
153
  try:
152
154
  file_path = Path(file_path)
153
-
155
+
154
156
  if atomic:
155
157
  return self._atomic_write(
156
- file_path,
157
- data,
158
- serializer='pickle',
159
- compress=compress
158
+ file_path, data, serializer="pickle", compress=compress
160
159
  )
161
160
  else:
162
161
  # Direct write (not atomic)
163
162
  if compress:
164
- with gzip.open(file_path, 'wb') as f:
163
+ with gzip.open(file_path, "wb") as f:
165
164
  pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)
166
165
  else:
167
- with open(file_path, 'wb') as f:
166
+ with open(file_path, "wb") as f:
168
167
  pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)
169
-
168
+
170
169
  self.write_count += 1
171
170
  return True
172
-
171
+
173
172
  except Exception as e:
174
173
  self.logger.error(f"Failed to write pickle to {file_path}: {e}")
175
174
  self.error_count += 1
176
175
  return False
177
-
178
- def read_pickle(self,
179
- file_path: Union[str, Path],
180
- compressed: Optional[bool] = None) -> Optional[Any]:
176
+
177
+ def read_pickle(
178
+ self, file_path: Union[str, Path], compressed: Optional[bool] = None
179
+ ) -> Optional[Any]:
181
180
  """Read data from pickle file.
182
-
181
+
183
182
  Args:
184
183
  file_path: Source file path
185
184
  compressed: Whether file is compressed (auto-detect if None)
186
-
185
+
187
186
  Returns:
188
187
  Deserialized data or None if read failed
189
188
  """
190
189
  try:
191
190
  file_path = Path(file_path)
192
-
191
+
193
192
  if not file_path.exists():
194
193
  self.logger.debug(f"File not found: {file_path}")
195
194
  return None
196
-
195
+
197
196
  # Auto-detect compression
198
197
  if compressed is None:
199
- compressed = file_path.suffix == '.gz'
200
-
201
- with self._file_lock(file_path, 'rb'):
198
+ compressed = file_path.suffix == ".gz"
199
+
200
+ with self._file_lock(file_path, "rb"):
202
201
  if compressed:
203
- with gzip.open(file_path, 'rb') as f:
202
+ with gzip.open(file_path, "rb") as f:
204
203
  data = pickle.load(f)
205
204
  else:
206
- with open(file_path, 'rb') as f:
205
+ with open(file_path, "rb") as f:
207
206
  data = pickle.load(f)
208
-
207
+
209
208
  self.read_count += 1
210
209
  return data
211
-
210
+
212
211
  except Exception as e:
213
212
  self.logger.error(f"Failed to read pickle from {file_path}: {e}")
214
213
  self.error_count += 1
215
214
  return None
216
-
217
- def _atomic_write(self,
218
- file_path: Path,
219
- data: Any,
220
- serializer: str = 'json',
221
- compress: bool = False) -> bool:
215
+
216
+ def _atomic_write(
217
+ self,
218
+ file_path: Path,
219
+ data: Any,
220
+ serializer: str = "json",
221
+ compress: bool = False,
222
+ ) -> bool:
222
223
  """Perform atomic write operation.
223
-
224
+
224
225
  Args:
225
226
  file_path: Target file path
226
227
  data: Data to write
227
228
  serializer: Serialization format ('json' or 'pickle')
228
229
  compress: Whether to compress
229
-
230
+
230
231
  Returns:
231
232
  True if write successful
232
233
  """
233
234
  try:
234
235
  # Ensure parent directory exists
235
236
  file_path.parent.mkdir(parents=True, exist_ok=True)
236
-
237
+
237
238
  # Create temporary file
238
239
  temp_fd, temp_path = tempfile.mkstemp(
239
- dir=file_path.parent,
240
- prefix=f'.{file_path.stem}_',
241
- suffix='.tmp'
240
+ dir=file_path.parent, prefix=f".{file_path.stem}_", suffix=".tmp"
242
241
  )
243
-
242
+
244
243
  try:
245
244
  # Write to temporary file
246
- if serializer == 'json':
245
+ if serializer == "json":
247
246
  if compress:
248
- with gzip.open(temp_path, 'wt', encoding='utf-8') as f:
247
+ with gzip.open(temp_path, "wt", encoding="utf-8") as f:
249
248
  json.dump(data, f, indent=2, default=str)
250
249
  else:
251
- with os.fdopen(temp_fd, 'w') as f:
250
+ with os.fdopen(temp_fd, "w") as f:
252
251
  json.dump(data, f, indent=2, default=str)
253
- elif serializer == 'pickle':
252
+ elif serializer == "pickle":
254
253
  if compress:
255
- with gzip.open(temp_path, 'wb') as f:
254
+ with gzip.open(temp_path, "wb") as f:
256
255
  pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)
257
256
  else:
258
- with os.fdopen(temp_fd, 'wb') as f:
257
+ with os.fdopen(temp_fd, "wb") as f:
259
258
  pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)
260
259
  else:
261
260
  raise ValueError(f"Unknown serializer: {serializer}")
262
-
261
+
263
262
  # Add checksum for integrity verification
264
263
  self._add_checksum(temp_path)
265
-
264
+
266
265
  # Atomic rename
267
266
  Path(temp_path).replace(file_path)
268
-
267
+
269
268
  self.write_count += 1
270
269
  self.logger.debug(f"Atomic write successful: {file_path}")
271
270
  return True
272
-
271
+
273
272
  finally:
274
273
  # Clean up temp file if it still exists
275
274
  if Path(temp_path).exists():
276
275
  os.unlink(temp_path)
277
-
276
+
278
277
  except Exception as e:
279
278
  self.logger.error(f"Atomic write failed for {file_path}: {e}")
280
279
  self.error_count += 1
281
280
  return False
282
-
281
+
283
282
  @contextmanager
284
283
  def _file_lock(self, file_path: Path, mode: str):
285
284
  """Context manager for file locking.
286
-
285
+
287
286
  Args:
288
287
  file_path: File to lock
289
288
  mode: File open mode
290
-
289
+
291
290
  Yields:
292
291
  Locked file handle
293
292
  """
@@ -296,12 +295,12 @@ class StateStorage:
296
295
  with open(file_path, mode) as f:
297
296
  yield f
298
297
  return
299
-
298
+
300
299
  # Unix-like systems with fcntl
301
300
  f = None
302
301
  try:
303
302
  f = open(file_path, mode)
304
-
303
+
305
304
  # Try to acquire lock (non-blocking)
306
305
  max_attempts = 50
307
306
  for attempt in range(max_attempts):
@@ -312,9 +311,9 @@ class StateStorage:
312
311
  if attempt == max_attempts - 1:
313
312
  raise
314
313
  time.sleep(0.1)
315
-
314
+
316
315
  yield f
317
-
316
+
318
317
  finally:
319
318
  if f:
320
319
  try:
@@ -322,79 +321,79 @@ class StateStorage:
322
321
  except:
323
322
  pass
324
323
  f.close()
325
-
324
+
326
325
  def _add_checksum(self, file_path: Union[str, Path]) -> None:
327
326
  """Add checksum to file for integrity verification.
328
-
327
+
329
328
  Args:
330
329
  file_path: File to add checksum to
331
330
  """
332
331
  try:
333
332
  file_path = Path(file_path)
334
-
333
+
335
334
  # Calculate checksum
336
335
  hasher = hashlib.sha256()
337
- with open(file_path, 'rb') as f:
338
- for chunk in iter(lambda: f.read(4096), b''):
336
+ with open(file_path, "rb") as f:
337
+ for chunk in iter(lambda: f.read(4096), b""):
339
338
  hasher.update(chunk)
340
-
339
+
341
340
  checksum = hasher.hexdigest()
342
-
341
+
343
342
  # Write checksum file
344
- checksum_path = file_path.with_suffix(file_path.suffix + '.sha256')
345
- with open(checksum_path, 'w') as f:
343
+ checksum_path = file_path.with_suffix(file_path.suffix + ".sha256")
344
+ with open(checksum_path, "w") as f:
346
345
  f.write(checksum)
347
-
346
+
348
347
  except Exception as e:
349
348
  self.logger.warning(f"Could not add checksum: {e}")
350
-
349
+
351
350
  def verify_checksum(self, file_path: Union[str, Path]) -> bool:
352
351
  """Verify file checksum for integrity.
353
-
352
+
354
353
  Args:
355
354
  file_path: File to verify
356
-
355
+
357
356
  Returns:
358
357
  True if checksum valid or not present
359
358
  """
360
359
  try:
361
360
  file_path = Path(file_path)
362
- checksum_path = file_path.with_suffix(file_path.suffix + '.sha256')
363
-
361
+ checksum_path = file_path.with_suffix(file_path.suffix + ".sha256")
362
+
364
363
  if not checksum_path.exists():
365
364
  return True # No checksum to verify
366
-
365
+
367
366
  # Read expected checksum
368
- with open(checksum_path, 'r') as f:
367
+ with open(checksum_path, "r") as f:
369
368
  expected = f.read().strip()
370
-
369
+
371
370
  # Calculate actual checksum
372
371
  hasher = hashlib.sha256()
373
- with open(file_path, 'rb') as f:
374
- for chunk in iter(lambda: f.read(4096), b''):
372
+ with open(file_path, "rb") as f:
373
+ for chunk in iter(lambda: f.read(4096), b""):
375
374
  hasher.update(chunk)
376
-
375
+
377
376
  actual = hasher.hexdigest()
378
-
377
+
379
378
  if actual != expected:
380
379
  self.logger.error(f"Checksum mismatch for {file_path}")
381
380
  return False
382
-
381
+
383
382
  return True
384
-
383
+
385
384
  except Exception as e:
386
385
  self.logger.warning(f"Could not verify checksum: {e}")
387
386
  return True # Assume valid if can't verify
388
-
387
+
389
388
  def cleanup_temp_files(self) -> int:
390
389
  """Clean up temporary files in storage directory.
391
-
390
+
392
391
  Returns:
393
392
  Number of files cleaned up
394
393
  """
395
394
  try:
396
395
  cleaned = 0
397
-
396
+
398
397
  # Find temp files
399
398
  for temp_file in self.storage_dir.glob(".*_*.tmp"):
400
399
  try:
@@ -406,26 +405,26 @@ class StateStorage:
406
405
  self.logger.debug(f"Cleaned up temp file: {temp_file}")
407
406
  except:
408
407
  pass
409
-
408
+
410
409
  # Clean up orphaned checksum files
411
410
  for checksum_file in self.storage_dir.glob("*.sha256"):
412
- data_file = checksum_file.with_suffix('')
411
+ data_file = checksum_file.with_suffix("")
413
412
  if not data_file.exists():
414
413
  checksum_file.unlink()
415
414
  cleaned += 1
416
-
415
+
417
416
  if cleaned > 0:
418
417
  self.logger.info(f"Cleaned up {cleaned} temporary files")
419
-
418
+
420
419
  return cleaned
421
-
420
+
422
421
  except Exception as e:
423
422
  self.logger.error(f"Error cleaning up temp files: {e}")
424
423
  return 0
425
-
424
+
426
425
  def get_storage_info(self) -> Dict[str, Any]:
427
426
  """Get storage statistics and information.
428
-
427
+
429
428
  Returns:
430
429
  Dictionary containing storage info
431
430
  """
@@ -433,40 +432,37 @@ class StateStorage:
433
432
  # Calculate storage size
434
433
  total_size = 0
435
434
  file_count = 0
436
-
435
+
437
436
  for file_path in self.storage_dir.rglob("*"):
438
437
  if file_path.is_file():
439
438
  total_size += file_path.stat().st_size
440
439
  file_count += 1
441
-
440
+
442
441
  # Find temp files
443
442
  temp_files = list(self.storage_dir.glob(".*_*.tmp"))
444
-
443
+
445
444
  return {
446
- 'storage_directory': str(self.storage_dir),
447
- 'total_files': file_count,
448
- 'total_size_mb': round(total_size / (1024 * 1024), 2),
449
- 'temp_files': len(temp_files),
450
- 'write_count': self.write_count,
451
- 'read_count': self.read_count,
452
- 'error_count': self.error_count,
453
- 'supports_locking': self.supports_locking
445
+ "storage_directory": str(self.storage_dir),
446
+ "total_files": file_count,
447
+ "total_size_mb": round(total_size / (1024 * 1024), 2),
448
+ "temp_files": len(temp_files),
449
+ "write_count": self.write_count,
450
+ "read_count": self.read_count,
451
+ "error_count": self.error_count,
452
+ "supports_locking": self.supports_locking,
454
453
  }
455
-
454
+
456
455
  except Exception as e:
457
456
  self.logger.error(f"Error getting storage info: {e}")
458
- return {
459
- 'storage_directory': str(self.storage_dir),
460
- 'error': str(e)
461
- }
457
+ return {"storage_directory": str(self.storage_dir), "error": str(e)}
462
458
 
463
459
 
464
460
  class StateCache:
465
461
  """In-memory cache for frequently accessed state data."""
466
-
462
+
467
463
  def __init__(self, max_size: int = 100, ttl_seconds: int = 300):
468
464
  """Initialize State Cache.
469
-
465
+
470
466
  Args:
471
467
  max_size: Maximum number of cached items
472
468
  ttl_seconds: Time-to-live for cached items
@@ -475,40 +471,40 @@ class StateCache:
475
471
  self.ttl_seconds = ttl_seconds
476
472
  self.cache: Dict[str, Tuple[Any, float]] = {}
477
473
  self.access_count: Dict[str, int] = {}
478
-
474
+
479
475
  # Statistics
480
476
  self.hits = 0
481
477
  self.misses = 0
482
-
478
+
483
479
  def get(self, key: str) -> Optional[Any]:
484
480
  """Get item from cache.
485
-
481
+
486
482
  Args:
487
483
  key: Cache key
488
-
484
+
489
485
  Returns:
490
486
  Cached value or None if not found/expired
491
487
  """
492
488
  if key not in self.cache:
493
489
  self.misses += 1
494
490
  return None
495
-
491
+
496
492
  value, timestamp = self.cache[key]
497
-
493
+
498
494
  # Check TTL
499
495
  if time.time() - timestamp > self.ttl_seconds:
500
496
  del self.cache[key]
501
497
  del self.access_count[key]
502
498
  self.misses += 1
503
499
  return None
504
-
500
+
505
501
  self.hits += 1
506
502
  self.access_count[key] = self.access_count.get(key, 0) + 1
507
503
  return value
508
-
504
+
509
505
  def set(self, key: str, value: Any) -> None:
510
506
  """Set item in cache.
511
-
507
+
512
508
  Args:
513
509
  key: Cache key
514
510
  value: Value to cache
@@ -516,41 +512,41 @@ class StateCache:
516
512
  # Evict if at capacity
517
513
  if len(self.cache) >= self.max_size and key not in self.cache:
518
514
  self._evict_lru()
519
-
515
+
520
516
  self.cache[key] = (value, time.time())
521
517
  self.access_count[key] = 0
522
-
518
+
523
519
  def _evict_lru(self) -> None:
524
520
  """Evict least recently used item."""
525
521
  if not self.cache:
526
522
  return
527
-
523
+
528
524
  # Find LRU item
529
525
  lru_key = min(self.access_count.keys(), key=lambda k: self.access_count[k])
530
-
526
+
531
527
  del self.cache[lru_key]
532
528
  del self.access_count[lru_key]
533
-
529
+
534
530
  def clear(self) -> None:
535
531
  """Clear all cached items."""
536
532
  self.cache.clear()
537
533
  self.access_count.clear()
538
-
534
+
539
535
  def get_stats(self) -> Dict[str, Any]:
540
536
  """Get cache statistics.
541
-
537
+
542
538
  Returns:
543
539
  Dictionary containing cache stats
544
540
  """
545
541
  total_requests = self.hits + self.misses
546
542
  hit_rate = (self.hits / total_requests * 100) if total_requests > 0 else 0
547
-
543
+
548
544
  return {
549
- 'size': len(self.cache),
550
- 'max_size': self.max_size,
551
- 'ttl_seconds': self.ttl_seconds,
552
- 'hits': self.hits,
553
- 'misses': self.misses,
554
- 'hit_rate': round(hit_rate, 2),
555
- 'total_requests': total_requests
556
- }
545
+ "size": len(self.cache),
546
+ "max_size": self.max_size,
547
+ "ttl_seconds": self.ttl_seconds,
548
+ "hits": self.hits,
549
+ "misses": self.misses,
550
+ "hit_rate": round(hit_rate, 2),
551
+ "total_requests": total_requests,
552
+ }