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,3 +1,5 @@
1
+ from pathlib import Path
2
+
1
3
  """
2
4
  Async Claude Session Response Logger with Optimized Performance
3
5
 
@@ -15,23 +17,19 @@ Key Features:
15
17
 
16
18
  import asyncio
17
19
  import json
20
+ import logging
21
+ import logging.handlers
18
22
  import os
19
23
  import sys
20
24
  import time
25
+ from dataclasses import asdict, dataclass
21
26
  from datetime import datetime
22
- from pathlib import Path
23
- from typing import Dict, Any, Optional, Callable
24
- from queue import Queue, Full
25
- from threading import Thread, Lock
26
- import logging
27
- import logging.handlers
28
- from dataclasses import dataclass, asdict
29
27
  from enum import Enum
30
- from claude_mpm.core.constants import (
31
- SystemLimits,
32
- TimeoutConfig,
33
- PerformanceConfig
34
- )
28
+ from queue import Full, Queue
29
+ from threading import Lock, Thread
30
+ from typing import Any, Callable, Dict, Optional
31
+
32
+ from claude_mpm.core.constants import PerformanceConfig, SystemLimits, TimeoutConfig
35
33
 
36
34
  # Import configuration manager
37
35
  from ..core.config import Config
@@ -41,6 +39,7 @@ logger = logging.getLogger(__name__)
41
39
 
42
40
  class LogFormat(Enum):
43
41
  """Supported log formats for response storage."""
42
+
44
43
  JSON = "json"
45
44
  SYSLOG = "syslog"
46
45
  JOURNALD = "journald"
@@ -49,6 +48,7 @@ class LogFormat(Enum):
49
48
  @dataclass
50
49
  class LogEntry:
51
50
  """Represents a log entry to be written."""
51
+
52
52
  timestamp: str
53
53
  agent: str # Standardized field name
54
54
  session_id: str
@@ -61,7 +61,7 @@ class LogEntry:
61
61
  class AsyncSessionLogger:
62
62
  """
63
63
  High-performance async logger with timestamp-based filenames.
64
-
64
+
65
65
  Features:
66
66
  - Non-blocking async writes with background queue processing
67
67
  - Timestamp-based filenames to eliminate lookup overhead
@@ -69,7 +69,7 @@ class AsyncSessionLogger:
69
69
  - Fire-and-forget pattern for zero latency impact
70
70
  - Graceful degradation on errors
71
71
  """
72
-
72
+
73
73
  def __init__(
74
74
  self,
75
75
  base_dir: Optional[Path] = None,
@@ -77,11 +77,11 @@ class AsyncSessionLogger:
77
77
  max_queue_size: Optional[int] = None,
78
78
  enable_async: Optional[bool] = None,
79
79
  enable_compression: Optional[bool] = None,
80
- config: Optional[Config] = None
80
+ config: Optional[Config] = None,
81
81
  ):
82
82
  """
83
83
  Initialize the async session logger.
84
-
84
+
85
85
  Args:
86
86
  base_dir: Base directory for responses (overrides config)
87
87
  log_format: Format to use for logging (overrides config)
@@ -94,86 +94,101 @@ class AsyncSessionLogger:
94
94
  if config is None:
95
95
  config = Config()
96
96
  self.config = config
97
-
97
+
98
98
  # Get response logging configuration section
99
- response_config = self.config.get('response_logging', {})
100
-
99
+ response_config = self.config.get("response_logging", {})
100
+
101
101
  # Apply configuration with parameter overrides
102
- self.base_dir = Path(base_dir or
103
- response_config.get('session_directory', '.claude-mpm/responses'))
104
-
102
+ self.base_dir = Path(
103
+ base_dir
104
+ or response_config.get("session_directory", ".claude-mpm/responses")
105
+ )
106
+
105
107
  # Convert log format string to enum
106
- format_str = response_config.get('format', 'json').lower()
108
+ format_str = response_config.get("format", "json").lower()
107
109
  if log_format is not None:
108
110
  self.log_format = log_format
109
- elif format_str == 'syslog':
111
+ elif format_str == "syslog":
110
112
  self.log_format = LogFormat.SYSLOG
111
- elif format_str == 'journald':
113
+ elif format_str == "journald":
112
114
  self.log_format = LogFormat.JOURNALD
113
115
  else:
114
116
  self.log_format = LogFormat.JSON
115
-
116
- self.max_queue_size = max_queue_size if max_queue_size is not None else response_config.get('max_queue_size', SystemLimits.MAX_QUEUE_SIZE)
117
-
117
+
118
+ self.max_queue_size = (
119
+ max_queue_size
120
+ if max_queue_size is not None
121
+ else response_config.get("max_queue_size", SystemLimits.MAX_QUEUE_SIZE)
122
+ )
123
+
118
124
  # Handle async configuration with backward compatibility
119
125
  if enable_async is not None:
120
126
  self.enable_async = enable_async
121
127
  else:
122
128
  # Check configuration first, then environment variables for backward compatibility
123
- self.enable_async = response_config.get('use_async', True)
129
+ self.enable_async = response_config.get("use_async", True)
124
130
  # Override with environment variable if set (backward compatibility)
125
- if os.environ.get('CLAUDE_USE_ASYNC_LOG'):
126
- self.enable_async = os.environ.get('CLAUDE_USE_ASYNC_LOG', 'true').lower() == 'true'
127
-
131
+ if os.environ.get("CLAUDE_USE_ASYNC_LOG"):
132
+ self.enable_async = (
133
+ os.environ.get("CLAUDE_USE_ASYNC_LOG", "true").lower() == "true"
134
+ )
135
+
128
136
  # Check debug sync mode (forces synchronous for debugging)
129
- if response_config.get('debug_sync', False) or os.environ.get('CLAUDE_LOG_SYNC', '').lower() == 'true':
137
+ if (
138
+ response_config.get("debug_sync", False)
139
+ or os.environ.get("CLAUDE_LOG_SYNC", "").lower() == "true"
140
+ ):
130
141
  logger.info("Debug sync mode enabled - forcing synchronous logging")
131
142
  self.enable_async = False
132
-
133
- self.enable_compression = enable_compression if enable_compression is not None else response_config.get('enable_compression', False)
134
-
143
+
144
+ self.enable_compression = (
145
+ enable_compression
146
+ if enable_compression is not None
147
+ else response_config.get("enable_compression", False)
148
+ )
149
+
135
150
  # Create base directory
136
151
  self.base_dir.mkdir(parents=True, exist_ok=True)
137
-
152
+
138
153
  # Session management
139
154
  self.session_id = self._get_claude_session_id()
140
-
155
+
141
156
  # Async infrastructure
142
157
  self._queue: Queue = Queue(maxsize=self.max_queue_size)
143
158
  self._worker_thread: Optional[Thread] = None
144
159
  self._shutdown = False
145
160
  self._lock = Lock()
146
-
161
+
147
162
  # Statistics
148
163
  self.stats = {
149
164
  "logged": 0,
150
165
  "queued": 0,
151
166
  "dropped": 0,
152
167
  "errors": 0,
153
- "avg_write_time_ms": 0.0
168
+ "avg_write_time_ms": 0.0,
154
169
  }
155
-
170
+
156
171
  # Initialize format-specific handlers
157
172
  self._init_format_handler()
158
-
173
+
159
174
  # Start background worker if async enabled
160
175
  if self.enable_async:
161
176
  self._start_worker()
162
-
177
+
163
178
  def _get_claude_session_id(self) -> str:
164
179
  """Get or generate a Claude session ID."""
165
180
  # Check environment variables in order of preference
166
- for env_var in ['CLAUDE_SESSION_ID', 'ANTHROPIC_SESSION_ID', 'SESSION_ID']:
181
+ for env_var in ["CLAUDE_SESSION_ID", "ANTHROPIC_SESSION_ID", "SESSION_ID"]:
167
182
  session_id = os.environ.get(env_var)
168
183
  if session_id:
169
184
  logger.info(f"Using session ID from {env_var}: {session_id}")
170
185
  return session_id
171
-
186
+
172
187
  # Generate timestamp-based session ID
173
- session_id = datetime.now().strftime('%Y%m%d_%H%M%S')
188
+ session_id = datetime.now().strftime("%Y%m%d_%H%M%S")
174
189
  logger.info(f"Generated session ID: {session_id}")
175
190
  return session_id
176
-
191
+
177
192
  def _init_format_handler(self):
178
193
  """Initialize format-specific logging handlers."""
179
194
  if self.log_format == LogFormat.SYSLOG:
@@ -185,65 +200,66 @@ class AsyncSessionLogger:
185
200
  address = "/dev/log"
186
201
  else:
187
202
  address = ("localhost", 514)
188
-
203
+
189
204
  self.syslog_handler = logging.handlers.SysLogHandler(address=address)
190
205
  self.syslog_handler.setFormatter(
191
- logging.Formatter('claude-mpm[%(process)d]: %(message)s')
206
+ logging.Formatter("claude-mpm[%(process)d]: %(message)s")
192
207
  )
193
208
  logger.info("Initialized syslog handler")
194
209
  except Exception as e:
195
210
  logger.warning(f"Failed to init syslog, falling back to JSON: {e}")
196
211
  self.log_format = LogFormat.JSON
197
-
212
+
198
213
  elif self.log_format == LogFormat.JOURNALD:
199
214
  # Use systemd journal for Linux systems
200
215
  try:
201
216
  from systemd.journal import JournalHandler
217
+
202
218
  self.journal_handler = JournalHandler()
203
- self.journal_handler.setFormatter(
204
- logging.Formatter('%(message)s')
205
- )
219
+ self.journal_handler.setFormatter(logging.Formatter("%(message)s"))
206
220
  logger.info("Initialized journald handler")
207
221
  except ImportError:
208
222
  logger.warning("systemd not available, falling back to JSON")
209
223
  self.log_format = LogFormat.JSON
210
-
224
+
211
225
  def _start_worker(self):
212
226
  """Start the background worker thread for async writes."""
213
227
  with self._lock:
214
228
  if self._worker_thread is None or not self._worker_thread.is_alive():
215
229
  self._shutdown = False
216
230
  self._worker_thread = Thread(
217
- target=self._process_queue,
218
- name="AsyncLoggerWorker",
219
- daemon=True
231
+ target=self._process_queue, name="AsyncLoggerWorker", daemon=True
220
232
  )
221
233
  self._worker_thread.start()
222
234
  logger.debug("Started async logger worker thread")
223
-
235
+
224
236
  def _process_queue(self):
225
237
  """Background worker to process the log queue."""
226
238
  write_times = []
227
-
239
+
228
240
  while not self._shutdown:
229
241
  try:
230
242
  # Get entry with timeout to allow shutdown checks
231
243
  entry = self._queue.get(timeout=TimeoutConfig.QUEUE_GET_TIMEOUT)
232
-
244
+
233
245
  # Time the write operation
234
246
  start_time = time.perf_counter()
235
247
  self._write_entry(entry)
236
- write_time = (time.perf_counter() - start_time) * PerformanceConfig.SECONDS_TO_MS
237
-
248
+ write_time = (
249
+ time.perf_counter() - start_time
250
+ ) * PerformanceConfig.SECONDS_TO_MS
251
+
238
252
  # Update statistics
239
253
  write_times.append(write_time)
240
254
  if len(write_times) > 100:
241
255
  write_times = write_times[-100:] # Keep last 100
242
-
256
+
243
257
  with self._lock:
244
258
  self.stats["logged"] += 1
245
- self.stats["avg_write_time_ms"] = sum(write_times) / len(write_times)
246
-
259
+ self.stats["avg_write_time_ms"] = sum(write_times) / len(
260
+ write_times
261
+ )
262
+
247
263
  except Exception as e:
248
264
  # Check if it's a timeout (queue.Empty) or real error
249
265
  if "Empty" not in str(type(e).__name__):
@@ -251,7 +267,7 @@ class AsyncSessionLogger:
251
267
  with self._lock:
252
268
  self.stats["errors"] += 1
253
269
  # Otherwise it's just a timeout, continue to check shutdown
254
-
270
+
255
271
  def _write_entry(self, entry: LogEntry):
256
272
  """Write a log entry to disk or system log."""
257
273
  try:
@@ -265,63 +281,66 @@ class AsyncSessionLogger:
265
281
  logger.error(f"Failed to write log entry: {e}", exc_info=True)
266
282
  with self._lock:
267
283
  self.stats["errors"] += 1
268
-
284
+
269
285
  def _generate_filename(self, entry: LogEntry) -> str:
270
286
  """
271
287
  Generate a flat filename with session ID, agent, and timestamp.
272
-
288
+
273
289
  Args:
274
290
  entry: Log entry with session, agent, and timestamp info
275
-
291
+
276
292
  Returns:
277
293
  Filename in format: [session_id]-[agent]-timestamp.json
278
294
  """
279
295
  # Format timestamp for filename (remove special chars)
280
- timestamp_str = entry.timestamp.replace(':', '').replace('-', '').replace('.', '_')
281
-
296
+ timestamp_str = (
297
+ entry.timestamp.replace(":", "").replace("-", "").replace(".", "_")
298
+ )
299
+
282
300
  # Create filename: session_id-agent-timestamp.json
283
301
  filename = f"{entry.session_id}-{entry.agent}-{timestamp_str}.json"
284
302
  if self.enable_compression:
285
303
  filename += ".gz"
286
304
  return filename
287
-
305
+
288
306
  def _write_json_entry(self, entry: LogEntry):
289
307
  """Write entry as JSON file with timestamp-based filename."""
290
308
  # Ensure base directory exists (flat structure, no subdirs)
291
309
  self.base_dir.mkdir(parents=True, exist_ok=True)
292
-
310
+
293
311
  # Generate flat filename
294
312
  filename = self._generate_filename(entry)
295
313
  file_path = self.base_dir / filename
296
-
314
+
297
315
  # Prepare data (exclude microseconds field which is internal only)
298
316
  data = asdict(entry)
299
317
  # Remove internal-only field
300
- data.pop('microseconds', None)
301
-
318
+ data.pop("microseconds", None)
319
+
302
320
  # Write file
303
321
  if self.enable_compression:
304
322
  import gzip
305
- with gzip.open(file_path, 'wt', encoding='utf-8') as f:
323
+
324
+ with gzip.open(file_path, "wt", encoding="utf-8") as f:
306
325
  json.dump(data, f, indent=2, ensure_ascii=False)
307
326
  else:
308
- with open(file_path, 'w', encoding='utf-8') as f:
327
+ with open(file_path, "w", encoding="utf-8") as f:
309
328
  json.dump(data, f, indent=2, ensure_ascii=False)
310
-
329
+
311
330
  logger.debug(f"Wrote log entry to {file_path}")
312
-
331
+
313
332
  def _write_syslog_entry(self, entry: LogEntry):
314
333
  """Write entry to syslog for OS-level performance."""
315
- if hasattr(self, 'syslog_handler'):
334
+ if hasattr(self, "syslog_handler"):
316
335
  # Format as structured log message with standardized field names
317
336
  msg = (
318
337
  f"agent={entry.agent} "
319
338
  f"session={entry.session_id} "
320
- f"request=\"{entry.request[:100]}\" "
339
+ f'request="{entry.request[:100]}" '
321
340
  f"response_len={len(entry.response)} "
322
341
  f"metadata={json.dumps(entry.metadata)}"
323
342
  )
324
-
343
+
325
344
  record = logging.LogRecord(
326
345
  name="claude-mpm",
327
346
  level=logging.INFO,
@@ -329,14 +348,14 @@ class AsyncSessionLogger:
329
348
  lineno=0,
330
349
  msg=msg,
331
350
  args=(),
332
- exc_info=None
351
+ exc_info=None,
333
352
  )
334
-
353
+
335
354
  self.syslog_handler.emit(record)
336
-
355
+
337
356
  def _write_journald_entry(self, entry: LogEntry):
338
357
  """Write entry to systemd journal."""
339
- if hasattr(self, 'journal_handler'):
358
+ if hasattr(self, "journal_handler"):
340
359
  # Create structured journal entry with standardized field names
341
360
  record = logging.LogRecord(
342
361
  name="claude-mpm",
@@ -345,36 +364,38 @@ class AsyncSessionLogger:
345
364
  lineno=0,
346
365
  msg=f"Claude MPM Response: {entry.request[:100]}",
347
366
  args=(),
348
- exc_info=None
367
+ exc_info=None,
349
368
  )
350
-
369
+
351
370
  # Add structured fields with standardized names
352
- record.__dict__.update({
353
- 'AGENT': entry.agent,
354
- 'SESSION_ID': entry.session_id,
355
- 'REQUEST': entry.request,
356
- 'RESPONSE_LENGTH': len(entry.response),
357
- 'METADATA': json.dumps(entry.metadata)
358
- })
359
-
371
+ record.__dict__.update(
372
+ {
373
+ "AGENT": entry.agent,
374
+ "SESSION_ID": entry.session_id,
375
+ "REQUEST": entry.request,
376
+ "RESPONSE_LENGTH": len(entry.response),
377
+ "METADATA": json.dumps(entry.metadata),
378
+ }
379
+ )
380
+
360
381
  self.journal_handler.emit(record)
361
-
382
+
362
383
  def log_response(
363
384
  self,
364
385
  request_summary: str,
365
386
  response_content: str,
366
387
  metadata: Optional[Dict[str, Any]] = None,
367
- agent: Optional[str] = None
388
+ agent: Optional[str] = None,
368
389
  ) -> bool:
369
390
  """
370
391
  Log a response with fire-and-forget async pattern.
371
-
392
+
372
393
  Args:
373
394
  request_summary: Brief summary of the request
374
395
  response_content: The full response content
375
396
  metadata: Optional metadata (agent name, model, etc.)
376
397
  agent: Optional agent name (overrides metadata)
377
-
398
+
378
399
  Returns:
379
400
  True if queued successfully, False if dropped
380
401
  """
@@ -384,12 +405,12 @@ class AsyncSessionLogger:
384
405
  agent_name = agent.replace(" ", "_").lower()
385
406
  elif metadata and "agent" in metadata:
386
407
  agent_name = metadata["agent"].replace(" ", "_").lower()
387
-
408
+
388
409
  # Create timestamp with microsecond precision
389
410
  now = datetime.now()
390
411
  timestamp = now.isoformat()
391
412
  microseconds = now.microsecond
392
-
413
+
393
414
  # Create log entry with standardized field names
394
415
  entry = LogEntry(
395
416
  timestamp=timestamp,
@@ -398,9 +419,9 @@ class AsyncSessionLogger:
398
419
  request=request_summary, # Standardized field name
399
420
  response=response_content, # Standardized field name
400
421
  metadata=metadata or {},
401
- microseconds=microseconds
422
+ microseconds=microseconds,
402
423
  )
403
-
424
+
404
425
  # Queue for async processing or write directly
405
426
  if self.enable_async:
406
427
  try:
@@ -418,62 +439,64 @@ class AsyncSessionLogger:
418
439
  # Synchronous write for debugging
419
440
  self._write_entry(entry)
420
441
  return True
421
-
442
+
422
443
  def flush(self, timeout: float = 5.0) -> bool:
423
444
  """
424
445
  Flush pending log entries with timeout.
425
-
446
+
426
447
  Args:
427
448
  timeout: Maximum time to wait for flush
428
-
449
+
429
450
  Returns:
430
451
  True if all entries flushed, False if timeout
431
452
  """
432
453
  if not self.enable_async:
433
454
  return True
434
-
455
+
435
456
  start_time = time.time()
436
457
  while not self._queue.empty():
437
458
  if time.time() - start_time > timeout:
438
- logger.warning(f"Flush timeout with {self._queue.qsize()} entries remaining")
459
+ logger.warning(
460
+ f"Flush timeout with {self._queue.qsize()} entries remaining"
461
+ )
439
462
  return False
440
463
  time.sleep(0.01)
441
-
464
+
442
465
  return True
443
-
466
+
444
467
  def shutdown(self, timeout: float = 5.0):
445
468
  """
446
469
  Gracefully shutdown the logger.
447
-
470
+
448
471
  Args:
449
472
  timeout: Maximum time to wait for shutdown
450
473
  """
451
474
  if self.enable_async:
452
475
  logger.info("Shutting down async logger")
453
-
476
+
454
477
  # Signal shutdown
455
478
  self._shutdown = True
456
-
479
+
457
480
  # Wait for worker to finish
458
481
  if self._worker_thread and self._worker_thread.is_alive():
459
482
  self._worker_thread.join(timeout)
460
-
483
+
461
484
  if self._worker_thread.is_alive():
462
485
  logger.warning("Worker thread did not shutdown cleanly")
463
-
486
+
464
487
  # Log final statistics
465
488
  logger.info(f"Logger stats: {self.stats}")
466
-
489
+
467
490
  def get_stats(self) -> Dict[str, Any]:
468
491
  """Get logger statistics."""
469
492
  with self._lock:
470
493
  return self.stats.copy()
471
-
494
+
472
495
  def set_session_id(self, session_id: str):
473
496
  """Set a new session ID."""
474
497
  self.session_id = session_id
475
498
  logger.info(f"Session ID updated to: {session_id}")
476
-
499
+
477
500
  def is_enabled(self) -> bool:
478
501
  """Check if logging is enabled."""
479
502
  return True # Always enabled in this implementation
@@ -487,71 +510,80 @@ _logger_lock = Lock()
487
510
  def get_async_logger(
488
511
  log_format: Optional[LogFormat] = None,
489
512
  enable_async: Optional[bool] = None,
490
- config: Optional[Config] = None
513
+ config: Optional[Config] = None,
491
514
  ) -> AsyncSessionLogger:
492
515
  """
493
516
  Get the singleton async logger instance.
494
-
517
+
495
518
  Args:
496
519
  log_format: Optional log format override
497
520
  enable_async: Enable async mode override
498
521
  config: Optional configuration instance to use
499
-
522
+
500
523
  Returns:
501
524
  The shared AsyncSessionLogger instance
502
525
  """
503
526
  global _logger_instance
504
-
527
+
505
528
  with _logger_lock:
506
529
  if _logger_instance is None:
507
530
  # Load configuration if not provided
508
531
  if config is None:
509
532
  config = Config()
510
-
533
+
511
534
  # Get response logging configuration
512
- response_config = config.get('response_logging', {})
513
-
535
+ response_config = config.get("response_logging", {})
536
+
514
537
  # Determine log format
515
538
  if log_format is None:
516
539
  # Check configuration first
517
- format_str = response_config.get('format', 'json').lower()
518
-
540
+ format_str = response_config.get("format", "json").lower()
541
+
519
542
  # Check environment for backward compatibility
520
- format_env = os.environ.get('CLAUDE_LOG_FORMAT', '').lower()
543
+ format_env = os.environ.get("CLAUDE_LOG_FORMAT", "").lower()
521
544
  if format_env:
522
- logger.info(f"Using CLAUDE_LOG_FORMAT environment variable (deprecated): {format_env}")
545
+ logger.info(
546
+ f"Using CLAUDE_LOG_FORMAT environment variable (deprecated): {format_env}"
547
+ )
523
548
  format_str = format_env
524
-
525
- if format_str == 'syslog':
549
+
550
+ if format_str == "syslog":
526
551
  log_format = LogFormat.SYSLOG
527
- elif format_str == 'journald':
552
+ elif format_str == "journald":
528
553
  log_format = LogFormat.JOURNALD
529
554
  else:
530
555
  log_format = LogFormat.JSON
531
-
556
+
532
557
  # Determine async mode if not specified
533
558
  if enable_async is None:
534
559
  # Configuration takes precedence
535
- enable_async = response_config.get('use_async', True)
536
-
560
+ enable_async = response_config.get("use_async", True)
561
+
537
562
  # Check environment for backward compatibility
538
- if os.environ.get('CLAUDE_USE_ASYNC_LOG'):
539
- env_async = os.environ.get('CLAUDE_USE_ASYNC_LOG', 'true').lower() == 'true'
540
- logger.info(f"Using CLAUDE_USE_ASYNC_LOG environment variable (deprecated): {env_async}")
563
+ if os.environ.get("CLAUDE_USE_ASYNC_LOG"):
564
+ env_async = (
565
+ os.environ.get("CLAUDE_USE_ASYNC_LOG", "true").lower() == "true"
566
+ )
567
+ logger.info(
568
+ f"Using CLAUDE_USE_ASYNC_LOG environment variable (deprecated): {env_async}"
569
+ )
541
570
  enable_async = env_async
542
-
571
+
543
572
  # Debug sync mode overrides everything
544
- if response_config.get('debug_sync', False) or os.environ.get('CLAUDE_LOG_SYNC', '').lower() == 'true':
545
- if os.environ.get('CLAUDE_LOG_SYNC'):
546
- logger.info("Using CLAUDE_LOG_SYNC environment variable (deprecated)")
573
+ if (
574
+ response_config.get("debug_sync", False)
575
+ or os.environ.get("CLAUDE_LOG_SYNC", "").lower() == "true"
576
+ ):
577
+ if os.environ.get("CLAUDE_LOG_SYNC"):
578
+ logger.info(
579
+ "Using CLAUDE_LOG_SYNC environment variable (deprecated)"
580
+ )
547
581
  enable_async = False
548
-
582
+
549
583
  _logger_instance = AsyncSessionLogger(
550
- log_format=log_format,
551
- enable_async=enable_async,
552
- config=config
584
+ log_format=log_format, enable_async=enable_async, config=config
553
585
  )
554
-
586
+
555
587
  return _logger_instance
556
588
 
557
589
 
@@ -559,17 +591,17 @@ def log_response_async(
559
591
  request_summary: str,
560
592
  response_content: str,
561
593
  metadata: Optional[Dict[str, Any]] = None,
562
- agent: Optional[str] = None
594
+ agent: Optional[str] = None,
563
595
  ) -> bool:
564
596
  """
565
597
  Convenience function for async response logging.
566
-
598
+
567
599
  Args:
568
600
  request_summary: Brief summary of the request
569
601
  response_content: The full response content
570
602
  metadata: Optional metadata
571
603
  agent: Optional agent name
572
-
604
+
573
605
  Returns:
574
606
  True if logged/queued successfully
575
607
  """
@@ -580,10 +612,12 @@ def log_response_async(
580
612
  # Cleanup on module unload
581
613
  import atexit
582
614
 
615
+
583
616
  def _cleanup():
584
617
  """Cleanup function called on exit."""
585
618
  global _logger_instance
586
619
  if _logger_instance:
587
620
  _logger_instance.shutdown()
588
621
 
589
- atexit.register(_cleanup)
622
+
623
+ atexit.register(_cleanup)