claude-mpm 3.9.9__py3-none-any.whl → 4.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (411) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +2 -2
  3. claude_mpm/__main__.py +3 -2
  4. claude_mpm/agents/__init__.py +85 -79
  5. claude_mpm/agents/agent_loader.py +464 -1003
  6. claude_mpm/agents/agent_loader_integration.py +45 -45
  7. claude_mpm/agents/agents_metadata.py +29 -30
  8. claude_mpm/agents/async_agent_loader.py +156 -138
  9. claude_mpm/agents/base_agent.json +1 -1
  10. claude_mpm/agents/base_agent_loader.py +179 -151
  11. claude_mpm/agents/frontmatter_validator.py +229 -130
  12. claude_mpm/agents/schema/agent_schema.json +1 -1
  13. claude_mpm/agents/system_agent_config.py +213 -147
  14. claude_mpm/agents/templates/__init__.py +13 -13
  15. claude_mpm/agents/templates/code_analyzer.json +2 -2
  16. claude_mpm/agents/templates/data_engineer.json +1 -1
  17. claude_mpm/agents/templates/documentation.json +23 -11
  18. claude_mpm/agents/templates/engineer.json +22 -6
  19. claude_mpm/agents/templates/memory_manager.json +155 -0
  20. claude_mpm/agents/templates/ops.json +2 -2
  21. claude_mpm/agents/templates/project_organizer.json +1 -1
  22. claude_mpm/agents/templates/qa.json +1 -1
  23. claude_mpm/agents/templates/refactoring_engineer.json +222 -0
  24. claude_mpm/agents/templates/research.json +20 -14
  25. claude_mpm/agents/templates/security.json +1 -1
  26. claude_mpm/agents/templates/ticketing.json +1 -1
  27. claude_mpm/agents/templates/version_control.json +1 -1
  28. claude_mpm/agents/templates/web_qa.json +3 -1
  29. claude_mpm/agents/templates/web_ui.json +2 -2
  30. claude_mpm/cli/__init__.py +90 -49
  31. claude_mpm/cli/__main__.py +3 -2
  32. claude_mpm/cli/commands/__init__.py +21 -18
  33. claude_mpm/cli/commands/agents.py +279 -247
  34. claude_mpm/cli/commands/aggregate.py +138 -157
  35. claude_mpm/cli/commands/cleanup.py +147 -147
  36. claude_mpm/cli/commands/config.py +93 -76
  37. claude_mpm/cli/commands/info.py +17 -16
  38. claude_mpm/cli/commands/mcp.py +143 -762
  39. claude_mpm/cli/commands/mcp_command_router.py +139 -0
  40. claude_mpm/cli/commands/mcp_config_commands.py +20 -0
  41. claude_mpm/cli/commands/mcp_install_commands.py +20 -0
  42. claude_mpm/cli/commands/mcp_server_commands.py +175 -0
  43. claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
  44. claude_mpm/cli/commands/memory.py +239 -203
  45. claude_mpm/cli/commands/monitor.py +203 -81
  46. claude_mpm/cli/commands/run.py +380 -429
  47. claude_mpm/cli/commands/run_config_checker.py +160 -0
  48. claude_mpm/cli/commands/socketio_monitor.py +235 -0
  49. claude_mpm/cli/commands/tickets.py +305 -197
  50. claude_mpm/cli/parser.py +24 -1150
  51. claude_mpm/cli/parsers/__init__.py +29 -0
  52. claude_mpm/cli/parsers/agents_parser.py +136 -0
  53. claude_mpm/cli/parsers/base_parser.py +331 -0
  54. claude_mpm/cli/parsers/config_parser.py +85 -0
  55. claude_mpm/cli/parsers/mcp_parser.py +152 -0
  56. claude_mpm/cli/parsers/memory_parser.py +138 -0
  57. claude_mpm/cli/parsers/monitor_parser.py +104 -0
  58. claude_mpm/cli/parsers/run_parser.py +147 -0
  59. claude_mpm/cli/parsers/tickets_parser.py +203 -0
  60. claude_mpm/cli/ticket_cli.py +7 -3
  61. claude_mpm/cli/utils.py +55 -37
  62. claude_mpm/cli_module/__init__.py +6 -6
  63. claude_mpm/cli_module/args.py +188 -140
  64. claude_mpm/cli_module/commands.py +79 -70
  65. claude_mpm/cli_module/migration_example.py +38 -60
  66. claude_mpm/config/__init__.py +32 -25
  67. claude_mpm/config/agent_config.py +151 -119
  68. claude_mpm/config/experimental_features.py +217 -0
  69. claude_mpm/config/paths.py +94 -208
  70. claude_mpm/config/socketio_config.py +84 -73
  71. claude_mpm/constants.py +36 -18
  72. claude_mpm/core/__init__.py +9 -6
  73. claude_mpm/core/agent_name_normalizer.py +68 -71
  74. claude_mpm/core/agent_registry.py +372 -521
  75. claude_mpm/core/agent_session_manager.py +74 -63
  76. claude_mpm/core/base_service.py +116 -87
  77. claude_mpm/core/cache.py +119 -153
  78. claude_mpm/core/claude_runner.py +425 -1120
  79. claude_mpm/core/config.py +263 -168
  80. claude_mpm/core/config_aliases.py +69 -61
  81. claude_mpm/core/config_constants.py +292 -0
  82. claude_mpm/core/constants.py +57 -99
  83. claude_mpm/core/container.py +211 -178
  84. claude_mpm/core/exceptions.py +233 -89
  85. claude_mpm/core/factories.py +92 -54
  86. claude_mpm/core/framework_loader.py +378 -220
  87. claude_mpm/core/hook_manager.py +198 -83
  88. claude_mpm/core/hook_performance_config.py +136 -0
  89. claude_mpm/core/injectable_service.py +61 -55
  90. claude_mpm/core/interactive_session.py +165 -155
  91. claude_mpm/core/interfaces.py +221 -195
  92. claude_mpm/core/lazy.py +96 -96
  93. claude_mpm/core/logger.py +133 -107
  94. claude_mpm/core/logging_config.py +185 -157
  95. claude_mpm/core/minimal_framework_loader.py +20 -15
  96. claude_mpm/core/mixins.py +30 -29
  97. claude_mpm/core/oneshot_session.py +215 -181
  98. claude_mpm/core/optimized_agent_loader.py +134 -138
  99. claude_mpm/core/optimized_startup.py +159 -157
  100. claude_mpm/core/pm_hook_interceptor.py +85 -72
  101. claude_mpm/core/service_registry.py +103 -101
  102. claude_mpm/core/session_manager.py +97 -87
  103. claude_mpm/core/socketio_pool.py +212 -158
  104. claude_mpm/core/tool_access_control.py +58 -51
  105. claude_mpm/core/types.py +46 -24
  106. claude_mpm/core/typing_utils.py +166 -82
  107. claude_mpm/core/unified_agent_registry.py +721 -0
  108. claude_mpm/core/unified_config.py +550 -0
  109. claude_mpm/core/unified_paths.py +549 -0
  110. claude_mpm/dashboard/index.html +1 -1
  111. claude_mpm/dashboard/open_dashboard.py +51 -17
  112. claude_mpm/dashboard/static/css/dashboard.css +27 -8
  113. claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
  114. claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
  115. claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
  116. claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
  117. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
  118. claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
  119. claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
  120. claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
  121. claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
  122. claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
  123. claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
  124. claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
  125. claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
  126. claude_mpm/dashboard/static/dist/dashboard.js +2 -0
  127. claude_mpm/dashboard/static/dist/socket-client.js +2 -0
  128. claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
  129. claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
  130. claude_mpm/dashboard/static/js/components/event-viewer.js +74 -70
  131. claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
  132. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +106 -92
  133. claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
  134. claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
  135. claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
  136. claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
  137. claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
  138. claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
  139. claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
  140. claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
  141. claude_mpm/dashboard/static/js/dashboard.js +178 -453
  142. claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
  143. claude_mpm/dashboard/static/js/socket-client.js +120 -54
  144. claude_mpm/dashboard/templates/index.html +40 -50
  145. claude_mpm/experimental/cli_enhancements.py +60 -58
  146. claude_mpm/generators/__init__.py +1 -1
  147. claude_mpm/generators/agent_profile_generator.py +75 -65
  148. claude_mpm/hooks/__init__.py +1 -1
  149. claude_mpm/hooks/base_hook.py +33 -28
  150. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  151. claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
  152. claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
  153. claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
  154. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
  155. claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
  156. claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
  157. claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
  158. claude_mpm/hooks/memory_integration_hook.py +140 -100
  159. claude_mpm/hooks/tool_call_interceptor.py +89 -76
  160. claude_mpm/hooks/validation_hooks.py +57 -49
  161. claude_mpm/init.py +145 -121
  162. claude_mpm/models/__init__.py +9 -9
  163. claude_mpm/models/agent_definition.py +33 -23
  164. claude_mpm/models/agent_session.py +228 -200
  165. claude_mpm/scripts/__init__.py +1 -1
  166. claude_mpm/scripts/socketio_daemon.py +192 -75
  167. claude_mpm/scripts/socketio_server_manager.py +328 -0
  168. claude_mpm/scripts/start_activity_logging.py +25 -22
  169. claude_mpm/services/__init__.py +68 -43
  170. claude_mpm/services/agent_capabilities_service.py +271 -0
  171. claude_mpm/services/agents/__init__.py +23 -32
  172. claude_mpm/services/agents/deployment/__init__.py +3 -3
  173. claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
  174. claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
  175. claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
  176. claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
  177. claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
  178. claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
  179. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
  180. claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
  181. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
  182. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
  183. claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
  184. claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
  185. claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
  186. claude_mpm/services/agents/deployment/agent_validator.py +352 -0
  187. claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
  188. claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
  189. claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
  190. claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
  191. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  192. claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
  193. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  194. claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
  195. claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
  196. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  197. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  198. claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
  199. claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
  200. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  201. claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
  202. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  203. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  204. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  205. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  206. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
  207. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  208. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  209. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
  210. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
  211. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
  212. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
  213. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
  214. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  215. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
  216. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  217. claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
  218. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
  219. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  220. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  221. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  222. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  223. claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
  224. claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
  225. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  226. claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
  227. claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
  228. claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
  229. claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
  230. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  231. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  232. claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
  233. claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
  234. claude_mpm/services/agents/loading/__init__.py +2 -2
  235. claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
  236. claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
  237. claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
  238. claude_mpm/services/agents/management/__init__.py +2 -2
  239. claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
  240. claude_mpm/services/agents/management/agent_management_service.py +209 -156
  241. claude_mpm/services/agents/memory/__init__.py +9 -6
  242. claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
  243. claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
  244. claude_mpm/services/agents/memory/analyzer.py +430 -0
  245. claude_mpm/services/agents/memory/content_manager.py +376 -0
  246. claude_mpm/services/agents/memory/template_generator.py +468 -0
  247. claude_mpm/services/agents/registry/__init__.py +7 -10
  248. claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
  249. claude_mpm/services/agents/registry/modification_tracker.py +351 -285
  250. claude_mpm/services/async_session_logger.py +187 -153
  251. claude_mpm/services/claude_session_logger.py +87 -72
  252. claude_mpm/services/command_handler_service.py +217 -0
  253. claude_mpm/services/communication/__init__.py +3 -2
  254. claude_mpm/services/core/__init__.py +50 -97
  255. claude_mpm/services/core/base.py +60 -53
  256. claude_mpm/services/core/interfaces/__init__.py +188 -0
  257. claude_mpm/services/core/interfaces/agent.py +351 -0
  258. claude_mpm/services/core/interfaces/communication.py +343 -0
  259. claude_mpm/services/core/interfaces/infrastructure.py +413 -0
  260. claude_mpm/services/core/interfaces/service.py +434 -0
  261. claude_mpm/services/core/interfaces.py +19 -944
  262. claude_mpm/services/event_aggregator.py +208 -170
  263. claude_mpm/services/exceptions.py +387 -308
  264. claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
  265. claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
  266. claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
  267. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
  268. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
  269. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
  270. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
  271. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
  272. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  273. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  274. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  275. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  276. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
  277. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  278. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  279. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
  280. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
  281. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  282. claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
  283. claude_mpm/services/hook_service.py +106 -114
  284. claude_mpm/services/infrastructure/__init__.py +7 -5
  285. claude_mpm/services/infrastructure/context_preservation.py +571 -0
  286. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  287. claude_mpm/services/infrastructure/logging.py +83 -76
  288. claude_mpm/services/infrastructure/monitoring.py +547 -404
  289. claude_mpm/services/mcp_gateway/__init__.py +40 -23
  290. claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
  291. claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
  292. claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
  293. claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
  294. claude_mpm/services/mcp_gateway/core/__init__.py +14 -21
  295. claude_mpm/services/mcp_gateway/core/base.py +80 -67
  296. claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
  297. claude_mpm/services/mcp_gateway/core/interfaces.py +97 -93
  298. claude_mpm/services/mcp_gateway/main.py +307 -127
  299. claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
  300. claude_mpm/services/mcp_gateway/registry/service_registry.py +100 -101
  301. claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
  302. claude_mpm/services/mcp_gateway/server/__init__.py +4 -4
  303. claude_mpm/services/mcp_gateway/server/{mcp_server.py → mcp_gateway.py} +149 -153
  304. claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
  305. claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
  306. claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
  307. claude_mpm/services/mcp_gateway/tools/base_adapter.py +110 -121
  308. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
  309. claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
  310. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
  311. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
  312. claude_mpm/services/memory/__init__.py +2 -2
  313. claude_mpm/services/memory/builder.py +451 -362
  314. claude_mpm/services/memory/cache/__init__.py +2 -2
  315. claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
  316. claude_mpm/services/memory/cache/simple_cache.py +107 -93
  317. claude_mpm/services/memory/indexed_memory.py +195 -193
  318. claude_mpm/services/memory/optimizer.py +267 -234
  319. claude_mpm/services/memory/router.py +571 -263
  320. claude_mpm/services/memory_hook_service.py +237 -0
  321. claude_mpm/services/port_manager.py +223 -0
  322. claude_mpm/services/project/__init__.py +3 -3
  323. claude_mpm/services/project/analyzer.py +451 -305
  324. claude_mpm/services/project/registry.py +262 -240
  325. claude_mpm/services/recovery_manager.py +287 -231
  326. claude_mpm/services/response_tracker.py +87 -67
  327. claude_mpm/services/runner_configuration_service.py +587 -0
  328. claude_mpm/services/session_management_service.py +304 -0
  329. claude_mpm/services/socketio/__init__.py +4 -4
  330. claude_mpm/services/socketio/client_proxy.py +174 -0
  331. claude_mpm/services/socketio/handlers/__init__.py +3 -3
  332. claude_mpm/services/socketio/handlers/base.py +44 -30
  333. claude_mpm/services/socketio/handlers/connection.py +145 -65
  334. claude_mpm/services/socketio/handlers/file.py +123 -108
  335. claude_mpm/services/socketio/handlers/git.py +607 -373
  336. claude_mpm/services/socketio/handlers/hook.py +170 -0
  337. claude_mpm/services/socketio/handlers/memory.py +4 -4
  338. claude_mpm/services/socketio/handlers/project.py +4 -4
  339. claude_mpm/services/socketio/handlers/registry.py +53 -38
  340. claude_mpm/services/socketio/server/__init__.py +18 -0
  341. claude_mpm/services/socketio/server/broadcaster.py +252 -0
  342. claude_mpm/services/socketio/server/core.py +399 -0
  343. claude_mpm/services/socketio/server/main.py +323 -0
  344. claude_mpm/services/socketio_client_manager.py +160 -133
  345. claude_mpm/services/socketio_server.py +36 -1885
  346. claude_mpm/services/subprocess_launcher_service.py +316 -0
  347. claude_mpm/services/system_instructions_service.py +258 -0
  348. claude_mpm/services/ticket_manager.py +20 -534
  349. claude_mpm/services/utility_service.py +285 -0
  350. claude_mpm/services/version_control/__init__.py +18 -21
  351. claude_mpm/services/version_control/branch_strategy.py +20 -10
  352. claude_mpm/services/version_control/conflict_resolution.py +37 -13
  353. claude_mpm/services/version_control/git_operations.py +52 -21
  354. claude_mpm/services/version_control/semantic_versioning.py +92 -53
  355. claude_mpm/services/version_control/version_parser.py +145 -125
  356. claude_mpm/services/version_service.py +270 -0
  357. claude_mpm/storage/__init__.py +9 -0
  358. claude_mpm/storage/state_storage.py +552 -0
  359. claude_mpm/ticket_wrapper.py +2 -2
  360. claude_mpm/utils/__init__.py +2 -2
  361. claude_mpm/utils/agent_dependency_loader.py +453 -243
  362. claude_mpm/utils/config_manager.py +157 -118
  363. claude_mpm/utils/console.py +1 -1
  364. claude_mpm/utils/dependency_cache.py +102 -107
  365. claude_mpm/utils/dependency_manager.py +52 -47
  366. claude_mpm/utils/dependency_strategies.py +131 -96
  367. claude_mpm/utils/environment_context.py +110 -102
  368. claude_mpm/utils/error_handler.py +75 -55
  369. claude_mpm/utils/file_utils.py +80 -67
  370. claude_mpm/utils/framework_detection.py +12 -11
  371. claude_mpm/utils/import_migration_example.py +12 -60
  372. claude_mpm/utils/imports.py +48 -45
  373. claude_mpm/utils/path_operations.py +100 -93
  374. claude_mpm/utils/robust_installer.py +172 -164
  375. claude_mpm/utils/session_logging.py +30 -23
  376. claude_mpm/utils/subprocess_utils.py +99 -61
  377. claude_mpm/validation/__init__.py +1 -1
  378. claude_mpm/validation/agent_validator.py +151 -111
  379. claude_mpm/validation/frontmatter_validator.py +92 -71
  380. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/METADATA +51 -2
  381. claude_mpm-4.0.3.dist-info/RECORD +402 -0
  382. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
  383. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/licenses/LICENSE +1 -1
  384. claude_mpm/config/memory_guardian_config.py +0 -325
  385. claude_mpm/core/config_paths.py +0 -150
  386. claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
  387. claude_mpm/deployment_paths.py +0 -261
  388. claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
  389. claude_mpm/models/state_models.py +0 -433
  390. claude_mpm/services/agent/__init__.py +0 -24
  391. claude_mpm/services/agent/deployment.py +0 -2548
  392. claude_mpm/services/agent/management.py +0 -598
  393. claude_mpm/services/agent/registry.py +0 -813
  394. claude_mpm/services/agents/registry/agent_registry.py +0 -813
  395. claude_mpm/services/communication/socketio.py +0 -1935
  396. claude_mpm/services/communication/websocket.py +0 -479
  397. claude_mpm/services/framework_claude_md_generator.py +0 -624
  398. claude_mpm/services/health_monitor.py +0 -893
  399. claude_mpm/services/infrastructure/memory_guardian.py +0 -770
  400. claude_mpm/services/mcp_gateway/server/mcp_server_simple.py +0 -444
  401. claude_mpm/services/optimized_hook_service.py +0 -542
  402. claude_mpm/services/project_analyzer.py +0 -864
  403. claude_mpm/services/project_registry.py +0 -608
  404. claude_mpm/services/standalone_socketio_server.py +0 -1300
  405. claude_mpm/services/ticket_manager_di.py +0 -318
  406. claude_mpm/services/ticketing_service_original.py +0 -510
  407. claude_mpm/utils/paths.py +0 -395
  408. claude_mpm/utils/platform_memory.py +0 -524
  409. claude_mpm-3.9.9.dist-info/RECORD +0 -293
  410. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/WHEEL +0 -0
  411. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,170 @@
1
+ """Hook event handlers for Socket.IO.
2
+
3
+ WHY: This module handles hook events from Claude to track session information,
4
+ agent delegations, and other hook-based activity for the system heartbeat.
5
+ """
6
+
7
+ from datetime import datetime
8
+ from typing import Any, Dict, Optional
9
+
10
+ from .base import BaseEventHandler
11
+
12
+
13
+ class HookEventHandler(BaseEventHandler):
14
+ """Handles hook events from Claude for session tracking.
15
+
16
+ WHY: Hook events provide rich information about Claude's activity including
17
+ session starts/stops, agent delegations, and tool usage. This handler
18
+ extracts session information to populate the system heartbeat data.
19
+ """
20
+
21
+ def register_events(self) -> None:
22
+ """Register hook event handlers.
23
+
24
+ NOTE: This handler no longer registers a claude_event handler directly
25
+ to avoid conflicts with ConnectionEventHandler. Instead, it processes
26
+ hook events passed from ConnectionEventHandler.
27
+ """
28
+ # No direct event registration - events are passed from ConnectionEventHandler
29
+ pass
30
+
31
+ async def process_hook_event(self, data: Dict[str, Any]) -> None:
32
+ """Process a hook event received from ConnectionEventHandler.
33
+
34
+ WHY: This method is called by ConnectionEventHandler when it receives
35
+ a claude_event with type 'hook'. This separation avoids handler conflicts.
36
+
37
+ Args:
38
+ data: The complete event data including type, event, and data fields
39
+ """
40
+ if not isinstance(data, dict):
41
+ return
42
+
43
+ # Extract hook event details
44
+ hook_event = data.get("event")
45
+ hook_data = data.get("data", {})
46
+
47
+ # Add the event to history for replay
48
+ self.add_to_history("hook", {
49
+ "event": hook_event,
50
+ "data": hook_data,
51
+ "timestamp": datetime.now().isoformat()
52
+ })
53
+
54
+ # Broadcast the event to all connected clients
55
+ await self.broadcast_event("claude_event", data)
56
+
57
+ # Track sessions based on hook events
58
+ if hook_event == "subagent_start":
59
+ await self._handle_subagent_start(hook_data)
60
+ elif hook_event == "subagent_stop":
61
+ await self._handle_subagent_stop(hook_data)
62
+ elif hook_event == "user_prompt":
63
+ await self._handle_user_prompt(hook_data)
64
+ elif hook_event == "pre_tool":
65
+ await self._handle_pre_tool(hook_data)
66
+
67
+ self.logger.debug(f"Processed hook event: {hook_event}")
68
+
69
+ async def _handle_subagent_start(self, data: Dict[str, Any]):
70
+ """Handle subagent start events.
71
+
72
+ WHY: When a subagent starts, we track it as an active session
73
+ with the agent type and start time for the heartbeat.
74
+ """
75
+ session_id = data.get("session_id")
76
+ agent_type = data.get("agent_type", "unknown")
77
+
78
+ if not session_id:
79
+ return
80
+
81
+ # Update or create session tracking
82
+ if hasattr(self.server, 'active_sessions'):
83
+ self.server.active_sessions[session_id] = {
84
+ "session_id": session_id,
85
+ "start_time": datetime.now().isoformat(),
86
+ "agent": agent_type,
87
+ "status": "active",
88
+ "prompt": data.get("prompt", "")[:100], # First 100 chars
89
+ "last_activity": datetime.now().isoformat(),
90
+ }
91
+
92
+ self.logger.debug(
93
+ f"Tracked subagent start: session={session_id[:8]}..., agent={agent_type}"
94
+ )
95
+
96
+ async def _handle_subagent_stop(self, data: Dict[str, Any]):
97
+ """Handle subagent stop events.
98
+
99
+ WHY: When a subagent stops, we update its status or remove it
100
+ from active sessions depending on the stop reason.
101
+ """
102
+ session_id = data.get("session_id")
103
+
104
+ if not session_id:
105
+ return
106
+
107
+ # Update session status
108
+ if hasattr(self.server, 'active_sessions'):
109
+ if session_id in self.server.active_sessions:
110
+ # Mark as completed rather than removing immediately
111
+ self.server.active_sessions[session_id]["status"] = "completed"
112
+ self.server.active_sessions[session_id]["last_activity"] = datetime.now().isoformat()
113
+
114
+ self.logger.debug(
115
+ f"Marked session completed: session={session_id[:8]}..."
116
+ )
117
+
118
+ async def _handle_user_prompt(self, data: Dict[str, Any]):
119
+ """Handle user prompt events.
120
+
121
+ WHY: User prompts indicate the start of a new interaction,
122
+ which we track as a PM session if no delegation occurs.
123
+ """
124
+ session_id = data.get("session_id")
125
+
126
+ if not session_id:
127
+ return
128
+
129
+ # Create or update PM session
130
+ if hasattr(self.server, 'active_sessions'):
131
+ if session_id not in self.server.active_sessions:
132
+ self.server.active_sessions[session_id] = {
133
+ "session_id": session_id,
134
+ "start_time": datetime.now().isoformat(),
135
+ "agent": "pm", # Default to PM
136
+ "status": "active",
137
+ "prompt": data.get("prompt_text", "")[:100],
138
+ "working_directory": data.get("working_directory", ""),
139
+ "last_activity": datetime.now().isoformat(),
140
+ }
141
+ else:
142
+ # Update last activity
143
+ self.server.active_sessions[session_id]["last_activity"] = datetime.now().isoformat()
144
+
145
+ async def _handle_pre_tool(self, data: Dict[str, Any]):
146
+ """Handle pre-tool events.
147
+
148
+ WHY: Pre-tool events with Task delegation indicate agent changes
149
+ that we need to track for accurate session information.
150
+ """
151
+ if data.get("tool_name") != "Task":
152
+ return
153
+
154
+ session_id = data.get("session_id")
155
+ delegation_details = data.get("delegation_details", {})
156
+ agent_type = delegation_details.get("agent_type", "unknown")
157
+
158
+ if not session_id:
159
+ return
160
+
161
+ # Update session with new agent
162
+ if hasattr(self.server, 'active_sessions'):
163
+ if session_id in self.server.active_sessions:
164
+ self.server.active_sessions[session_id]["agent"] = agent_type
165
+ self.server.active_sessions[session_id]["status"] = "delegated"
166
+ self.server.active_sessions[session_id]["last_activity"] = datetime.now().isoformat()
167
+
168
+ self.logger.debug(
169
+ f"Updated session delegation: session={session_id[:8]}..., agent={agent_type}"
170
+ )
@@ -10,18 +10,18 @@ from .base import BaseEventHandler
10
10
 
11
11
  class MemoryEventHandler(BaseEventHandler):
12
12
  """Handles memory-related Socket.IO events.
13
-
13
+
14
14
  WHY: Agent memory management events will be handled here as the system
15
15
  grows. This provides a clean separation for memory-specific functionality.
16
16
  """
17
-
17
+
18
18
  def register_events(self):
19
19
  """Register memory-related event handlers.
20
-
20
+
21
21
  Currently memory events are handled through broadcast methods
22
22
  rather than Socket.IO event handlers, but this provides a place
23
23
  for future interactive memory management features.
24
24
  """
25
25
  # Future memory management events will be registered here
26
26
  # For example: query_memory, clear_memory, export_memory, etc.
27
- pass
27
+ pass
@@ -10,16 +10,16 @@ from .base import BaseEventHandler
10
10
 
11
11
  class ProjectEventHandler(BaseEventHandler):
12
12
  """Handles project-related Socket.IO events.
13
-
13
+
14
14
  WHY: Project management events will be handled here as the system
15
15
  grows. This provides a clean separation for project-specific functionality.
16
16
  """
17
-
17
+
18
18
  def register_events(self):
19
19
  """Register project-related event handlers.
20
-
20
+
21
21
  Currently no project-specific events are defined, but this
22
22
  handler is ready for future expansion.
23
23
  """
24
24
  # Future project events will be registered here
25
- pass
25
+ pass
@@ -5,66 +5,73 @@ providing a clean interface for the SocketIOServer to register all
5
5
  events without knowing the details of each handler.
6
6
  """
7
7
 
8
- from typing import List, Type, Optional, TYPE_CHECKING
9
8
  from logging import Logger
10
- from ....core.logger import get_logger
9
+ from typing import TYPE_CHECKING, List, Optional, Type
11
10
 
11
+ from ....core.logger import get_logger
12
12
  from .base import BaseEventHandler
13
13
 
14
14
  if TYPE_CHECKING:
15
15
  from ..server import SocketIOServer
16
+
16
17
  from .connection import ConnectionEventHandler
17
- from .project import ProjectEventHandler
18
- from .memory import MemoryEventHandler
19
18
  from .file import FileEventHandler
20
19
  from .git import GitEventHandler
20
+ from .hook import HookEventHandler
21
+ from .memory import MemoryEventHandler
22
+ from .project import ProjectEventHandler
21
23
 
22
24
 
23
25
  class EventHandlerRegistry:
24
26
  """Manages registration of Socket.IO event handlers.
25
-
27
+
26
28
  WHY: The registry pattern allows us to easily add, remove, or modify
27
29
  event handlers without changing the SocketIOServer implementation.
28
30
  It provides a single point of configuration for all event handlers.
29
31
  """
30
-
32
+
31
33
  # Default handler classes in registration order
32
34
  DEFAULT_HANDLERS: List[Type[BaseEventHandler]] = [
33
35
  ConnectionEventHandler, # Connection management first
34
- GitEventHandler, # Git operations
35
- FileEventHandler, # File operations
36
- ProjectEventHandler, # Project management (future)
37
- MemoryEventHandler, # Memory management (future)
36
+ HookEventHandler, # Hook events for session tracking
37
+ GitEventHandler, # Git operations
38
+ FileEventHandler, # File operations
39
+ ProjectEventHandler, # Project management (future)
40
+ MemoryEventHandler, # Memory management (future)
38
41
  ]
39
-
40
- def __init__(self, server: 'SocketIOServer') -> None:
42
+
43
+ def __init__(self, server: "SocketIOServer") -> None:
41
44
  """Initialize the registry.
42
-
45
+
43
46
  Args:
44
47
  server: The SocketIOServer instance
45
48
  """
46
- self.server: 'SocketIOServer' = server
49
+ self.server: "SocketIOServer" = server
47
50
  self.logger: Logger = get_logger("EventHandlerRegistry")
48
51
  self.handlers: List[BaseEventHandler] = []
49
52
  self._initialized: bool = False
50
-
51
- def initialize(self, handler_classes: Optional[List[Type[BaseEventHandler]]] = None) -> None:
53
+
54
+ def initialize(
55
+ self, handler_classes: Optional[List[Type[BaseEventHandler]]] = None
56
+ ) -> None:
52
57
  """Initialize all event handlers.
53
-
58
+
54
59
  WHY: This creates instances of all handler classes and prepares
55
60
  them for event registration. Using a list of classes allows
56
61
  customization of which handlers to use.
57
-
62
+
58
63
  Args:
59
64
  handler_classes: Optional list of handler classes to use.
60
65
  Defaults to DEFAULT_HANDLERS if not provided.
61
66
  """
62
67
  if self._initialized:
63
- self.logger.warning("Registry already initialized, skipping re-initialization")
68
+ self.logger.warning(
69
+ "Registry already initialized, skipping re-initialization"
70
+ )
64
71
  return
65
-
72
+
66
73
  handler_classes = handler_classes or self.DEFAULT_HANDLERS
67
-
74
+
68
75
  for handler_class in handler_classes:
69
76
  try:
70
77
  handler = handler_class(self.server)
@@ -73,14 +80,15 @@ class EventHandlerRegistry:
73
80
  except Exception as e:
74
81
  self.logger.error(f"Failed to initialize {handler_class.__name__}: {e}")
75
82
  import traceback
83
+
76
84
  self.logger.error(f"Stack trace: {traceback.format_exc()}")
77
-
85
+
78
86
  self._initialized = True
79
87
  self.logger.info(f"Registry initialized with {len(self.handlers)} handlers")
80
-
88
+
81
89
  def register_all_events(self) -> None:
82
90
  """Register all events from all handlers.
83
-
91
+
84
92
  WHY: This is the main method called by SocketIOServer to register
85
93
  all events. It delegates to each handler's register_events method,
86
94
  keeping the server code clean and simple.
@@ -88,7 +96,7 @@ class EventHandlerRegistry:
88
96
  if not self._initialized:
89
97
  self.logger.error("Registry not initialized. Call initialize() first.")
90
98
  raise RuntimeError("EventHandlerRegistry not initialized")
91
-
99
+
92
100
  registered_count = 0
93
101
  for handler in self.handlers:
94
102
  try:
@@ -97,27 +105,34 @@ class EventHandlerRegistry:
97
105
  self.logger.info(f"Registered events for {handler.__class__.__name__}")
98
106
  except NotImplementedError:
99
107
  # Handler has no events to register (like ProjectEventHandler)
100
- self.logger.debug(f"No events to register for {handler.__class__.__name__}")
108
+ self.logger.debug(
109
+ f"No events to register for {handler.__class__.__name__}"
110
+ )
101
111
  except Exception as e:
102
- self.logger.error(f"Failed to register events for {handler.__class__.__name__}: {e}")
112
+ self.logger.error(
113
+ f"Failed to register events for {handler.__class__.__name__}: {e}"
114
+ )
103
115
  import traceback
116
+
104
117
  self.logger.error(f"Stack trace: {traceback.format_exc()}")
105
-
106
- self.logger.info(f"Successfully registered events from {registered_count} handlers")
107
-
118
+
119
+ self.logger.info(
120
+ f"Successfully registered events from {registered_count} handlers"
121
+ )
122
+
108
123
  def add_handler(self, handler_class: Type[BaseEventHandler]):
109
124
  """Add a custom handler to the registry.
110
-
125
+
111
126
  WHY: Allows dynamic addition of custom handlers for specific
112
127
  deployments or testing without modifying the default handlers.
113
-
128
+
114
129
  Args:
115
130
  handler_class: The handler class to add
116
131
  """
117
132
  if not self._initialized:
118
133
  self.logger.error("Registry not initialized. Call initialize() first.")
119
134
  raise RuntimeError("EventHandlerRegistry not initialized")
120
-
135
+
121
136
  try:
122
137
  handler = handler_class(self.server)
123
138
  self.handlers.append(handler)
@@ -126,20 +141,20 @@ class EventHandlerRegistry:
126
141
  except Exception as e:
127
142
  self.logger.error(f"Failed to add handler {handler_class.__name__}: {e}")
128
143
  raise
129
-
144
+
130
145
  def get_handler(self, handler_class: Type[BaseEventHandler]) -> BaseEventHandler:
131
146
  """Get a specific handler instance by class.
132
-
147
+
133
148
  WHY: Useful for testing or when specific handler functionality
134
149
  needs to be accessed directly.
135
-
150
+
136
151
  Args:
137
152
  handler_class: The handler class to find
138
-
153
+
139
154
  Returns:
140
155
  The handler instance or None if not found
141
156
  """
142
157
  for handler in self.handlers:
143
158
  if isinstance(handler, handler_class):
144
159
  return handler
145
- return None
160
+ return None
@@ -0,0 +1,18 @@
1
+ """
2
+ SocketIO Server package for claude-mpm.
3
+
4
+ WHY: This package contains the modular SocketIO server components that were
5
+ extracted from the monolithic socketio_server.py file.
6
+
7
+ DESIGN DECISION: Split the massive SocketIOServer class into focused modules:
8
+ - core.py: Server lifecycle and static file management
9
+ - broadcaster.py: Event broadcasting to clients
10
+ - event_registry.py: Event handler registration (if needed)
11
+
12
+ This improves maintainability, testability, and code organization.
13
+ """
14
+
15
+ from .broadcaster import SocketIOEventBroadcaster
16
+ from .core import SocketIOServerCore
17
+
18
+ __all__ = ["SocketIOServerCore", "SocketIOEventBroadcaster"]
@@ -0,0 +1,252 @@
1
+ """
2
+ SocketIO Event Broadcaster for claude-mpm.
3
+
4
+ WHY: This module contains all the broadcasting methods extracted from the
5
+ monolithic socketio_server.py file. It handles sending events to connected
6
+ clients for various Claude MPM activities.
7
+
8
+ DESIGN DECISION: Separated broadcasting logic from core server management
9
+ to create focused, testable modules with single responsibilities.
10
+ """
11
+
12
+ import asyncio
13
+ from datetime import datetime
14
+ from typing import Any, Dict, List, Optional, Set
15
+
16
+ from ....core.logging_config import get_logger
17
+
18
+
19
+ class SocketIOEventBroadcaster:
20
+ """Handles broadcasting events to connected Socket.IO clients.
21
+
22
+ WHY: This class encapsulates all the event broadcasting logic that was
23
+ scattered throughout the monolithic SocketIOServer class.
24
+ """
25
+
26
+ def __init__(
27
+ self,
28
+ sio,
29
+ connected_clients: Set[str],
30
+ event_buffer,
31
+ buffer_lock,
32
+ stats: Dict[str, Any],
33
+ logger,
34
+ server=None, # Add server reference for event history access
35
+ ):
36
+ self.sio = sio
37
+ self.connected_clients = connected_clients
38
+ self.event_buffer = event_buffer
39
+ self.buffer_lock = buffer_lock
40
+ self.stats = stats
41
+ self.logger = logger
42
+ self.loop = None # Will be set by main server
43
+ self.server = server # Reference to main server for event history
44
+
45
+ def broadcast_event(self, event_type: str, data: Dict[str, Any]):
46
+ """Broadcast an event to all connected clients."""
47
+ if not self.sio:
48
+ return
49
+
50
+ event = {
51
+ "type": event_type,
52
+ "timestamp": datetime.now().isoformat(),
53
+ "data": data,
54
+ }
55
+
56
+ # Buffer the event for reliability AND add to event history for new clients
57
+ with self.buffer_lock:
58
+ self.event_buffer.append(event)
59
+ self.stats["events_buffered"] += 1
60
+
61
+ # Also add to event history if available (for client replay)
62
+ # Access through server reference to maintain single history source
63
+ if hasattr(self, 'server') and hasattr(self.server, 'event_history'):
64
+ self.server.event_history.append(event)
65
+ self.logger.debug(f"Added {event_type} to history (total: {len(self.server.event_history)})")
66
+
67
+ # Broadcast to all connected clients
68
+ try:
69
+ # Use run_coroutine_threadsafe to safely call from any thread
70
+ if hasattr(self, "loop") and self.loop and not self.loop.is_closed():
71
+ future = asyncio.run_coroutine_threadsafe(
72
+ self.sio.emit("claude_event", event), self.loop
73
+ )
74
+ # Don't wait for the result to avoid blocking
75
+ self.stats["events_sent"] += 1
76
+ self.logger.debug(f"Broadcasted event: {event_type}")
77
+ else:
78
+ self.logger.warning(
79
+ f"Cannot broadcast {event_type}: server loop not available"
80
+ )
81
+
82
+ except Exception as e:
83
+ self.logger.error(f"Failed to broadcast event {event_type}: {e}")
84
+
85
+ def session_started(self, session_id: str, launch_method: str, working_dir: str):
86
+ """Notify that a session has started."""
87
+ self.broadcast_event(
88
+ "session_started",
89
+ {
90
+ "session_id": session_id,
91
+ "launch_method": launch_method,
92
+ "working_dir": working_dir,
93
+ "timestamp": datetime.now().isoformat(),
94
+ },
95
+ )
96
+
97
+ def session_ended(self):
98
+ """Notify that a session has ended."""
99
+ self.broadcast_event("session_ended", {"timestamp": datetime.now().isoformat()})
100
+
101
+ def claude_status_changed(
102
+ self, status: str, pid: Optional[int] = None, message: str = ""
103
+ ):
104
+ """Notify Claude status change."""
105
+ self.broadcast_event(
106
+ "claude_status", {"status": status, "pid": pid, "message": message}
107
+ )
108
+
109
+ def claude_output(self, content: str, stream: str = "stdout"):
110
+ """Broadcast Claude output."""
111
+ self.broadcast_event("claude_output", {"content": content, "stream": stream})
112
+
113
+ def agent_delegated(self, agent: str, task: str, status: str = "started"):
114
+ """Notify agent delegation."""
115
+ self.broadcast_event(
116
+ "agent_delegated", {"agent": agent, "task": task, "status": status}
117
+ )
118
+
119
+ def todo_updated(self, todos: List[Dict[str, Any]]):
120
+ """Notify todo list update."""
121
+ # Limit the size of todo data to prevent large payloads
122
+ limited_todos = todos[:50] if len(todos) > 50 else todos
123
+
124
+ self.broadcast_event(
125
+ "todo_updated",
126
+ {
127
+ "todos": limited_todos,
128
+ "total_count": len(todos),
129
+ "truncated": len(todos) > 50,
130
+ },
131
+ )
132
+
133
+ def ticket_created(self, ticket_id: str, title: str, priority: str = "medium"):
134
+ """Notify ticket creation."""
135
+ self.broadcast_event(
136
+ "ticket_created",
137
+ {"ticket_id": ticket_id, "title": title, "priority": priority},
138
+ )
139
+
140
+ def memory_loaded(self, agent_id: str, memory_size: int, sections_count: int):
141
+ """Notify when agent memory is loaded from file."""
142
+ self.broadcast_event(
143
+ "memory_loaded",
144
+ {
145
+ "agent_id": agent_id,
146
+ "memory_size": memory_size,
147
+ "sections_count": sections_count,
148
+ },
149
+ )
150
+
151
+ def memory_created(self, agent_id: str, template_type: str):
152
+ """Notify when new agent memory is created from template."""
153
+ self.broadcast_event(
154
+ "memory_created", {"agent_id": agent_id, "template_type": template_type}
155
+ )
156
+
157
+ def memory_updated(
158
+ self, agent_id: str, learning_type: str, content: str, section: str
159
+ ):
160
+ """Notify when learning is added to agent memory."""
161
+ # Truncate content if too long to prevent large payloads
162
+ truncated_content = content[:500] + "..." if len(content) > 500 else content
163
+
164
+ self.broadcast_event(
165
+ "memory_updated",
166
+ {
167
+ "agent_id": agent_id,
168
+ "learning_type": learning_type,
169
+ "content": truncated_content,
170
+ "section": section,
171
+ "content_length": len(content),
172
+ "truncated": len(content) > 500,
173
+ },
174
+ )
175
+
176
+ def memory_injected(self, agent_id: str, context_size: int):
177
+ """Notify when agent memory is injected into context."""
178
+ self.broadcast_event(
179
+ "memory_injected", {"agent_id": agent_id, "context_size": context_size}
180
+ )
181
+
182
+ def file_changed(
183
+ self, file_path: str, change_type: str, content: Optional[str] = None
184
+ ):
185
+ """Notify file system changes."""
186
+ event_data = {"file_path": file_path, "change_type": change_type}
187
+
188
+ # Include content for small files only
189
+ if content and len(content) < 1000:
190
+ event_data["content"] = content
191
+ elif content:
192
+ event_data["content_preview"] = content[:200] + "..."
193
+ event_data["content_length"] = len(content)
194
+
195
+ self.broadcast_event("file_changed", event_data)
196
+
197
+ def git_operation(self, operation: str, details: Dict[str, Any]):
198
+ """Notify Git operations."""
199
+ self.broadcast_event(
200
+ "git_operation", {"operation": operation, "details": details}
201
+ )
202
+
203
+ def error_occurred(
204
+ self, error_type: str, message: str, details: Optional[Dict[str, Any]] = None
205
+ ):
206
+ """Notify when errors occur."""
207
+ self.broadcast_event(
208
+ "error",
209
+ {"error_type": error_type, "message": message, "details": details or {}},
210
+ )
211
+
212
+ def performance_metric(self, metric_name: str, value: float, unit: str = ""):
213
+ """Broadcast performance metrics."""
214
+ self.broadcast_event(
215
+ "performance", {"metric": metric_name, "value": value, "unit": unit}
216
+ )
217
+
218
+ def system_status(self, status: Dict[str, Any]):
219
+ """Broadcast system status information."""
220
+ self.broadcast_event("system_status", status)
221
+
222
+ def broadcast_system_heartbeat(self, heartbeat_data: Dict[str, Any]):
223
+ """Broadcast system heartbeat event.
224
+
225
+ WHY: System events are separate from hook events to provide
226
+ server health monitoring independent of Claude activity.
227
+ """
228
+ if not self.sio:
229
+ return
230
+
231
+ # Create system event with consistent format
232
+ event = {
233
+ "type": "system",
234
+ "event": "heartbeat",
235
+ "timestamp": datetime.now().isoformat(),
236
+ "data": heartbeat_data,
237
+ }
238
+
239
+ # Broadcast to all connected clients
240
+ try:
241
+ if self.loop and not self.loop.is_closed():
242
+ future = asyncio.run_coroutine_threadsafe(
243
+ self.sio.emit("system_event", event), self.loop
244
+ )
245
+ self.logger.debug(
246
+ f"Broadcasted system heartbeat - clients: {len(self.connected_clients)}, "
247
+ f"uptime: {heartbeat_data.get('uptime_seconds', 0)}s"
248
+ )
249
+ else:
250
+ self.logger.warning("Cannot broadcast heartbeat: server loop not available")
251
+ except Exception as e:
252
+ self.logger.error(f"Failed to broadcast system heartbeat: {e}")