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
  """Agent Session Model for Event Aggregation.
2
4
 
3
5
  WHY: This model represents a complete agent activity session, capturing all events
@@ -11,15 +13,15 @@ chronological order for session replay and analysis.
11
13
 
12
14
  import json
13
15
  import os
16
+ from dataclasses import asdict, dataclass, field
14
17
  from datetime import datetime
15
- from dataclasses import dataclass, field, asdict
16
- from typing import List, Dict, Any, Optional, Set
17
18
  from enum import Enum
18
- from pathlib import Path
19
+ from typing import Any, Dict, List, Optional, Set
19
20
 
20
21
 
21
22
  class EventCategory(Enum):
22
23
  """Categories for different types of events in a session."""
24
+
23
25
  PROMPT = "prompt"
24
26
  DELEGATION = "delegation"
25
27
  TOOL = "tool"
@@ -34,10 +36,11 @@ class EventCategory(Enum):
34
36
  @dataclass
35
37
  class SessionEvent:
36
38
  """Individual event within a session.
37
-
39
+
38
40
  WHY: Each event needs to be self-contained with all necessary context
39
41
  for later analysis, including timing, category, and relationships.
40
42
  """
43
+
41
44
  timestamp: str
42
45
  event_type: str # Original event type from Socket.IO
43
46
  category: EventCategory
@@ -45,27 +48,28 @@ class SessionEvent:
45
48
  session_id: Optional[str] = None
46
49
  agent_context: Optional[str] = None # Which agent was active
47
50
  correlation_id: Optional[str] = None # For matching pre/post events
48
-
51
+
49
52
  def to_dict(self) -> Dict[str, Any]:
50
53
  """Convert to dictionary for JSON serialization."""
51
54
  return {
52
- 'timestamp': self.timestamp,
53
- 'event_type': self.event_type,
54
- 'category': self.category.value,
55
- 'data': self.data,
56
- 'session_id': self.session_id,
57
- 'agent_context': self.agent_context,
58
- 'correlation_id': self.correlation_id
55
+ "timestamp": self.timestamp,
56
+ "event_type": self.event_type,
57
+ "category": self.category.value,
58
+ "data": self.data,
59
+ "session_id": self.session_id,
60
+ "agent_context": self.agent_context,
61
+ "correlation_id": self.correlation_id,
59
62
  }
60
63
 
61
64
 
62
65
  @dataclass
63
66
  class ToolOperation:
64
67
  """Represents a complete tool operation with pre/post events.
65
-
68
+
66
69
  WHY: Tool operations often span multiple events (pre_tool, post_tool).
67
70
  This structure correlates them for complete analysis.
68
71
  """
72
+
69
73
  tool_name: str
70
74
  agent_type: str
71
75
  start_time: str
@@ -75,7 +79,7 @@ class ToolOperation:
75
79
  duration_ms: Optional[int] = None
76
80
  success: bool = True
77
81
  error: Optional[str] = None
78
-
82
+
79
83
  def to_dict(self) -> Dict[str, Any]:
80
84
  """Convert to dictionary for JSON serialization."""
81
85
  return asdict(self)
@@ -84,10 +88,11 @@ class ToolOperation:
84
88
  @dataclass
85
89
  class AgentDelegation:
86
90
  """Represents an agent delegation with its full lifecycle.
87
-
91
+
88
92
  WHY: Agent delegations are key session events that need special tracking
89
93
  to understand the flow of work between agents.
90
94
  """
95
+
91
96
  agent_type: str
92
97
  task_description: str
93
98
  start_time: str
@@ -101,33 +106,34 @@ class AgentDelegation:
101
106
  duration_ms: Optional[int] = None
102
107
  success: bool = True
103
108
  error: Optional[str] = None
104
-
109
+
105
110
  def to_dict(self) -> Dict[str, Any]:
106
111
  """Convert to dictionary for JSON serialization."""
107
112
  return {
108
- 'agent_type': self.agent_type,
109
- 'task_description': self.task_description,
110
- 'start_time': self.start_time,
111
- 'end_time': self.end_time,
112
- 'prompt': self.prompt,
113
- 'response': self.response,
114
- 'tool_operations': [op.to_dict() for op in self.tool_operations],
115
- 'file_changes': self.file_changes,
116
- 'todos_modified': self.todos_modified,
117
- 'memory_updates': self.memory_updates,
118
- 'duration_ms': self.duration_ms,
119
- 'success': self.success,
120
- 'error': self.error
113
+ "agent_type": self.agent_type,
114
+ "task_description": self.task_description,
115
+ "start_time": self.start_time,
116
+ "end_time": self.end_time,
117
+ "prompt": self.prompt,
118
+ "response": self.response,
119
+ "tool_operations": [op.to_dict() for op in self.tool_operations],
120
+ "file_changes": self.file_changes,
121
+ "todos_modified": self.todos_modified,
122
+ "memory_updates": self.memory_updates,
123
+ "duration_ms": self.duration_ms,
124
+ "success": self.success,
125
+ "error": self.error,
121
126
  }
122
127
 
123
128
 
124
129
  @dataclass
125
130
  class SessionMetrics:
126
131
  """Aggregated metrics for a session.
127
-
132
+
128
133
  WHY: Quick summary statistics help identify patterns and anomalies
129
134
  without processing all events.
130
135
  """
136
+
131
137
  total_events: int = 0
132
138
  event_counts: Dict[str, int] = field(default_factory=dict)
133
139
  agents_used: Set[str] = field(default_factory=set)
@@ -137,33 +143,34 @@ class SessionMetrics:
137
143
  total_tool_calls: int = 0
138
144
  total_file_operations: int = 0
139
145
  session_duration_ms: Optional[int] = None
140
-
146
+
141
147
  def to_dict(self) -> Dict[str, Any]:
142
148
  """Convert to dictionary for JSON serialization."""
143
149
  return {
144
- 'total_events': self.total_events,
145
- 'event_counts': self.event_counts,
146
- 'agents_used': list(self.agents_used),
147
- 'tools_used': list(self.tools_used),
148
- 'files_modified': list(self.files_modified),
149
- 'total_delegations': self.total_delegations,
150
- 'total_tool_calls': self.total_tool_calls,
151
- 'total_file_operations': self.total_file_operations,
152
- 'session_duration_ms': self.session_duration_ms
150
+ "total_events": self.total_events,
151
+ "event_counts": self.event_counts,
152
+ "agents_used": list(self.agents_used),
153
+ "tools_used": list(self.tools_used),
154
+ "files_modified": list(self.files_modified),
155
+ "total_delegations": self.total_delegations,
156
+ "total_tool_calls": self.total_tool_calls,
157
+ "total_file_operations": self.total_file_operations,
158
+ "session_duration_ms": self.session_duration_ms,
153
159
  }
154
160
 
155
161
 
156
162
  @dataclass
157
163
  class AgentSession:
158
164
  """Complete representation of an agent activity session.
159
-
165
+
160
166
  WHY: This is the top-level model that captures everything that happened
161
167
  during a Claude MPM session, from initial prompt to final response.
162
-
168
+
163
169
  DESIGN DECISION: We maintain both a flat chronological event list and
164
170
  structured representations (delegations, tool operations) to support
165
171
  different analysis needs.
166
172
  """
173
+
167
174
  session_id: str
168
175
  start_time: str
169
176
  end_time: Optional[str] = None
@@ -171,36 +178,38 @@ class AgentSession:
171
178
  launch_method: str = ""
172
179
  initial_prompt: Optional[str] = None
173
180
  final_response: Optional[str] = None
174
-
181
+
175
182
  # Event collections
176
183
  events: List[SessionEvent] = field(default_factory=list)
177
184
  delegations: List[AgentDelegation] = field(default_factory=list)
178
-
185
+
179
186
  # Session state
180
187
  current_agent: Optional[str] = None
181
188
  active_delegation: Optional[AgentDelegation] = None
182
189
  pending_tool_operations: Dict[str, ToolOperation] = field(default_factory=dict)
183
-
190
+
184
191
  # Metrics
185
192
  metrics: SessionMetrics = field(default_factory=SessionMetrics)
186
-
193
+
187
194
  # Metadata
188
195
  claude_pid: Optional[int] = None
189
196
  git_branch: Optional[str] = None
190
197
  project_root: Optional[str] = None
191
-
192
- def add_event(self, event_type: str, data: Dict[str, Any], timestamp: Optional[str] = None) -> SessionEvent:
198
+
199
+ def add_event(
200
+ self, event_type: str, data: Dict[str, Any], timestamp: Optional[str] = None
201
+ ) -> SessionEvent:
193
202
  """Add an event to the session.
194
-
203
+
195
204
  WHY: Centralizes event processing logic including categorization
196
205
  and metric updates.
197
206
  """
198
207
  if timestamp is None:
199
- timestamp = datetime.utcnow().isoformat() + 'Z'
200
-
208
+ timestamp = datetime.utcnow().isoformat() + "Z"
209
+
201
210
  # Categorize the event
202
211
  category = self._categorize_event(event_type, data)
203
-
212
+
204
213
  # Create the event
205
214
  event = SessionEvent(
206
215
  timestamp=timestamp,
@@ -208,304 +217,323 @@ class AgentSession:
208
217
  category=category,
209
218
  data=data,
210
219
  session_id=self.session_id,
211
- agent_context=self.current_agent
220
+ agent_context=self.current_agent,
212
221
  )
213
-
222
+
214
223
  self.events.append(event)
215
-
224
+
216
225
  # Update metrics
217
226
  self.metrics.total_events += 1
218
- self.metrics.event_counts[event_type] = self.metrics.event_counts.get(event_type, 0) + 1
219
-
227
+ self.metrics.event_counts[event_type] = (
228
+ self.metrics.event_counts.get(event_type, 0) + 1
229
+ )
230
+
220
231
  # Process specific event types
221
232
  self._process_event(event)
222
-
233
+
223
234
  return event
224
-
235
+
225
236
  def _categorize_event(self, event_type: str, data: Dict[str, Any]) -> EventCategory:
226
237
  """Categorize an event based on its type and data.
227
-
238
+
228
239
  WHY: Categories help with filtering and analysis of related events.
229
240
  """
230
241
  # Check event type patterns
231
- if 'prompt' in event_type.lower() or event_type == 'user_input':
242
+ if "prompt" in event_type.lower() or event_type == "user_input":
232
243
  return EventCategory.PROMPT
233
- elif 'delegation' in event_type.lower() or event_type == 'Task':
244
+ elif "delegation" in event_type.lower() or event_type == "Task":
234
245
  return EventCategory.DELEGATION
235
- elif 'tool' in event_type.lower() or event_type in ['PreToolUse', 'PostToolUse']:
246
+ elif "tool" in event_type.lower() or event_type in [
247
+ "PreToolUse",
248
+ "PostToolUse",
249
+ ]:
236
250
  return EventCategory.TOOL
237
- elif 'file' in event_type.lower() or 'write' in event_type.lower() or 'read' in event_type.lower():
251
+ elif (
252
+ "file" in event_type.lower()
253
+ or "write" in event_type.lower()
254
+ or "read" in event_type.lower()
255
+ ):
238
256
  return EventCategory.FILE
239
- elif 'todo' in event_type.lower():
257
+ elif "todo" in event_type.lower():
240
258
  return EventCategory.TODO
241
- elif 'response' in event_type.lower() or event_type in ['Stop', 'SubagentStop']:
259
+ elif "response" in event_type.lower() or event_type in ["Stop", "SubagentStop"]:
242
260
  return EventCategory.RESPONSE
243
- elif 'memory' in event_type.lower():
261
+ elif "memory" in event_type.lower():
244
262
  return EventCategory.MEMORY
245
- elif 'status' in event_type.lower() or 'session' in event_type.lower():
263
+ elif "status" in event_type.lower() or "session" in event_type.lower():
246
264
  return EventCategory.STATUS
247
265
  else:
248
266
  return EventCategory.SYSTEM
249
-
267
+
250
268
  def _process_event(self, event: SessionEvent):
251
269
  """Process specific event types to update session state.
252
-
270
+
253
271
  WHY: Different event types require different processing to maintain
254
272
  accurate session state and correlations.
255
273
  """
256
274
  event_type = event.event_type
257
275
  data = event.data
258
-
276
+
259
277
  # Track user prompts
260
278
  if event.category == EventCategory.PROMPT:
261
- if not self.initial_prompt and 'prompt' in data:
262
- self.initial_prompt = data['prompt']
263
-
279
+ if not self.initial_prompt and "prompt" in data:
280
+ self.initial_prompt = data["prompt"]
281
+
264
282
  # Track agent delegations
265
- elif event_type == 'Task' or 'delegation' in event_type.lower():
266
- agent_type = data.get('agent_type', 'unknown')
283
+ elif event_type == "Task" or "delegation" in event_type.lower():
284
+ agent_type = data.get("agent_type", "unknown")
267
285
  self.current_agent = agent_type
268
286
  self.metrics.agents_used.add(agent_type)
269
-
287
+
270
288
  # Create new delegation
271
289
  delegation = AgentDelegation(
272
290
  agent_type=agent_type,
273
- task_description=data.get('description', ''),
291
+ task_description=data.get("description", ""),
274
292
  start_time=event.timestamp,
275
- prompt=data.get('prompt')
293
+ prompt=data.get("prompt"),
276
294
  )
277
295
  self.delegations.append(delegation)
278
296
  self.active_delegation = delegation
279
297
  self.metrics.total_delegations += 1
280
-
298
+
281
299
  # Track tool operations
282
- elif event_type == 'PreToolUse':
283
- tool_name = data.get('tool_name', 'unknown')
300
+ elif event_type == "PreToolUse":
301
+ tool_name = data.get("tool_name", "unknown")
284
302
  self.metrics.tools_used.add(tool_name)
285
303
  self.metrics.total_tool_calls += 1
286
-
304
+
287
305
  # Create pending tool operation
288
306
  tool_op = ToolOperation(
289
307
  tool_name=tool_name,
290
- agent_type=self.current_agent or 'unknown',
308
+ agent_type=self.current_agent or "unknown",
291
309
  start_time=event.timestamp,
292
- input_data=data.get('tool_input')
310
+ input_data=data.get("tool_input"),
293
311
  )
294
-
312
+
295
313
  # Store with correlation ID if available
296
314
  correlation_id = f"{event.session_id}:{tool_name}:{event.timestamp}"
297
315
  self.pending_tool_operations[correlation_id] = tool_op
298
316
  event.correlation_id = correlation_id
299
-
317
+
300
318
  # Add to active delegation if exists
301
319
  if self.active_delegation:
302
320
  self.active_delegation.tool_operations.append(tool_op)
303
-
304
- elif event_type == 'PostToolUse':
321
+
322
+ elif event_type == "PostToolUse":
305
323
  # Match with pending tool operation
306
- tool_name = data.get('tool_name', 'unknown')
307
-
324
+ tool_name = data.get("tool_name", "unknown")
325
+
308
326
  # Find matching pending operation
309
327
  for corr_id, tool_op in list(self.pending_tool_operations.items()):
310
328
  if tool_op.tool_name == tool_name and not tool_op.end_time:
311
329
  tool_op.end_time = event.timestamp
312
- tool_op.output_data = data.get('tool_output')
313
- tool_op.success = data.get('success', True)
314
- tool_op.error = data.get('error')
315
-
330
+ tool_op.output_data = data.get("tool_output")
331
+ tool_op.success = data.get("success", True)
332
+ tool_op.error = data.get("error")
333
+
316
334
  # Calculate duration
317
335
  try:
318
- start = datetime.fromisoformat(tool_op.start_time.replace('Z', '+00:00'))
319
- end = datetime.fromisoformat(event.timestamp.replace('Z', '+00:00'))
336
+ start = datetime.fromisoformat(
337
+ tool_op.start_time.replace("Z", "+00:00")
338
+ )
339
+ end = datetime.fromisoformat(
340
+ event.timestamp.replace("Z", "+00:00")
341
+ )
320
342
  tool_op.duration_ms = int((end - start).total_seconds() * 1000)
321
343
  except:
322
344
  pass
323
-
345
+
324
346
  event.correlation_id = corr_id
325
347
  del self.pending_tool_operations[corr_id]
326
348
  break
327
-
349
+
328
350
  # Track file operations
329
351
  elif event.category == EventCategory.FILE:
330
- file_path = data.get('file_path') or data.get('path') or data.get('file')
352
+ file_path = data.get("file_path") or data.get("path") or data.get("file")
331
353
  if file_path:
332
354
  self.metrics.files_modified.add(file_path)
333
355
  self.metrics.total_file_operations += 1
334
-
356
+
335
357
  if self.active_delegation:
336
358
  self.active_delegation.file_changes.append(file_path)
337
-
359
+
338
360
  # Track responses
339
- elif event_type in ['Stop', 'SubagentStop']:
340
- response = data.get('response') or data.get('content') or data.get('message')
361
+ elif event_type in ["Stop", "SubagentStop"]:
362
+ response = (
363
+ data.get("response") or data.get("content") or data.get("message")
364
+ )
341
365
  if response:
342
- if event_type == 'SubagentStop' and self.active_delegation:
366
+ if event_type == "SubagentStop" and self.active_delegation:
343
367
  self.active_delegation.response = response
344
368
  self.active_delegation.end_time = event.timestamp
345
369
  self.active_delegation = None
346
- elif event_type == 'Stop':
370
+ elif event_type == "Stop":
347
371
  self.final_response = response
348
-
372
+
349
373
  # Track todo updates
350
374
  elif event.category == EventCategory.TODO:
351
- if self.active_delegation and 'todos' in data:
352
- self.active_delegation.todos_modified.append(data['todos'])
353
-
375
+ if self.active_delegation and "todos" in data:
376
+ self.active_delegation.todos_modified.append(data["todos"])
377
+
354
378
  # Track memory updates
355
379
  elif event.category == EventCategory.MEMORY:
356
380
  if self.active_delegation:
357
381
  self.active_delegation.memory_updates.append(data)
358
-
382
+
359
383
  def finalize(self):
360
384
  """Finalize the session by calculating final metrics.
361
-
385
+
362
386
  WHY: Some metrics can only be calculated after all events are processed.
363
387
  """
364
388
  if not self.end_time and self.events:
365
389
  self.end_time = self.events[-1].timestamp
366
-
390
+
367
391
  # Calculate session duration
368
392
  if self.start_time and self.end_time:
369
393
  try:
370
- start = datetime.fromisoformat(self.start_time.replace('Z', '+00:00'))
371
- end = datetime.fromisoformat(self.end_time.replace('Z', '+00:00'))
372
- self.metrics.session_duration_ms = int((end - start).total_seconds() * 1000)
394
+ start = datetime.fromisoformat(self.start_time.replace("Z", "+00:00"))
395
+ end = datetime.fromisoformat(self.end_time.replace("Z", "+00:00"))
396
+ self.metrics.session_duration_ms = int(
397
+ (end - start).total_seconds() * 1000
398
+ )
373
399
  except:
374
400
  pass
375
-
401
+
376
402
  # Finalize any pending delegations
377
403
  for delegation in self.delegations:
378
404
  if not delegation.end_time:
379
405
  delegation.end_time = self.end_time
380
406
  delegation.success = False
381
407
  delegation.error = "Delegation did not complete"
382
-
408
+
383
409
  def to_dict(self) -> Dict[str, Any]:
384
410
  """Convert to dictionary for JSON serialization."""
385
411
  return {
386
- 'session_id': self.session_id,
387
- 'start_time': self.start_time,
388
- 'end_time': self.end_time,
389
- 'working_directory': self.working_directory,
390
- 'launch_method': self.launch_method,
391
- 'initial_prompt': self.initial_prompt,
392
- 'final_response': self.final_response,
393
- 'events': [e.to_dict() for e in self.events],
394
- 'delegations': [d.to_dict() for d in self.delegations],
395
- 'metrics': self.metrics.to_dict(),
396
- 'metadata': {
397
- 'claude_pid': self.claude_pid,
398
- 'git_branch': self.git_branch,
399
- 'project_root': self.project_root
400
- }
412
+ "session_id": self.session_id,
413
+ "start_time": self.start_time,
414
+ "end_time": self.end_time,
415
+ "working_directory": self.working_directory,
416
+ "launch_method": self.launch_method,
417
+ "initial_prompt": self.initial_prompt,
418
+ "final_response": self.final_response,
419
+ "events": [e.to_dict() for e in self.events],
420
+ "delegations": [d.to_dict() for d in self.delegations],
421
+ "metrics": self.metrics.to_dict(),
422
+ "metadata": {
423
+ "claude_pid": self.claude_pid,
424
+ "git_branch": self.git_branch,
425
+ "project_root": self.project_root,
426
+ },
401
427
  }
402
-
428
+
403
429
  def save_to_file(self, directory: Optional[str] = None) -> str:
404
430
  """Save the session to a JSON file.
405
-
431
+
406
432
  WHY: Persistent storage allows for later analysis and debugging.
407
-
433
+
408
434
  Args:
409
435
  directory: Directory to save to (defaults to .claude-mpm/sessions/)
410
-
436
+
411
437
  Returns:
412
438
  Path to the saved file
413
439
  """
414
440
  if directory is None:
415
- directory = Path.cwd() / '.claude-mpm' / 'sessions'
441
+ directory = Path.cwd() / ".claude-mpm" / "sessions"
416
442
  else:
417
443
  directory = Path(directory)
418
-
444
+
419
445
  # Create directory if it doesn't exist
420
446
  directory.mkdir(parents=True, exist_ok=True)
421
-
447
+
422
448
  # Generate filename with timestamp
423
- timestamp = self.start_time.replace(':', '-').replace('.', '-')[:19]
449
+ timestamp = self.start_time.replace(":", "-").replace(".", "-")[:19]
424
450
  filename = f"session_{self.session_id[:8]}_{timestamp}.json"
425
451
  filepath = directory / filename
426
-
452
+
427
453
  # Save to file
428
- with open(filepath, 'w', encoding='utf-8') as f:
454
+ with open(filepath, "w", encoding="utf-8") as f:
429
455
  json.dump(self.to_dict(), f, indent=2, ensure_ascii=False)
430
-
456
+
431
457
  return str(filepath)
432
-
458
+
433
459
  @classmethod
434
- def from_dict(cls, data: Dict[str, Any]) -> 'AgentSession':
460
+ def from_dict(cls, data: Dict[str, Any]) -> "AgentSession":
435
461
  """Create an AgentSession from a dictionary.
436
-
462
+
437
463
  WHY: Allows loading saved sessions for analysis.
438
464
  """
439
465
  session = cls(
440
- session_id=data['session_id'],
441
- start_time=data['start_time'],
442
- end_time=data.get('end_time'),
443
- working_directory=data.get('working_directory', ''),
444
- launch_method=data.get('launch_method', ''),
445
- initial_prompt=data.get('initial_prompt'),
446
- final_response=data.get('final_response')
466
+ session_id=data["session_id"],
467
+ start_time=data["start_time"],
468
+ end_time=data.get("end_time"),
469
+ working_directory=data.get("working_directory", ""),
470
+ launch_method=data.get("launch_method", ""),
471
+ initial_prompt=data.get("initial_prompt"),
472
+ final_response=data.get("final_response"),
447
473
  )
448
-
474
+
449
475
  # Restore events
450
- for event_data in data.get('events', []):
476
+ for event_data in data.get("events", []):
451
477
  event = SessionEvent(
452
- timestamp=event_data['timestamp'],
453
- event_type=event_data['event_type'],
454
- category=EventCategory(event_data['category']),
455
- data=event_data['data'],
456
- session_id=event_data.get('session_id'),
457
- agent_context=event_data.get('agent_context'),
458
- correlation_id=event_data.get('correlation_id')
478
+ timestamp=event_data["timestamp"],
479
+ event_type=event_data["event_type"],
480
+ category=EventCategory(event_data["category"]),
481
+ data=event_data["data"],
482
+ session_id=event_data.get("session_id"),
483
+ agent_context=event_data.get("agent_context"),
484
+ correlation_id=event_data.get("correlation_id"),
459
485
  )
460
486
  session.events.append(event)
461
-
487
+
462
488
  # Restore delegations
463
- for del_data in data.get('delegations', []):
489
+ for del_data in data.get("delegations", []):
464
490
  delegation = AgentDelegation(
465
- agent_type=del_data['agent_type'],
466
- task_description=del_data['task_description'],
467
- start_time=del_data['start_time'],
468
- end_time=del_data.get('end_time'),
469
- prompt=del_data.get('prompt'),
470
- response=del_data.get('response'),
471
- tool_operations=[ToolOperation(**op) for op in del_data.get('tool_operations', [])],
472
- file_changes=del_data.get('file_changes', []),
473
- todos_modified=del_data.get('todos_modified', []),
474
- memory_updates=del_data.get('memory_updates', []),
475
- duration_ms=del_data.get('duration_ms'),
476
- success=del_data.get('success', True),
477
- error=del_data.get('error')
491
+ agent_type=del_data["agent_type"],
492
+ task_description=del_data["task_description"],
493
+ start_time=del_data["start_time"],
494
+ end_time=del_data.get("end_time"),
495
+ prompt=del_data.get("prompt"),
496
+ response=del_data.get("response"),
497
+ tool_operations=[
498
+ ToolOperation(**op) for op in del_data.get("tool_operations", [])
499
+ ],
500
+ file_changes=del_data.get("file_changes", []),
501
+ todos_modified=del_data.get("todos_modified", []),
502
+ memory_updates=del_data.get("memory_updates", []),
503
+ duration_ms=del_data.get("duration_ms"),
504
+ success=del_data.get("success", True),
505
+ error=del_data.get("error"),
478
506
  )
479
507
  session.delegations.append(delegation)
480
-
508
+
481
509
  # Restore metrics
482
- metrics_data = data.get('metrics', {})
510
+ metrics_data = data.get("metrics", {})
483
511
  session.metrics = SessionMetrics(
484
- total_events=metrics_data.get('total_events', 0),
485
- event_counts=metrics_data.get('event_counts', {}),
486
- agents_used=set(metrics_data.get('agents_used', [])),
487
- tools_used=set(metrics_data.get('tools_used', [])),
488
- files_modified=set(metrics_data.get('files_modified', [])),
489
- total_delegations=metrics_data.get('total_delegations', 0),
490
- total_tool_calls=metrics_data.get('total_tool_calls', 0),
491
- total_file_operations=metrics_data.get('total_file_operations', 0),
492
- session_duration_ms=metrics_data.get('session_duration_ms')
512
+ total_events=metrics_data.get("total_events", 0),
513
+ event_counts=metrics_data.get("event_counts", {}),
514
+ agents_used=set(metrics_data.get("agents_used", [])),
515
+ tools_used=set(metrics_data.get("tools_used", [])),
516
+ files_modified=set(metrics_data.get("files_modified", [])),
517
+ total_delegations=metrics_data.get("total_delegations", 0),
518
+ total_tool_calls=metrics_data.get("total_tool_calls", 0),
519
+ total_file_operations=metrics_data.get("total_file_operations", 0),
520
+ session_duration_ms=metrics_data.get("session_duration_ms"),
493
521
  )
494
-
522
+
495
523
  # Restore metadata
496
- metadata = data.get('metadata', {})
497
- session.claude_pid = metadata.get('claude_pid')
498
- session.git_branch = metadata.get('git_branch')
499
- session.project_root = metadata.get('project_root')
500
-
524
+ metadata = data.get("metadata", {})
525
+ session.claude_pid = metadata.get("claude_pid")
526
+ session.git_branch = metadata.get("git_branch")
527
+ session.project_root = metadata.get("project_root")
528
+
501
529
  return session
502
-
530
+
503
531
  @classmethod
504
- def load_from_file(cls, filepath: str) -> 'AgentSession':
532
+ def load_from_file(cls, filepath: str) -> "AgentSession":
505
533
  """Load a session from a JSON file.
506
-
534
+
507
535
  WHY: Enables analysis of historical sessions.
508
536
  """
509
- with open(filepath, 'r', encoding='utf-8') as f:
537
+ with open(filepath, "r", encoding="utf-8") as f:
510
538
  data = json.load(f)
511
- return cls.from_dict(data)
539
+ return cls.from_dict(data)