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
@@ -8,18 +8,19 @@ Supports multiple file formats and summarization strategies.
8
8
  Part of ISS-0037: Document Summarizer Tool - Intelligent Document Processing
9
9
  """
10
10
 
11
- import os
12
- import re
13
- import json
14
- import yaml
15
11
  import csv
12
+ import hashlib
13
+ import json
16
14
  import mimetypes
17
- from pathlib import Path
18
- from typing import Any, Dict, List, Optional, Tuple
15
+ import os
16
+ import re
17
+ from collections import OrderedDict
19
18
  from datetime import datetime
20
19
  from functools import lru_cache
21
- from collections import OrderedDict
22
- import hashlib
20
+ from pathlib import Path
21
+ from typing import Any, Dict, List, Optional, Tuple
22
+
23
+ import yaml
23
24
 
24
25
  from claude_mpm.services.mcp_gateway.core.interfaces import (
25
26
  MCPToolDefinition,
@@ -32,15 +33,15 @@ from claude_mpm.services.mcp_gateway.tools.base_adapter import BaseToolAdapter
32
33
  class LRUCache:
33
34
  """
34
35
  Simple LRU cache implementation for document summaries.
35
-
36
+
36
37
  WHY: We need a memory-efficient cache to avoid re-processing documents
37
38
  that are accessed repeatedly, which is common in Claude Code sessions.
38
39
  """
39
-
40
+
40
41
  def __init__(self, max_size: int = 100, max_memory_mb: int = 100):
41
42
  """
42
43
  Initialize LRU cache.
43
-
44
+
44
45
  Args:
45
46
  max_size: Maximum number of entries
46
47
  max_memory_mb: Maximum memory usage in MB
@@ -51,7 +52,7 @@ class LRUCache:
51
52
  self.current_memory = 0
52
53
  self.hits = 0
53
54
  self.misses = 0
54
-
55
+
55
56
  def get(self, key: str) -> Optional[Dict[str, Any]]:
56
57
  """Get item from cache, updating LRU order."""
57
58
  if key in self.cache:
@@ -61,63 +62,69 @@ class LRUCache:
61
62
  return self.cache[key]
62
63
  self.misses += 1
63
64
  return None
64
-
65
+
65
66
  def put(self, key: str, value: Dict[str, Any], size_bytes: int) -> None:
66
67
  """Add item to cache, evicting LRU items if necessary."""
67
68
  # Remove item if it already exists
68
69
  if key in self.cache:
69
- old_size = self.cache[key].get('size_bytes', 0)
70
+ old_size = self.cache[key].get("size_bytes", 0)
70
71
  self.current_memory -= old_size
71
72
  del self.cache[key]
72
-
73
+
73
74
  # Evict items if necessary
74
- while (len(self.cache) >= self.max_size or
75
- self.current_memory + size_bytes > self.max_memory_bytes):
75
+ while (
76
+ len(self.cache) >= self.max_size
77
+ or self.current_memory + size_bytes > self.max_memory_bytes
78
+ ):
76
79
  if not self.cache:
77
80
  break
78
81
  # Remove least recently used item
79
82
  removed_key, removed_value = self.cache.popitem(last=False)
80
- self.current_memory -= removed_value.get('size_bytes', 0)
81
-
83
+ self.current_memory -= removed_value.get("size_bytes", 0)
84
+
82
85
  # Add new item
83
- value['size_bytes'] = size_bytes
86
+ value["size_bytes"] = size_bytes
84
87
  self.cache[key] = value
85
88
  self.current_memory += size_bytes
86
-
89
+
87
90
  def get_stats(self) -> Dict[str, Any]:
88
91
  """Get cache statistics."""
89
- hit_rate = self.hits / (self.hits + self.misses) if (self.hits + self.misses) > 0 else 0
92
+ hit_rate = (
93
+ self.hits / (self.hits + self.misses)
94
+ if (self.hits + self.misses) > 0
95
+ else 0
96
+ )
90
97
  return {
91
- 'size': len(self.cache),
92
- 'memory_mb': self.current_memory / (1024 * 1024),
93
- 'hits': self.hits,
94
- 'misses': self.misses,
95
- 'hit_rate': hit_rate
98
+ "size": len(self.cache),
99
+ "memory_mb": self.current_memory / (1024 * 1024),
100
+ "hits": self.hits,
101
+ "misses": self.misses,
102
+ "hit_rate": hit_rate,
96
103
  }
97
104
 
98
105
 
99
106
  class DocumentSummarizerTool(BaseToolAdapter):
100
107
  """
101
108
  Document summarizer tool for intelligent document processing.
102
-
109
+
103
110
  WHY: Claude Code accumulates massive memory from reading full files,
104
111
  leading to context overflow. This tool reduces document size by 60%+
105
112
  while preserving essential information through intelligent summarization.
106
-
113
+
107
114
  DESIGN DECISIONS:
108
115
  - Use sentence boundary detection to preserve readability
109
116
  - Implement multiple summarization modes for different use cases
110
117
  - Cache summaries to avoid re-processing frequently accessed files
111
118
  - Support common file formats used in development
112
119
  """
113
-
120
+
114
121
  # File size limits (in bytes)
115
122
  MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
116
123
  CHUNK_SIZE = 50000 # Characters per chunk for large files
117
-
124
+
118
125
  # Token estimation (rough approximation)
119
126
  CHARS_PER_TOKEN = 4 # Approximate for Claude's tokenizer
120
-
127
+
121
128
  def __init__(self):
122
129
  """Initialize the document summarizer tool."""
123
130
  definition = MCPToolDefinition(
@@ -128,408 +135,454 @@ class DocumentSummarizerTool(BaseToolAdapter):
128
135
  "properties": {
129
136
  "file_path": {
130
137
  "type": "string",
131
- "description": "Path to the document file"
138
+ "description": "Path to the document file",
132
139
  },
133
140
  "mode": {
134
141
  "type": "string",
135
142
  "enum": ["brief", "detailed", "key_points", "technical"],
136
143
  "description": "Summarization mode",
137
- "default": "brief"
144
+ "default": "brief",
138
145
  },
139
146
  "max_tokens": {
140
147
  "type": "integer",
141
148
  "description": "Maximum tokens in summary (optional)",
142
149
  "minimum": 100,
143
- "maximum": 10000
150
+ "maximum": 10000,
144
151
  },
145
152
  "max_percentage": {
146
153
  "type": "integer",
147
154
  "description": "Maximum percentage of original to keep (1-100)",
148
155
  "minimum": 1,
149
156
  "maximum": 100,
150
- "default": 40
157
+ "default": 40,
151
158
  },
152
159
  "preserve_code": {
153
160
  "type": "boolean",
154
161
  "description": "Whether to preserve code blocks intact",
155
- "default": True
162
+ "default": True,
156
163
  },
157
164
  "use_cache": {
158
165
  "type": "boolean",
159
166
  "description": "Whether to use cached summaries",
160
- "default": True
161
- }
167
+ "default": True,
168
+ },
162
169
  },
163
- "required": ["file_path"]
170
+ "required": ["file_path"],
164
171
  },
165
172
  output_schema={
166
173
  "type": "object",
167
174
  "properties": {
168
175
  "summary": {
169
176
  "type": "string",
170
- "description": "The summarized content"
177
+ "description": "The summarized content",
171
178
  },
172
179
  "original_size": {
173
180
  "type": "integer",
174
- "description": "Original document size in bytes"
181
+ "description": "Original document size in bytes",
175
182
  },
176
183
  "summary_size": {
177
184
  "type": "integer",
178
- "description": "Summary size in bytes"
185
+ "description": "Summary size in bytes",
179
186
  },
180
187
  "reduction_percentage": {
181
188
  "type": "number",
182
- "description": "Percentage reduction achieved"
189
+ "description": "Percentage reduction achieved",
183
190
  },
184
191
  "token_estimate": {
185
192
  "type": "object",
186
193
  "properties": {
187
194
  "original": {"type": "integer"},
188
195
  "summary": {"type": "integer"},
189
- "saved": {"type": "integer"}
190
- }
196
+ "saved": {"type": "integer"},
197
+ },
191
198
  },
192
199
  "chunks_processed": {
193
200
  "type": "integer",
194
- "description": "Number of chunks processed for large files"
201
+ "description": "Number of chunks processed for large files",
195
202
  },
196
203
  "cache_hit": {
197
204
  "type": "boolean",
198
- "description": "Whether summary was retrieved from cache"
199
- }
200
- }
205
+ "description": "Whether summary was retrieved from cache",
206
+ },
207
+ },
201
208
  },
202
209
  version="1.0.0",
203
210
  metadata={
204
211
  "category": "document_processing",
205
- "supported_formats": ["txt", "md", "pdf", "docx", "json", "yaml", "csv", "py", "js", "ts", "java", "cpp", "c", "h", "hpp"]
206
- }
212
+ "supported_formats": [
213
+ "txt",
214
+ "md",
215
+ "pdf",
216
+ "docx",
217
+ "json",
218
+ "yaml",
219
+ "csv",
220
+ "py",
221
+ "js",
222
+ "ts",
223
+ "java",
224
+ "cpp",
225
+ "c",
226
+ "h",
227
+ "hpp",
228
+ ],
229
+ },
207
230
  )
208
231
  super().__init__(definition)
209
-
232
+
210
233
  # Initialize cache
211
234
  self._cache = LRUCache(max_size=100, max_memory_mb=50)
212
-
235
+
213
236
  # Sentence boundary patterns
214
- self._sentence_endings = re.compile(r'[.!?]\s+')
215
-
237
+ self._sentence_endings = re.compile(r"[.!?]\s+")
238
+
216
239
  # Code block patterns for different formats
217
240
  self._code_patterns = {
218
- 'markdown': re.compile(r'```[\s\S]*?```', re.MULTILINE),
219
- 'inline': re.compile(r'`[^`]+`'),
220
- 'indent': re.compile(r'^( |\t).*$', re.MULTILINE)
241
+ "markdown": re.compile(r"```[\s\S]*?```", re.MULTILINE),
242
+ "inline": re.compile(r"`[^`]+`"),
243
+ "indent": re.compile(r"^( |\t).*$", re.MULTILINE),
221
244
  }
222
-
245
+
223
246
  def _get_file_hash(self, file_path: str) -> str:
224
247
  """Generate hash for file caching."""
225
248
  stat = os.stat(file_path)
226
249
  hash_input = f"{file_path}:{stat.st_size}:{stat.st_mtime}"
227
250
  return hashlib.md5(hash_input.encode()).hexdigest()
228
-
251
+
229
252
  def _estimate_tokens(self, text: str) -> int:
230
253
  """Estimate token count for text."""
231
254
  return len(text) // self.CHARS_PER_TOKEN
232
-
255
+
233
256
  def _validate_file(self, file_path: str) -> Tuple[bool, Optional[str]]:
234
257
  """
235
258
  Validate file for processing.
236
-
259
+
237
260
  Returns:
238
261
  Tuple of (is_valid, error_message)
239
262
  """
240
263
  path = Path(file_path)
241
-
264
+
242
265
  # Check if file exists
243
266
  if not path.exists():
244
267
  return False, f"File not found: {file_path}"
245
-
268
+
246
269
  # Check if it's a file (not directory)
247
270
  if not path.is_file():
248
271
  return False, f"Path is not a file: {file_path}"
249
-
272
+
250
273
  # Check file size
251
274
  file_size = path.stat().st_size
252
275
  if file_size > self.MAX_FILE_SIZE:
253
- return False, f"File too large: {file_size} bytes (max: {self.MAX_FILE_SIZE})"
254
-
276
+ return (
277
+ False,
278
+ f"File too large: {file_size} bytes (max: {self.MAX_FILE_SIZE})",
279
+ )
280
+
255
281
  # Check file extension
256
- extension = path.suffix.lower().lstrip('.')
257
- supported = self._definition.metadata.get('supported_formats', [])
282
+ extension = path.suffix.lower().lstrip(".")
283
+ supported = self._definition.metadata.get("supported_formats", [])
258
284
  if extension and extension not in supported:
259
285
  # Try to detect by mime type
260
286
  mime_type, _ = mimetypes.guess_type(file_path)
261
- if not mime_type or not mime_type.startswith('text/'):
287
+ if not mime_type or not mime_type.startswith("text/"):
262
288
  return False, f"Unsupported file format: {extension}"
263
-
289
+
264
290
  return True, None
265
-
291
+
266
292
  def _read_file(self, file_path: str) -> str:
267
293
  """
268
294
  Read file content with appropriate encoding.
269
-
295
+
270
296
  Args:
271
297
  file_path: Path to file
272
-
298
+
273
299
  Returns:
274
300
  File content as string
275
301
  """
276
302
  path = Path(file_path)
277
-
303
+
278
304
  # Try different encodings
279
- encodings = ['utf-8', 'latin-1', 'cp1252']
280
-
305
+ encodings = ["utf-8", "latin-1", "cp1252"]
306
+
281
307
  for encoding in encodings:
282
308
  try:
283
309
  return path.read_text(encoding=encoding)
284
310
  except UnicodeDecodeError:
285
311
  continue
286
-
312
+
287
313
  # If all fail, read as binary and decode with errors='ignore'
288
- with open(file_path, 'rb') as f:
314
+ with open(file_path, "rb") as f:
289
315
  content = f.read()
290
- return content.decode('utf-8', errors='ignore')
291
-
316
+ return content.decode("utf-8", errors="ignore")
317
+
292
318
  def _extract_code_blocks(self, text: str) -> Tuple[List[str], str]:
293
319
  """
294
320
  Extract code blocks from text for preservation.
295
-
321
+
296
322
  Returns:
297
323
  Tuple of (code_blocks, text_without_code)
298
324
  """
299
325
  code_blocks = []
300
326
  placeholder_template = "[[CODE_BLOCK_{}]]"
301
-
327
+
302
328
  # Extract markdown code blocks
303
- for match in self._code_patterns['markdown'].finditer(text):
329
+ for match in self._code_patterns["markdown"].finditer(text):
304
330
  code_blocks.append(match.group(0))
305
- text = text.replace(match.group(0), placeholder_template.format(len(code_blocks) - 1))
306
-
331
+ text = text.replace(
332
+ match.group(0), placeholder_template.format(len(code_blocks) - 1)
333
+ )
334
+
307
335
  return code_blocks, text
308
-
336
+
309
337
  def _restore_code_blocks(self, text: str, code_blocks: List[str]) -> str:
310
338
  """Restore code blocks to summarized text."""
311
339
  for i, block in enumerate(code_blocks):
312
340
  placeholder = f"[[CODE_BLOCK_{i}]]"
313
341
  text = text.replace(placeholder, block)
314
342
  return text
315
-
343
+
316
344
  def _truncate_at_sentence(self, text: str, max_chars: int) -> str:
317
345
  """
318
346
  Truncate text at sentence boundary.
319
-
347
+
320
348
  WHY: Truncating mid-sentence makes summaries harder to read and
321
349
  can lose important context. Sentence boundaries preserve meaning.
322
350
  """
323
351
  if len(text) <= max_chars:
324
352
  return text
325
-
353
+
326
354
  # Find sentence boundaries
327
355
  sentences = self._sentence_endings.split(text)
328
-
356
+
329
357
  result = []
330
358
  current_length = 0
331
-
359
+
332
360
  for i, sentence in enumerate(sentences):
333
361
  # Add sentence ending back if not last sentence
334
362
  if i < len(sentences) - 1:
335
- sentence += '. '
336
-
363
+ sentence += ". "
364
+
337
365
  if current_length + len(sentence) <= max_chars:
338
366
  result.append(sentence)
339
367
  current_length += len(sentence)
340
368
  else:
341
369
  # Add partial sentence if we haven't added anything yet
342
370
  if not result and sentence:
343
- result.append(sentence[:max_chars - 3] + '...')
371
+ result.append(sentence[: max_chars - 3] + "...")
344
372
  break
345
-
346
- return ''.join(result)
347
-
373
+
374
+ return "".join(result)
375
+
348
376
  def _summarize_brief(self, text: str, max_chars: int) -> str:
349
377
  """
350
378
  Brief summarization - first and last portions.
351
-
379
+
352
380
  WHY: For quick overview, showing beginning and end gives context
353
381
  about what the document covers and its conclusions.
354
382
  """
355
383
  if len(text) <= max_chars:
356
384
  return text
357
-
385
+
358
386
  # Split available space between beginning and end
359
387
  half_chars = max_chars // 2 - 20 # Reserve space for separator
360
-
388
+
361
389
  beginning = self._truncate_at_sentence(text, half_chars)
362
- ending = self._truncate_at_sentence(text[-half_chars * 2:], half_chars)
363
-
390
+ ending = self._truncate_at_sentence(text[-half_chars * 2 :], half_chars)
391
+
364
392
  return f"{beginning}\n\n[... content omitted for brevity ...]\n\n{ending}"
365
-
393
+
366
394
  def _summarize_detailed(self, text: str, max_chars: int) -> str:
367
395
  """
368
396
  Detailed summarization - extract key paragraphs.
369
-
397
+
370
398
  WHY: For technical documents, we want to preserve more structure
371
399
  and include middle sections that might contain important details.
372
400
  """
373
401
  if len(text) <= max_chars:
374
402
  return text
375
-
403
+
376
404
  # Split into paragraphs
377
- paragraphs = text.split('\n\n')
378
-
405
+ paragraphs = text.split("\n\n")
406
+
379
407
  # Calculate importance scores (based on length and position)
380
408
  scored_paragraphs = []
381
409
  for i, para in enumerate(paragraphs):
382
410
  # Skip empty paragraphs
383
411
  if not para.strip():
384
412
  continue
385
-
413
+
386
414
  # Score based on position (beginning and end are important)
387
415
  position_score = 1.0
388
416
  if i < 3: # First 3 paragraphs
389
417
  position_score = 2.0
390
418
  elif i >= len(paragraphs) - 3: # Last 3 paragraphs
391
419
  position_score = 1.5
392
-
420
+
393
421
  # Score based on content indicators
394
422
  content_score = 1.0
395
- if any(keyword in para.lower() for keyword in ['summary', 'conclusion', 'important', 'note', 'warning']):
423
+ if any(
424
+ keyword in para.lower()
425
+ for keyword in ["summary", "conclusion", "important", "note", "warning"]
426
+ ):
396
427
  content_score = 1.5
397
-
428
+
398
429
  score = position_score * content_score * (1 + len(para) / 1000)
399
430
  scored_paragraphs.append((score, i, para))
400
-
431
+
401
432
  # Sort by score and select top paragraphs
402
433
  scored_paragraphs.sort(reverse=True)
403
-
434
+
404
435
  selected = []
405
436
  current_length = 0
406
-
437
+
407
438
  for score, original_index, para in scored_paragraphs:
408
- truncated_para = self._truncate_at_sentence(para, max_chars - current_length)
439
+ truncated_para = self._truncate_at_sentence(
440
+ para, max_chars - current_length
441
+ )
409
442
  if current_length + len(truncated_para) <= max_chars:
410
443
  selected.append((original_index, truncated_para))
411
444
  current_length += len(truncated_para) + 2 # Account for newlines
412
-
445
+
413
446
  if current_length >= max_chars * 0.9: # Stop at 90% to leave some buffer
414
447
  break
415
-
448
+
416
449
  # Sort selected paragraphs by original order
417
450
  selected.sort()
418
-
419
- return '\n\n'.join(para for _, para in selected)
420
-
451
+
452
+ return "\n\n".join(para for _, para in selected)
453
+
421
454
  def _summarize_key_points(self, text: str, max_chars: int) -> str:
422
455
  """
423
456
  Extract key points and bullet points.
424
-
457
+
425
458
  WHY: Many documents have lists, bullet points, or numbered items
426
459
  that contain the most important information in condensed form.
427
460
  """
428
461
  if len(text) <= max_chars:
429
462
  return text
430
-
431
- lines = text.split('\n')
463
+
464
+ lines = text.split("\n")
432
465
  key_lines = []
433
-
466
+
434
467
  # Patterns for identifying key points
435
468
  list_patterns = [
436
- re.compile(r'^\s*[-*•]\s+'), # Bullet points
437
- re.compile(r'^\s*\d+[.)]\s+'), # Numbered lists
438
- re.compile(r'^\s*[A-Z][.)]\s+'), # Letter lists
439
- re.compile(r'^#+\s+'), # Markdown headers
440
- re.compile(r'^[A-Z][^.!?]*:'), # Definition lists
469
+ re.compile(r"^\s*[-*•]\s+"), # Bullet points
470
+ re.compile(r"^\s*\d+[.)]\s+"), # Numbered lists
471
+ re.compile(r"^\s*[A-Z][.)]\s+"), # Letter lists
472
+ re.compile(r"^#+\s+"), # Markdown headers
473
+ re.compile(r"^[A-Z][^.!?]*:"), # Definition lists
441
474
  ]
442
-
475
+
443
476
  # Extract lines that match key point patterns
444
477
  for line in lines:
445
478
  if any(pattern.match(line) for pattern in list_patterns):
446
479
  key_lines.append(line)
447
-
480
+
448
481
  # If we found key points, use them
449
482
  if key_lines:
450
- result = '\n'.join(key_lines)
483
+ result = "\n".join(key_lines)
451
484
  if len(result) <= max_chars:
452
485
  return result
453
486
  else:
454
487
  return self._truncate_at_sentence(result, max_chars)
455
-
488
+
456
489
  # Fallback to brief summary if no key points found
457
490
  return self._summarize_brief(text, max_chars)
458
-
459
- def _summarize_technical(self, text: str, max_chars: int, preserve_code: bool) -> str:
491
+
492
+ def _summarize_technical(
493
+ self, text: str, max_chars: int, preserve_code: bool
494
+ ) -> str:
460
495
  """
461
496
  Technical summarization - preserve code and technical details.
462
-
497
+
463
498
  WHY: For code files and technical documentation, we need to
464
499
  preserve function signatures, class definitions, and important code.
465
500
  """
466
501
  if len(text) <= max_chars:
467
502
  return text
468
-
503
+
469
504
  # Extract and preserve code blocks if requested
470
505
  code_blocks = []
471
506
  text_without_code = text
472
-
507
+
473
508
  if preserve_code:
474
509
  code_blocks, text_without_code = self._extract_code_blocks(text)
475
-
510
+
476
511
  # Extract technical patterns
477
512
  tech_patterns = [
478
- re.compile(r'^(class|def|function|interface|struct)\s+\w+.*$', re.MULTILINE), # Definitions
479
- re.compile(r'^(import|from|require|include|using)\s+.*$', re.MULTILINE), # Imports
480
- re.compile(r'^\s*@\w+.*$', re.MULTILINE), # Decorators/Annotations
481
- re.compile(r'^(public|private|protected|static).*\{?$', re.MULTILINE), # Method signatures
513
+ re.compile(
514
+ r"^(class|def|function|interface|struct)\s+\w+.*$", re.MULTILINE
515
+ ), # Definitions
516
+ re.compile(
517
+ r"^(import|from|require|include|using)\s+.*$", re.MULTILINE
518
+ ), # Imports
519
+ re.compile(r"^\s*@\w+.*$", re.MULTILINE), # Decorators/Annotations
520
+ re.compile(
521
+ r"^(public|private|protected|static).*\{?$", re.MULTILINE
522
+ ), # Method signatures
482
523
  ]
483
-
524
+
484
525
  important_lines = []
485
526
  for pattern in tech_patterns:
486
527
  important_lines.extend(pattern.findall(text_without_code))
487
-
528
+
488
529
  # Build technical summary
489
530
  result_parts = []
490
-
531
+
491
532
  # Add imports/includes first
492
- imports = [line for line in important_lines if any(
493
- keyword in line for keyword in ['import', 'from', 'require', 'include', 'using']
494
- )]
533
+ imports = [
534
+ line
535
+ for line in important_lines
536
+ if any(
537
+ keyword in line
538
+ for keyword in ["import", "from", "require", "include", "using"]
539
+ )
540
+ ]
495
541
  if imports:
496
- result_parts.append("# Imports/Dependencies\n" + '\n'.join(imports[:10]))
497
-
542
+ result_parts.append("# Imports/Dependencies\n" + "\n".join(imports[:10]))
543
+
498
544
  # Add class/function definitions
499
- definitions = [line for line in important_lines if any(
500
- keyword in line for keyword in ['class', 'def', 'function', 'interface', 'struct']
501
- )]
545
+ definitions = [
546
+ line
547
+ for line in important_lines
548
+ if any(
549
+ keyword in line
550
+ for keyword in ["class", "def", "function", "interface", "struct"]
551
+ )
552
+ ]
502
553
  if definitions:
503
- result_parts.append("# Key Definitions\n" + '\n'.join(definitions[:20]))
504
-
554
+ result_parts.append("# Key Definitions\n" + "\n".join(definitions[:20]))
555
+
505
556
  # Add some code blocks if space allows
506
557
  if preserve_code and code_blocks:
507
558
  result_parts.append("# Code Samples")
508
559
  for i, block in enumerate(code_blocks[:3]): # Limit to first 3 blocks
509
- if len('\n'.join(result_parts)) + len(block) < max_chars * 0.8:
560
+ if len("\n".join(result_parts)) + len(block) < max_chars * 0.8:
510
561
  result_parts.append(block)
511
-
512
- result = '\n\n'.join(result_parts)
513
-
562
+
563
+ result = "\n\n".join(result_parts)
564
+
514
565
  # If still too long, truncate
515
566
  if len(result) > max_chars:
516
567
  result = self._truncate_at_sentence(result, max_chars)
517
-
568
+
518
569
  return result
519
-
520
- def _process_chunks(self, text: str, mode: str, max_chars_per_chunk: int, preserve_code: bool) -> str:
570
+
571
+ def _process_chunks(
572
+ self, text: str, mode: str, max_chars_per_chunk: int, preserve_code: bool
573
+ ) -> str:
521
574
  """
522
575
  Process large documents in chunks.
523
-
576
+
524
577
  WHY: Very large documents need to be processed in chunks to
525
578
  avoid memory issues and maintain performance.
526
579
  """
527
580
  chunks = []
528
581
  chunk_size = self.CHUNK_SIZE
529
-
582
+
530
583
  for i in range(0, len(text), chunk_size):
531
- chunk = text[i:i + chunk_size]
532
-
584
+ chunk = text[i : i + chunk_size]
585
+
533
586
  # Summarize chunk based on mode
534
587
  if mode == "brief":
535
588
  summarized = self._summarize_brief(chunk, max_chars_per_chunk)
@@ -538,26 +591,28 @@ class DocumentSummarizerTool(BaseToolAdapter):
538
591
  elif mode == "key_points":
539
592
  summarized = self._summarize_key_points(chunk, max_chars_per_chunk)
540
593
  elif mode == "technical":
541
- summarized = self._summarize_technical(chunk, max_chars_per_chunk, preserve_code)
594
+ summarized = self._summarize_technical(
595
+ chunk, max_chars_per_chunk, preserve_code
596
+ )
542
597
  else:
543
598
  summarized = self._summarize_brief(chunk, max_chars_per_chunk)
544
-
599
+
545
600
  chunks.append(summarized)
546
-
547
- return '\n\n[--- Next Section ---]\n\n'.join(chunks)
548
-
601
+
602
+ return "\n\n[--- Next Section ---]\n\n".join(chunks)
603
+
549
604
  async def invoke(self, invocation: MCPToolInvocation) -> MCPToolResult:
550
605
  """
551
606
  Invoke the document summarizer tool.
552
-
607
+
553
608
  Args:
554
609
  invocation: Tool invocation request
555
-
610
+
556
611
  Returns:
557
612
  Tool execution result with summary
558
613
  """
559
614
  start_time = datetime.now()
560
-
615
+
561
616
  try:
562
617
  # Get parameters
563
618
  file_path = invocation.parameters["file_path"]
@@ -566,12 +621,12 @@ class DocumentSummarizerTool(BaseToolAdapter):
566
621
  max_percentage = invocation.parameters.get("max_percentage", 40)
567
622
  preserve_code = invocation.parameters.get("preserve_code", True)
568
623
  use_cache = invocation.parameters.get("use_cache", True)
569
-
624
+
570
625
  # Validate file
571
626
  is_valid, error_msg = self._validate_file(file_path)
572
627
  if not is_valid:
573
628
  raise ValueError(error_msg)
574
-
629
+
575
630
  # Check cache if enabled
576
631
  cache_hit = False
577
632
  if use_cache:
@@ -581,35 +636,41 @@ class DocumentSummarizerTool(BaseToolAdapter):
581
636
  cache_hit = True
582
637
  execution_time = (datetime.now() - start_time).total_seconds()
583
638
  self._update_metrics(True, execution_time)
584
-
639
+
585
640
  return MCPToolResult(
586
641
  success=True,
587
642
  data={
588
643
  **cached_result,
589
644
  "cache_hit": True,
590
- "cache_stats": self._cache.get_stats()
645
+ "cache_stats": self._cache.get_stats(),
591
646
  },
592
647
  execution_time=execution_time,
593
- metadata={"tool": "document_summarizer", "mode": mode, "cached": True}
648
+ metadata={
649
+ "tool": "document_summarizer",
650
+ "mode": mode,
651
+ "cached": True,
652
+ },
594
653
  )
595
-
654
+
596
655
  # Read file content
597
656
  content = self._read_file(file_path)
598
657
  original_size = len(content)
599
-
658
+
600
659
  # Calculate target size
601
660
  if max_tokens:
602
661
  max_chars = max_tokens * self.CHARS_PER_TOKEN
603
662
  else:
604
663
  max_chars = int(original_size * (max_percentage / 100))
605
-
664
+
606
665
  # Process based on file size
607
666
  chunks_processed = 1
608
667
  if original_size > self.CHUNK_SIZE:
609
668
  # Process in chunks for large files
610
669
  chunks_processed = (original_size // self.CHUNK_SIZE) + 1
611
670
  max_chars_per_chunk = max_chars // chunks_processed
612
- summary = self._process_chunks(content, mode, max_chars_per_chunk, preserve_code)
671
+ summary = self._process_chunks(
672
+ content, mode, max_chars_per_chunk, preserve_code
673
+ )
613
674
  else:
614
675
  # Process entire file
615
676
  if mode == "brief":
@@ -619,19 +680,23 @@ class DocumentSummarizerTool(BaseToolAdapter):
619
680
  elif mode == "key_points":
620
681
  summary = self._summarize_key_points(content, max_chars)
621
682
  elif mode == "technical":
622
- summary = self._summarize_technical(content, max_chars, preserve_code)
683
+ summary = self._summarize_technical(
684
+ content, max_chars, preserve_code
685
+ )
623
686
  else:
624
687
  summary = self._summarize_brief(content, max_chars)
625
-
688
+
626
689
  # Calculate metrics
627
690
  summary_size = len(summary)
628
- reduction_percentage = ((original_size - summary_size) / original_size) * 100
629
-
691
+ reduction_percentage = (
692
+ (original_size - summary_size) / original_size
693
+ ) * 100
694
+
630
695
  # Token estimates
631
696
  original_tokens = self._estimate_tokens(content)
632
697
  summary_tokens = self._estimate_tokens(summary)
633
698
  saved_tokens = original_tokens - summary_tokens
634
-
699
+
635
700
  # Prepare result
636
701
  result = {
637
702
  "summary": summary,
@@ -641,26 +706,26 @@ class DocumentSummarizerTool(BaseToolAdapter):
641
706
  "token_estimate": {
642
707
  "original": original_tokens,
643
708
  "summary": summary_tokens,
644
- "saved": saved_tokens
709
+ "saved": saved_tokens,
645
710
  },
646
711
  "chunks_processed": chunks_processed,
647
- "cache_hit": cache_hit
712
+ "cache_hit": cache_hit,
648
713
  }
649
-
714
+
650
715
  # Cache result if enabled
651
716
  if use_cache and not cache_hit:
652
717
  cache_key = f"{self._get_file_hash(file_path)}:{mode}:{max_percentage}"
653
718
  self._cache.put(cache_key, result.copy(), summary_size)
654
-
719
+
655
720
  # Calculate execution time
656
721
  execution_time = (datetime.now() - start_time).total_seconds()
657
-
722
+
658
723
  # Update metrics
659
724
  self._update_metrics(True, execution_time)
660
-
725
+
661
726
  # Add cache stats to result
662
727
  result["cache_stats"] = self._cache.get_stats()
663
-
728
+
664
729
  return MCPToolResult(
665
730
  success=True,
666
731
  data=result,
@@ -669,61 +734,64 @@ class DocumentSummarizerTool(BaseToolAdapter):
669
734
  "tool": "document_summarizer",
670
735
  "mode": mode,
671
736
  "file_path": file_path,
672
- "reduction_achieved": reduction_percentage >= 60
673
- }
737
+ "reduction_achieved": reduction_percentage >= 60,
738
+ },
674
739
  )
675
-
740
+
676
741
  except Exception as e:
677
742
  execution_time = (datetime.now() - start_time).total_seconds()
678
743
  self._update_metrics(False, execution_time)
679
744
  self._metrics["last_error"] = str(e)
680
-
745
+
681
746
  self.log_error(f"Document summarizer failed: {e}")
682
-
747
+
683
748
  return MCPToolResult(
684
749
  success=False,
685
750
  error=f"Document summarizer failed: {str(e)}",
686
751
  execution_time=execution_time,
687
- metadata={"tool": "document_summarizer", "error_type": type(e).__name__}
752
+ metadata={
753
+ "tool": "document_summarizer",
754
+ "error_type": type(e).__name__,
755
+ },
688
756
  )
689
-
757
+
690
758
  async def initialize(self) -> bool:
691
759
  """
692
760
  Initialize the document summarizer tool.
693
-
761
+
694
762
  Returns:
695
763
  True if initialization successful
696
764
  """
697
765
  try:
698
766
  self.log_info("Initializing document summarizer tool")
699
-
767
+
700
768
  # Clear cache on initialization
701
769
  self._cache = LRUCache(max_size=100, max_memory_mb=50)
702
-
770
+
703
771
  self._initialized = True
704
772
  self.log_info("Document summarizer tool initialized successfully")
705
773
  return True
706
-
774
+
707
775
  except Exception as e:
708
776
  self.log_error(f"Failed to initialize document summarizer: {e}")
709
777
  return False
710
-
778
+
711
779
  async def shutdown(self) -> None:
712
780
  """
713
781
  Shutdown the document summarizer tool and clean up resources.
714
782
  """
715
783
  try:
716
784
  self.log_info("Shutting down document summarizer tool")
717
-
785
+
718
786
  # Log final cache stats
719
787
  cache_stats = self._cache.get_stats()
720
788
  self.log_info(f"Final cache stats: {cache_stats}")
721
-
789
+
722
790
  # Clear cache
723
791
  self._cache = None
724
-
792
+
725
793
  self._initialized = False
726
794
  self.log_info("Document summarizer tool shutdown complete")
727
-
795
+
728
796
  except Exception as e:
729
- self.log_error(f"Error during document summarizer shutdown: {e}")
797
+ self.log_error(f"Error during document summarizer shutdown: {e}")