claude-mpm 3.4.10__py3-none-any.whl → 5.4.55__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 (950) hide show
  1. claude_mpm/BUILD_NUMBER +1 -0
  2. claude_mpm/VERSION +1 -0
  3. claude_mpm/__init__.py +50 -12
  4. claude_mpm/__main__.py +7 -2
  5. claude_mpm/agents/BASE_AGENT.md +164 -0
  6. claude_mpm/agents/BASE_ENGINEER.md +658 -0
  7. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +290 -0
  8. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +2002 -0
  9. claude_mpm/agents/MEMORY.md +72 -0
  10. claude_mpm/agents/PM_INSTRUCTIONS.md +1402 -0
  11. claude_mpm/agents/WORKFLOW.md +111 -0
  12. claude_mpm/agents/__init__.py +92 -80
  13. claude_mpm/agents/agent-template.yaml +83 -0
  14. claude_mpm/agents/agent_loader.py +560 -745
  15. claude_mpm/agents/agent_loader_integration.py +53 -55
  16. claude_mpm/agents/agents_metadata.py +186 -27
  17. claude_mpm/agents/async_agent_loader.py +436 -0
  18. claude_mpm/agents/base_agent.json +8 -4
  19. claude_mpm/agents/frontmatter_validator.py +754 -0
  20. claude_mpm/agents/system_agent_config.py +222 -155
  21. claude_mpm/agents/templates/README.md +465 -0
  22. claude_mpm/agents/templates/__init__.py +17 -13
  23. claude_mpm/agents/templates/circuit-breakers.md +1391 -0
  24. claude_mpm/agents/templates/context-management-examples.md +544 -0
  25. claude_mpm/agents/templates/git-file-tracking.md +584 -0
  26. claude_mpm/agents/templates/pm-examples.md +474 -0
  27. claude_mpm/agents/templates/pm-red-flags.md +310 -0
  28. claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
  29. claude_mpm/agents/templates/research-gate-examples.md +669 -0
  30. claude_mpm/agents/templates/response-format.md +583 -0
  31. claude_mpm/agents/templates/structured-questions-examples.md +615 -0
  32. claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
  33. claude_mpm/agents/templates/ticketing-examples.md +277 -0
  34. claude_mpm/agents/templates/validation-templates.md +312 -0
  35. claude_mpm/cli/__init__.py +90 -128
  36. claude_mpm/cli/__main__.py +33 -0
  37. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  38. claude_mpm/cli/commands/__init__.py +36 -12
  39. claude_mpm/cli/commands/agent_manager.py +1403 -0
  40. claude_mpm/cli/commands/agent_source.py +774 -0
  41. claude_mpm/cli/commands/agent_state_manager.py +335 -0
  42. claude_mpm/cli/commands/agents.py +2503 -168
  43. claude_mpm/cli/commands/agents_cleanup.py +210 -0
  44. claude_mpm/cli/commands/agents_discover.py +338 -0
  45. claude_mpm/cli/commands/aggregate.py +540 -0
  46. claude_mpm/cli/commands/analyze.py +553 -0
  47. claude_mpm/cli/commands/analyze_code.py +528 -0
  48. claude_mpm/cli/commands/auto_configure.py +1053 -0
  49. claude_mpm/cli/commands/cleanup.py +588 -0
  50. claude_mpm/cli/commands/cleanup_orphaned_agents.py +150 -0
  51. claude_mpm/cli/commands/config.py +586 -0
  52. claude_mpm/cli/commands/configure.py +2654 -0
  53. claude_mpm/cli/commands/configure_agent_display.py +282 -0
  54. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  55. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  56. claude_mpm/cli/commands/configure_models.py +18 -0
  57. claude_mpm/cli/commands/configure_navigation.py +184 -0
  58. claude_mpm/cli/commands/configure_paths.py +104 -0
  59. claude_mpm/cli/commands/configure_persistence.py +254 -0
  60. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  61. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  62. claude_mpm/cli/commands/configure_validators.py +73 -0
  63. claude_mpm/cli/commands/dashboard.py +286 -0
  64. claude_mpm/cli/commands/debug.py +1386 -0
  65. claude_mpm/cli/commands/doctor.py +243 -0
  66. claude_mpm/cli/commands/hook_errors.py +277 -0
  67. claude_mpm/cli/commands/info.py +195 -74
  68. claude_mpm/cli/commands/local_deploy.py +534 -0
  69. claude_mpm/cli/commands/mcp.py +205 -0
  70. claude_mpm/cli/commands/mcp_command_router.py +161 -0
  71. claude_mpm/cli/commands/mcp_config.py +154 -0
  72. claude_mpm/cli/commands/mcp_config_commands.py +20 -0
  73. claude_mpm/cli/commands/mcp_external_commands.py +249 -0
  74. claude_mpm/cli/commands/mcp_install_commands.py +346 -0
  75. claude_mpm/cli/commands/mcp_pipx_config.py +208 -0
  76. claude_mpm/cli/commands/mcp_server_commands.py +155 -0
  77. claude_mpm/cli/commands/mcp_setup_external.py +868 -0
  78. claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
  79. claude_mpm/cli/commands/memory.py +585 -846
  80. claude_mpm/cli/commands/monitor.py +228 -310
  81. claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
  82. claude_mpm/cli/commands/mpm_init/core.py +759 -0
  83. claude_mpm/cli/commands/mpm_init/display.py +341 -0
  84. claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
  85. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  86. claude_mpm/cli/commands/mpm_init/modes.py +397 -0
  87. claude_mpm/cli/commands/mpm_init/prompts.py +722 -0
  88. claude_mpm/cli/commands/mpm_init_cli.py +396 -0
  89. claude_mpm/cli/commands/mpm_init_handler.py +195 -0
  90. claude_mpm/cli/commands/postmortem.py +401 -0
  91. claude_mpm/cli/commands/profile.py +276 -0
  92. claude_mpm/cli/commands/run.py +910 -488
  93. claude_mpm/cli/commands/search.py +458 -0
  94. claude_mpm/cli/commands/skill_source.py +694 -0
  95. claude_mpm/cli/commands/skills.py +1246 -0
  96. claude_mpm/cli/commands/summarize.py +413 -0
  97. claude_mpm/cli/commands/tickets.py +536 -53
  98. claude_mpm/cli/commands/uninstall.py +176 -0
  99. claude_mpm/cli/commands/upgrade.py +152 -0
  100. claude_mpm/cli/commands/verify.py +119 -0
  101. claude_mpm/cli/executor.py +297 -0
  102. claude_mpm/cli/helpers.py +105 -0
  103. claude_mpm/cli/interactive/__init__.py +21 -0
  104. claude_mpm/cli/interactive/agent_wizard.py +1947 -0
  105. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  106. claude_mpm/cli/parser.py +87 -563
  107. claude_mpm/cli/parsers/__init__.py +35 -0
  108. claude_mpm/cli/parsers/agent_manager_parser.py +393 -0
  109. claude_mpm/cli/parsers/agent_source_parser.py +171 -0
  110. claude_mpm/cli/parsers/agents_parser.py +575 -0
  111. claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
  112. claude_mpm/cli/parsers/analyze_parser.py +135 -0
  113. claude_mpm/cli/parsers/auto_configure_parser.py +120 -0
  114. claude_mpm/cli/parsers/base_parser.py +644 -0
  115. claude_mpm/cli/parsers/config_parser.py +208 -0
  116. claude_mpm/cli/parsers/configure_parser.py +138 -0
  117. claude_mpm/cli/parsers/dashboard_parser.py +113 -0
  118. claude_mpm/cli/parsers/debug_parser.py +319 -0
  119. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  120. claude_mpm/cli/parsers/mcp_parser.py +195 -0
  121. claude_mpm/cli/parsers/memory_parser.py +138 -0
  122. claude_mpm/cli/parsers/monitor_parser.py +142 -0
  123. claude_mpm/cli/parsers/mpm_init_parser.py +311 -0
  124. claude_mpm/cli/parsers/profile_parser.py +147 -0
  125. claude_mpm/cli/parsers/run_parser.py +157 -0
  126. claude_mpm/cli/parsers/search_parser.py +245 -0
  127. claude_mpm/cli/parsers/skill_source_parser.py +169 -0
  128. claude_mpm/cli/parsers/skills_parser.py +277 -0
  129. claude_mpm/cli/parsers/source_parser.py +138 -0
  130. claude_mpm/cli/parsers/tickets_parser.py +203 -0
  131. claude_mpm/cli/shared/__init__.py +40 -0
  132. claude_mpm/cli/shared/argument_patterns.py +205 -0
  133. claude_mpm/cli/shared/base_command.py +242 -0
  134. claude_mpm/cli/shared/error_handling.py +242 -0
  135. claude_mpm/cli/shared/output_formatters.py +241 -0
  136. claude_mpm/cli/startup.py +1743 -0
  137. claude_mpm/cli/startup_display.py +480 -0
  138. claude_mpm/cli/startup_logging.py +839 -0
  139. claude_mpm/cli/utils.py +136 -47
  140. claude_mpm/cli_module/__init__.py +6 -6
  141. claude_mpm/cli_module/args.py +188 -140
  142. claude_mpm/cli_module/commands.py +79 -70
  143. claude_mpm/cli_module/migration_example.py +42 -64
  144. claude_mpm/commands/__init__.py +14 -0
  145. claude_mpm/commands/mpm-config.md +28 -0
  146. claude_mpm/commands/mpm-doctor.md +20 -0
  147. claude_mpm/commands/mpm-help.md +20 -0
  148. claude_mpm/commands/mpm-init.md +120 -0
  149. claude_mpm/commands/mpm-monitor.md +31 -0
  150. claude_mpm/commands/mpm-organize.md +120 -0
  151. claude_mpm/commands/mpm-postmortem.md +21 -0
  152. claude_mpm/commands/mpm-session-resume.md +30 -0
  153. claude_mpm/commands/mpm-status.md +20 -0
  154. claude_mpm/commands/mpm-ticket-view.md +109 -0
  155. claude_mpm/commands/mpm-version.md +20 -0
  156. claude_mpm/commands/mpm.md +31 -0
  157. claude_mpm/config/__init__.py +42 -2
  158. claude_mpm/config/agent_config.py +402 -0
  159. claude_mpm/config/agent_presets.py +488 -0
  160. claude_mpm/config/agent_sources.py +352 -0
  161. claude_mpm/config/experimental_features.py +217 -0
  162. claude_mpm/config/model_config.py +428 -0
  163. claude_mpm/config/paths.py +258 -0
  164. claude_mpm/config/skill_presets.py +392 -0
  165. claude_mpm/config/skill_sources.py +590 -0
  166. claude_mpm/config/socketio_config.py +125 -83
  167. claude_mpm/constants.py +132 -22
  168. claude_mpm/core/__init__.py +62 -36
  169. claude_mpm/core/agent_name_normalizer.py +71 -73
  170. claude_mpm/core/agent_registry.py +385 -492
  171. claude_mpm/core/agent_session_manager.py +81 -70
  172. claude_mpm/core/api_validator.py +330 -0
  173. claude_mpm/core/base_service.py +159 -122
  174. claude_mpm/core/cache.py +560 -0
  175. claude_mpm/core/claude_runner.py +696 -916
  176. claude_mpm/core/config.py +613 -122
  177. claude_mpm/core/config_aliases.py +74 -73
  178. claude_mpm/core/config_constants.py +314 -0
  179. claude_mpm/core/constants.py +361 -0
  180. claude_mpm/core/container.py +646 -104
  181. claude_mpm/core/enums.py +452 -0
  182. claude_mpm/core/error_handler.py +623 -0
  183. claude_mpm/core/exceptions.py +536 -0
  184. claude_mpm/core/factories.py +105 -109
  185. claude_mpm/core/file_utils.py +764 -0
  186. claude_mpm/core/framework/__init__.py +25 -0
  187. claude_mpm/core/framework/formatters/__init__.py +11 -0
  188. claude_mpm/core/framework/formatters/capability_generator.py +367 -0
  189. claude_mpm/core/framework/formatters/content_formatter.py +278 -0
  190. claude_mpm/core/framework/formatters/context_generator.py +185 -0
  191. claude_mpm/core/framework/loaders/__init__.py +13 -0
  192. claude_mpm/core/framework/loaders/agent_loader.py +213 -0
  193. claude_mpm/core/framework/loaders/file_loader.py +176 -0
  194. claude_mpm/core/framework/loaders/instruction_loader.py +222 -0
  195. claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
  196. claude_mpm/core/framework/processors/__init__.py +11 -0
  197. claude_mpm/core/framework/processors/memory_processor.py +230 -0
  198. claude_mpm/core/framework/processors/metadata_processor.py +146 -0
  199. claude_mpm/core/framework/processors/template_processor.py +244 -0
  200. claude_mpm/core/framework_loader.py +485 -414
  201. claude_mpm/core/hook_error_memory.py +381 -0
  202. claude_mpm/core/hook_manager.py +246 -86
  203. claude_mpm/core/hook_performance_config.py +147 -0
  204. claude_mpm/core/injectable_service.py +72 -63
  205. claude_mpm/core/instruction_reinforcement_hook.py +267 -0
  206. claude_mpm/core/interactive_session.py +670 -0
  207. claude_mpm/core/interfaces.py +570 -164
  208. claude_mpm/core/lazy.py +467 -0
  209. claude_mpm/core/log_manager.py +707 -0
  210. claude_mpm/core/logger.py +295 -134
  211. claude_mpm/core/logging_config.py +474 -0
  212. claude_mpm/core/logging_utils.py +520 -0
  213. claude_mpm/core/minimal_framework_loader.py +24 -22
  214. claude_mpm/core/mixins.py +30 -29
  215. claude_mpm/core/oneshot_session.py +594 -0
  216. claude_mpm/core/optimized_agent_loader.py +479 -0
  217. claude_mpm/core/optimized_startup.py +554 -0
  218. claude_mpm/core/output_style_manager.py +483 -0
  219. claude_mpm/core/pm_hook_interceptor.py +197 -82
  220. claude_mpm/core/protocols/__init__.py +23 -0
  221. claude_mpm/core/protocols/runner_protocol.py +103 -0
  222. claude_mpm/core/protocols/session_protocol.py +131 -0
  223. claude_mpm/core/service_registry.py +153 -116
  224. claude_mpm/core/session_manager.py +179 -64
  225. claude_mpm/core/shared/__init__.py +17 -0
  226. claude_mpm/core/shared/config_loader.py +326 -0
  227. claude_mpm/core/shared/path_resolver.py +281 -0
  228. claude_mpm/core/shared/singleton_manager.py +221 -0
  229. claude_mpm/core/socketio_pool.py +400 -137
  230. claude_mpm/core/system_context.py +38 -0
  231. claude_mpm/core/tool_access_control.py +64 -57
  232. claude_mpm/core/types.py +307 -0
  233. claude_mpm/core/typing_utils.py +553 -0
  234. claude_mpm/core/unified_agent_registry.py +969 -0
  235. claude_mpm/core/unified_config.py +570 -0
  236. claude_mpm/core/unified_paths.py +941 -0
  237. claude_mpm/dashboard/__init__.py +12 -0
  238. claude_mpm/dashboard/api/simple_directory.py +261 -0
  239. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  240. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +1 -0
  241. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +1 -0
  242. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +1 -0
  243. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +24 -0
  244. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B0uc0UOD.js +36 -0
  245. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7RN905-.js +1 -0
  246. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7xVLGWV.js +2 -0
  247. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BIF9m_hv.js +61 -0
  248. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +1 -0
  249. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BPYeabCQ.js +1 -0
  250. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  251. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
  252. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Be7GpZd6.js +7 -0
  253. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bh0LDWpI.js +145 -0
  254. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BofRWZRR.js +10 -0
  255. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BovzEFCE.js +30 -0
  256. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C30mlcqg.js +165 -0
  257. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4B-KCzX.js +1 -0
  258. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4JcI4KD.js +122 -0
  259. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CBBdVcY8.js +1 -0
  260. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CDuw-vjf.js +1 -0
  261. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C_Usid8X.js +15 -0
  262. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cfqx1Qun.js +10 -0
  263. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CiIAseT4.js +128 -0
  264. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  265. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CnA0NrzZ.js +1 -0
  266. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cs_tUR18.js +24 -0
  267. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  268. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CyWMqx4W.js +43 -0
  269. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzZX-COe.js +220 -0
  270. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzeYkLYB.js +65 -0
  271. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D3k0OPJN.js +4 -0
  272. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9lljYKQ.js +1 -0
  273. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DGkLK5U1.js +267 -0
  274. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DI7hHRFL.js +1 -0
  275. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DLVjFsZ3.js +139 -0
  276. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUrLdbGD.js +89 -0
  277. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  278. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DY1XQ8fi.js +2 -0
  279. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DZX00Y4g.js +1 -0
  280. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +1 -0
  281. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DaimHw_p.js +68 -0
  282. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +323 -0
  283. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dhb8PKl3.js +1 -0
  284. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dle-35c7.js +64 -0
  285. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DmxopI1J.js +1 -0
  286. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DwBR2MJi.js +60 -0
  287. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/GYwsonyD.js +1 -0
  288. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  289. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
  290. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/RJiighC3.js +1 -0
  291. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Vzk33B_K.js +2 -0
  292. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ZGh7QtNv.js +7 -0
  293. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bT1r9zLR.js +1 -0
  294. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bTOqqlTd.js +1 -0
  295. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/eNVUfhuA.js +1 -0
  296. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/iEWssX7S.js +162 -0
  297. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/sQeU3Y1z.js +1 -0
  298. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uuIeMWc-.js +1 -0
  299. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.D6-I5TpK.js +2 -0
  300. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +1 -0
  301. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.m1gL8KXf.js +1 -0
  302. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.CgNOuw-d.js +1 -0
  303. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +1 -0
  304. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  305. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  306. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  307. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  308. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  309. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  310. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  311. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  312. claude_mpm/experimental/__init__.py +10 -0
  313. claude_mpm/experimental/cli_enhancements.py +104 -89
  314. claude_mpm/generators/__init__.py +1 -1
  315. claude_mpm/generators/agent_profile_generator.py +76 -66
  316. claude_mpm/hooks/__init__.py +37 -1
  317. claude_mpm/hooks/base_hook.py +37 -32
  318. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  319. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  320. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  321. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  322. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  323. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  324. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  325. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  326. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  327. claude_mpm/hooks/claude_hooks/connection_pool.py +250 -0
  328. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  329. claude_mpm/hooks/claude_hooks/event_handlers.py +888 -0
  330. claude_mpm/hooks/claude_hooks/hook_handler.py +652 -875
  331. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +10 -7
  332. claude_mpm/hooks/claude_hooks/installer.py +806 -0
  333. claude_mpm/hooks/claude_hooks/memory_integration.py +249 -0
  334. claude_mpm/hooks/claude_hooks/response_tracking.py +412 -0
  335. claude_mpm/hooks/claude_hooks/services/__init__.py +15 -0
  336. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  337. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  338. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  339. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  340. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  341. claude_mpm/hooks/claude_hooks/services/connection_manager.py +229 -0
  342. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +254 -0
  343. claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
  344. claude_mpm/hooks/claude_hooks/services/state_manager.py +284 -0
  345. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
  346. claude_mpm/hooks/claude_hooks/tool_analysis.py +224 -0
  347. claude_mpm/hooks/failure_learning/__init__.py +54 -0
  348. claude_mpm/hooks/failure_learning/failure_detection_hook.py +230 -0
  349. claude_mpm/hooks/failure_learning/fix_detection_hook.py +212 -0
  350. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +281 -0
  351. claude_mpm/hooks/instruction_reinforcement.py +301 -0
  352. claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
  353. claude_mpm/hooks/kuzu_memory_hook.py +386 -0
  354. claude_mpm/hooks/kuzu_response_hook.py +179 -0
  355. claude_mpm/hooks/memory_integration_hook.py +201 -107
  356. claude_mpm/hooks/session_resume_hook.py +121 -0
  357. claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
  358. claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
  359. claude_mpm/hooks/tool_call_interceptor.py +92 -76
  360. claude_mpm/hooks/validation_hooks.py +62 -54
  361. claude_mpm/init.py +518 -83
  362. claude_mpm/models/__init__.py +9 -9
  363. claude_mpm/models/agent_definition.py +40 -23
  364. claude_mpm/models/agent_session.py +538 -0
  365. claude_mpm/models/git_repository.py +198 -0
  366. claude_mpm/models/resume_log.py +340 -0
  367. claude_mpm/schemas/__init__.py +12 -0
  368. claude_mpm/scripts/__init__.py +15 -0
  369. claude_mpm/scripts/claude-hook-handler.sh +227 -0
  370. claude_mpm/scripts/launch_monitor.py +165 -0
  371. claude_mpm/scripts/mpm_doctor.py +322 -0
  372. claude_mpm/scripts/socketio_daemon.py +189 -200
  373. claude_mpm/scripts/start_activity_logging.py +91 -0
  374. claude_mpm/services/__init__.py +208 -39
  375. claude_mpm/services/agent_capabilities_service.py +266 -0
  376. claude_mpm/services/agents/__init__.py +89 -0
  377. claude_mpm/services/agents/agent_builder.py +514 -0
  378. claude_mpm/services/agents/agent_preset_service.py +238 -0
  379. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  380. claude_mpm/services/agents/agent_review_service.py +280 -0
  381. claude_mpm/services/agents/agent_selection_service.py +484 -0
  382. claude_mpm/services/agents/auto_config_manager.py +796 -0
  383. claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
  384. claude_mpm/services/agents/cache_git_manager.py +621 -0
  385. claude_mpm/services/agents/deployment/__init__.py +21 -0
  386. claude_mpm/services/agents/deployment/agent_config_provider.py +410 -0
  387. claude_mpm/services/agents/deployment/agent_configuration_manager.py +358 -0
  388. claude_mpm/services/agents/deployment/agent_definition_factory.py +80 -0
  389. claude_mpm/services/agents/deployment/agent_deployment.py +1037 -0
  390. claude_mpm/services/agents/deployment/agent_discovery_service.py +546 -0
  391. claude_mpm/services/agents/deployment/agent_environment_manager.py +288 -0
  392. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +383 -0
  393. claude_mpm/services/agents/deployment/agent_format_converter.py +505 -0
  394. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +160 -0
  395. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +957 -0
  396. claude_mpm/services/agents/deployment/agent_metrics_collector.py +273 -0
  397. claude_mpm/services/agents/deployment/agent_operation_service.py +573 -0
  398. claude_mpm/services/agents/deployment/agent_record_service.py +418 -0
  399. claude_mpm/services/agents/deployment/agent_restore_handler.py +84 -0
  400. claude_mpm/services/agents/deployment/agent_state_service.py +381 -0
  401. claude_mpm/services/agents/deployment/agent_template_builder.py +1369 -0
  402. claude_mpm/services/agents/deployment/agent_validator.py +376 -0
  403. claude_mpm/services/agents/deployment/agent_version_manager.py +322 -0
  404. claude_mpm/services/{agent_versioning.py → agents/deployment/agent_versioning.py} +10 -13
  405. claude_mpm/services/agents/deployment/agents_directory_resolver.py +149 -0
  406. claude_mpm/services/agents/deployment/async_agent_deployment.py +768 -0
  407. claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
  408. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  409. claude_mpm/services/agents/deployment/config/deployment_config.py +181 -0
  410. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  411. claude_mpm/services/agents/deployment/deployment_config_loader.py +178 -0
  412. claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
  413. claude_mpm/services/agents/deployment/deployment_type_detector.py +120 -0
  414. claude_mpm/services/agents/deployment/deployment_wrapper.py +129 -0
  415. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  416. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  417. claude_mpm/services/agents/deployment/facade/deployment_executor.py +70 -0
  418. claude_mpm/services/agents/deployment/facade/deployment_facade.py +269 -0
  419. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  420. claude_mpm/services/agents/deployment/interface_adapter.py +226 -0
  421. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  422. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  423. claude_mpm/services/agents/deployment/local_template_deployment.py +362 -0
  424. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +1478 -0
  425. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  426. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  427. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +162 -0
  428. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  429. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  430. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +240 -0
  431. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +110 -0
  432. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +80 -0
  433. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +92 -0
  434. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +101 -0
  435. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  436. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +102 -0
  437. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  438. claude_mpm/services/agents/deployment/processors/agent_processor.py +269 -0
  439. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +311 -0
  440. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +862 -0
  441. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  442. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  443. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  444. claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
  445. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  446. claude_mpm/services/agents/deployment/strategies/base_strategy.py +113 -0
  447. claude_mpm/services/agents/deployment/strategies/project_strategy.py +148 -0
  448. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  449. claude_mpm/services/agents/deployment/strategies/system_strategy.py +131 -0
  450. claude_mpm/services/agents/deployment/strategies/user_strategy.py +130 -0
  451. claude_mpm/services/agents/deployment/system_instructions_deployer.py +228 -0
  452. claude_mpm/services/agents/deployment/validation/__init__.py +21 -0
  453. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  454. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  455. claude_mpm/services/agents/deployment/validation/template_validator.py +319 -0
  456. claude_mpm/services/agents/deployment/validation/validation_result.py +214 -0
  457. claude_mpm/services/agents/git_source_manager.py +682 -0
  458. claude_mpm/services/agents/loading/__init__.py +11 -0
  459. claude_mpm/services/{agent_profile_loader.py → agents/loading/agent_profile_loader.py} +306 -228
  460. claude_mpm/services/{base_agent_manager.py → agents/loading/base_agent_manager.py} +106 -91
  461. claude_mpm/services/agents/loading/framework_agent_loader.py +433 -0
  462. claude_mpm/services/agents/local_template_manager.py +784 -0
  463. claude_mpm/services/agents/management/__init__.py +9 -0
  464. claude_mpm/services/{agent_capabilities_generator.py → agents/management/agent_capabilities_generator.py} +92 -69
  465. claude_mpm/services/{agent_management_service.py → agents/management/agent_management_service.py} +219 -168
  466. claude_mpm/services/agents/memory/__init__.py +22 -0
  467. claude_mpm/services/agents/memory/agent_memory_manager.py +784 -0
  468. claude_mpm/services/{agent_persistence_service.py → agents/memory/agent_persistence_service.py} +20 -18
  469. claude_mpm/services/agents/memory/content_manager.py +470 -0
  470. claude_mpm/services/agents/memory/memory_categorization_service.py +167 -0
  471. claude_mpm/services/agents/memory/memory_file_service.py +129 -0
  472. claude_mpm/services/agents/memory/memory_format_service.py +201 -0
  473. claude_mpm/services/agents/memory/memory_limits_service.py +101 -0
  474. claude_mpm/services/agents/memory/template_generator.py +83 -0
  475. claude_mpm/services/agents/observers.py +547 -0
  476. claude_mpm/services/agents/recommender.py +617 -0
  477. claude_mpm/services/agents/registry/__init__.py +30 -0
  478. claude_mpm/services/agents/registry/deployed_agent_discovery.py +273 -0
  479. claude_mpm/services/{agent_modification_tracker.py → agents/registry/modification_tracker.py} +370 -295
  480. claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
  481. claude_mpm/services/agents/sources/__init__.py +13 -0
  482. claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
  483. claude_mpm/services/agents/sources/git_source_sync_service.py +1202 -0
  484. claude_mpm/services/agents/startup_sync.py +259 -0
  485. claude_mpm/services/agents/toolchain_detector.py +478 -0
  486. claude_mpm/services/analysis/__init__.py +35 -0
  487. claude_mpm/services/analysis/clone_detector.py +1030 -0
  488. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  489. claude_mpm/services/analysis/postmortem_service.py +765 -0
  490. claude_mpm/services/async_session_logger.py +665 -0
  491. claude_mpm/services/claude_session_logger.py +321 -0
  492. claude_mpm/services/cli/__init__.py +18 -0
  493. claude_mpm/services/cli/agent_cleanup_service.py +408 -0
  494. claude_mpm/services/cli/agent_dependency_service.py +395 -0
  495. claude_mpm/services/cli/agent_listing_service.py +463 -0
  496. claude_mpm/services/cli/agent_output_formatter.py +605 -0
  497. claude_mpm/services/cli/agent_validation_service.py +590 -0
  498. claude_mpm/services/cli/memory_crud_service.py +622 -0
  499. claude_mpm/services/cli/memory_output_formatter.py +604 -0
  500. claude_mpm/services/cli/resume_service.py +617 -0
  501. claude_mpm/services/cli/session_manager.py +604 -0
  502. claude_mpm/services/cli/session_pause_manager.py +504 -0
  503. claude_mpm/services/cli/session_resume_helper.py +372 -0
  504. claude_mpm/services/cli/startup_checker.py +362 -0
  505. claude_mpm/services/cli/unified_dashboard_manager.py +439 -0
  506. claude_mpm/services/command_deployment_service.py +446 -0
  507. claude_mpm/services/command_handler_service.py +221 -0
  508. claude_mpm/services/communication/__init__.py +22 -0
  509. claude_mpm/services/core/__init__.py +108 -0
  510. claude_mpm/services/core/base.py +269 -0
  511. claude_mpm/services/core/cache_manager.py +309 -0
  512. claude_mpm/services/core/interfaces/__init__.py +273 -0
  513. claude_mpm/services/core/interfaces/agent.py +514 -0
  514. claude_mpm/services/core/interfaces/communication.py +316 -0
  515. claude_mpm/services/core/interfaces/health.py +169 -0
  516. claude_mpm/services/core/interfaces/infrastructure.py +357 -0
  517. claude_mpm/services/core/interfaces/model.py +281 -0
  518. claude_mpm/services/core/interfaces/process.py +372 -0
  519. claude_mpm/services/core/interfaces/project.py +121 -0
  520. claude_mpm/services/core/interfaces/restart.py +307 -0
  521. claude_mpm/services/core/interfaces/service.py +405 -0
  522. claude_mpm/services/core/interfaces/stability.py +260 -0
  523. claude_mpm/services/core/interfaces.py +81 -0
  524. claude_mpm/services/core/memory_manager.py +682 -0
  525. claude_mpm/services/core/models/__init__.py +70 -0
  526. claude_mpm/services/core/models/agent_config.py +384 -0
  527. claude_mpm/services/core/models/health.py +162 -0
  528. claude_mpm/services/core/models/process.py +239 -0
  529. claude_mpm/services/core/models/restart.py +302 -0
  530. claude_mpm/services/core/models/stability.py +264 -0
  531. claude_mpm/services/core/models/toolchain.py +306 -0
  532. claude_mpm/services/core/path_resolver.py +517 -0
  533. claude_mpm/services/core/service_container.py +520 -0
  534. claude_mpm/services/core/service_interfaces.py +436 -0
  535. claude_mpm/services/diagnostics/__init__.py +18 -0
  536. claude_mpm/services/diagnostics/checks/__init__.py +38 -0
  537. claude_mpm/services/diagnostics/checks/agent_check.py +370 -0
  538. claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
  539. claude_mpm/services/diagnostics/checks/base_check.py +60 -0
  540. claude_mpm/services/diagnostics/checks/claude_code_check.py +270 -0
  541. claude_mpm/services/diagnostics/checks/common_issues_check.py +363 -0
  542. claude_mpm/services/diagnostics/checks/configuration_check.py +306 -0
  543. claude_mpm/services/diagnostics/checks/filesystem_check.py +233 -0
  544. claude_mpm/services/diagnostics/checks/installation_check.py +520 -0
  545. claude_mpm/services/diagnostics/checks/instructions_check.py +415 -0
  546. claude_mpm/services/diagnostics/checks/mcp_check.py +330 -0
  547. claude_mpm/services/diagnostics/checks/mcp_services_check.py +1058 -0
  548. claude_mpm/services/diagnostics/checks/monitor_check.py +281 -0
  549. claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
  550. claude_mpm/services/diagnostics/checks/startup_log_check.py +319 -0
  551. claude_mpm/services/diagnostics/diagnostic_runner.py +286 -0
  552. claude_mpm/services/diagnostics/doctor_reporter.py +578 -0
  553. claude_mpm/services/diagnostics/models.py +138 -0
  554. claude_mpm/services/event_aggregator.py +582 -0
  555. claude_mpm/services/event_bus/__init__.py +18 -0
  556. claude_mpm/services/event_bus/config.py +186 -0
  557. claude_mpm/services/event_bus/direct_relay.py +312 -0
  558. claude_mpm/services/event_bus/event_bus.py +396 -0
  559. claude_mpm/services/event_bus/relay.py +326 -0
  560. claude_mpm/services/events/__init__.py +44 -0
  561. claude_mpm/services/events/consumers/__init__.py +18 -0
  562. claude_mpm/services/events/consumers/dead_letter.py +306 -0
  563. claude_mpm/services/events/consumers/logging.py +184 -0
  564. claude_mpm/services/events/consumers/metrics.py +241 -0
  565. claude_mpm/services/events/consumers/socketio.py +377 -0
  566. claude_mpm/services/events/core.py +480 -0
  567. claude_mpm/services/events/interfaces.py +214 -0
  568. claude_mpm/services/events/producers/__init__.py +14 -0
  569. claude_mpm/services/events/producers/hook.py +269 -0
  570. claude_mpm/services/events/producers/system.py +329 -0
  571. claude_mpm/services/exceptions.py +433 -353
  572. claude_mpm/services/framework_claude_md_generator/__init__.py +81 -80
  573. claude_mpm/services/framework_claude_md_generator/content_assembler.py +74 -67
  574. claude_mpm/services/framework_claude_md_generator/content_validator.py +66 -62
  575. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +82 -60
  576. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +36 -37
  577. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +41 -40
  578. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +15 -15
  579. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +5 -4
  580. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  581. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  582. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  583. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  584. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +5 -4
  585. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  586. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  587. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +26 -30
  588. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +6 -5
  589. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  590. claude_mpm/services/framework_claude_md_generator/version_manager.py +31 -30
  591. claude_mpm/services/git/__init__.py +21 -0
  592. claude_mpm/services/git/git_operations_service.py +579 -0
  593. claude_mpm/services/github/__init__.py +21 -0
  594. claude_mpm/services/github/github_cli_service.py +397 -0
  595. claude_mpm/services/hook_installer_service.py +506 -0
  596. claude_mpm/services/hook_service.py +159 -111
  597. claude_mpm/services/infrastructure/__init__.py +52 -0
  598. claude_mpm/services/infrastructure/context_preservation.py +569 -0
  599. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  600. claude_mpm/services/infrastructure/logging.py +209 -0
  601. claude_mpm/services/infrastructure/monitoring/__init__.py +39 -0
  602. claude_mpm/services/infrastructure/monitoring/aggregator.py +432 -0
  603. claude_mpm/services/infrastructure/monitoring/base.py +122 -0
  604. claude_mpm/services/infrastructure/monitoring/legacy.py +203 -0
  605. claude_mpm/services/infrastructure/monitoring/network.py +219 -0
  606. claude_mpm/services/infrastructure/monitoring/process.py +343 -0
  607. claude_mpm/services/infrastructure/monitoring/resources.py +244 -0
  608. claude_mpm/services/infrastructure/monitoring/service.py +368 -0
  609. claude_mpm/services/infrastructure/monitoring.py +71 -0
  610. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  611. claude_mpm/services/instructions/__init__.py +9 -0
  612. claude_mpm/services/instructions/instruction_cache_service.py +374 -0
  613. claude_mpm/services/local_ops/__init__.py +155 -0
  614. claude_mpm/services/local_ops/crash_detector.py +257 -0
  615. claude_mpm/services/local_ops/health_checks/__init__.py +26 -0
  616. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  617. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  618. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  619. claude_mpm/services/local_ops/health_manager.py +427 -0
  620. claude_mpm/services/local_ops/log_monitor.py +396 -0
  621. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  622. claude_mpm/services/local_ops/process_manager.py +595 -0
  623. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  624. claude_mpm/services/local_ops/restart_manager.py +401 -0
  625. claude_mpm/services/local_ops/restart_policy.py +387 -0
  626. claude_mpm/services/local_ops/state_manager.py +372 -0
  627. claude_mpm/services/local_ops/unified_manager.py +600 -0
  628. claude_mpm/services/mcp_config_manager.py +1542 -0
  629. claude_mpm/services/mcp_service_verifier.py +732 -0
  630. claude_mpm/services/memory/__init__.py +19 -0
  631. claude_mpm/services/{memory_builder.py → memory/builder.py} +465 -373
  632. claude_mpm/services/memory/cache/__init__.py +14 -0
  633. claude_mpm/services/{shared_prompt_cache.py → memory/cache/shared_prompt_cache.py} +237 -200
  634. claude_mpm/services/memory/cache/simple_cache.py +331 -0
  635. claude_mpm/services/memory/failure_tracker.py +578 -0
  636. claude_mpm/services/memory/indexed_memory.py +648 -0
  637. claude_mpm/services/{memory_optimizer.py → memory/optimizer.py} +272 -243
  638. claude_mpm/services/memory/router.py +951 -0
  639. claude_mpm/services/memory_hook_service.py +470 -0
  640. claude_mpm/services/model/__init__.py +147 -0
  641. claude_mpm/services/model/base_provider.py +365 -0
  642. claude_mpm/services/model/claude_provider.py +412 -0
  643. claude_mpm/services/model/model_router.py +452 -0
  644. claude_mpm/services/model/ollama_provider.py +415 -0
  645. claude_mpm/services/monitor/__init__.py +20 -0
  646. claude_mpm/services/monitor/daemon.py +698 -0
  647. claude_mpm/services/monitor/daemon_manager.py +1076 -0
  648. claude_mpm/services/monitor/event_emitter.py +350 -0
  649. claude_mpm/services/monitor/handlers/__init__.py +21 -0
  650. claude_mpm/services/monitor/handlers/code_analysis.py +332 -0
  651. claude_mpm/services/monitor/handlers/dashboard.py +299 -0
  652. claude_mpm/services/monitor/handlers/file.py +264 -0
  653. claude_mpm/services/monitor/handlers/hooks.py +512 -0
  654. claude_mpm/services/monitor/management/__init__.py +18 -0
  655. claude_mpm/services/monitor/management/health.py +124 -0
  656. claude_mpm/services/monitor/management/lifecycle.py +730 -0
  657. claude_mpm/services/monitor/server.py +1493 -0
  658. claude_mpm/services/monitor_build_service.py +349 -0
  659. claude_mpm/services/native_agent_converter.py +356 -0
  660. claude_mpm/services/orphan_detection.py +786 -0
  661. claude_mpm/services/pm_skills_deployer.py +707 -0
  662. claude_mpm/services/port_manager.py +597 -0
  663. claude_mpm/services/pr/__init__.py +14 -0
  664. claude_mpm/services/pr/pr_template_service.py +329 -0
  665. claude_mpm/services/profile_manager.py +337 -0
  666. claude_mpm/services/project/__init__.py +44 -0
  667. claude_mpm/services/{project_analyzer.py → project/analyzer.py} +541 -291
  668. claude_mpm/services/project/analyzer_v2.py +566 -0
  669. claude_mpm/services/project/architecture_analyzer.py +461 -0
  670. claude_mpm/services/project/archive_manager.py +1045 -0
  671. claude_mpm/services/project/dependency_analyzer.py +462 -0
  672. claude_mpm/services/project/detection_strategies.py +719 -0
  673. claude_mpm/services/project/documentation_manager.py +554 -0
  674. claude_mpm/services/project/enhanced_analyzer.py +572 -0
  675. claude_mpm/services/project/language_analyzer.py +265 -0
  676. claude_mpm/services/project/metrics_collector.py +407 -0
  677. claude_mpm/services/project/project_organizer.py +1009 -0
  678. claude_mpm/services/project/registry.py +636 -0
  679. claude_mpm/services/project/toolchain_analyzer.py +583 -0
  680. claude_mpm/services/project_port_allocator.py +596 -0
  681. claude_mpm/services/recovery_manager.py +293 -240
  682. claude_mpm/services/response_tracker.py +267 -0
  683. claude_mpm/services/runner_configuration_service.py +605 -0
  684. claude_mpm/services/self_upgrade_service.py +608 -0
  685. claude_mpm/services/session_management_service.py +314 -0
  686. claude_mpm/services/session_manager.py +380 -0
  687. claude_mpm/services/shared/__init__.py +21 -0
  688. claude_mpm/services/shared/async_service_base.py +216 -0
  689. claude_mpm/services/shared/config_service_base.py +301 -0
  690. claude_mpm/services/shared/lifecycle_service_base.py +308 -0
  691. claude_mpm/services/shared/manager_base.py +315 -0
  692. claude_mpm/services/shared/service_factory.py +309 -0
  693. claude_mpm/services/skills/__init__.py +21 -0
  694. claude_mpm/services/skills/git_skill_source_manager.py +1324 -0
  695. claude_mpm/services/skills/selective_skill_deployer.py +744 -0
  696. claude_mpm/services/skills/skill_discovery_service.py +568 -0
  697. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  698. claude_mpm/services/skills_config.py +547 -0
  699. claude_mpm/services/skills_deployer.py +1168 -0
  700. claude_mpm/services/socketio/__init__.py +25 -0
  701. claude_mpm/services/socketio/client_proxy.py +229 -0
  702. claude_mpm/services/socketio/dashboard_server.py +362 -0
  703. claude_mpm/services/socketio/event_normalizer.py +798 -0
  704. claude_mpm/services/socketio/handlers/__init__.py +30 -0
  705. claude_mpm/services/socketio/handlers/base.py +136 -0
  706. claude_mpm/services/socketio/handlers/code_analysis.py +682 -0
  707. claude_mpm/services/socketio/handlers/connection.py +643 -0
  708. claude_mpm/services/socketio/handlers/connection_handler.py +333 -0
  709. claude_mpm/services/socketio/handlers/file.py +263 -0
  710. claude_mpm/services/socketio/handlers/git.py +962 -0
  711. claude_mpm/services/socketio/handlers/hook.py +211 -0
  712. claude_mpm/services/socketio/handlers/memory.py +26 -0
  713. claude_mpm/services/socketio/handlers/project.py +24 -0
  714. claude_mpm/services/socketio/handlers/registry.py +214 -0
  715. claude_mpm/services/socketio/migration_utils.py +343 -0
  716. claude_mpm/services/socketio/monitor_client.py +364 -0
  717. claude_mpm/services/socketio/server/__init__.py +18 -0
  718. claude_mpm/services/socketio/server/broadcaster.py +569 -0
  719. claude_mpm/services/socketio/server/connection_manager.py +579 -0
  720. claude_mpm/services/socketio/server/core.py +1079 -0
  721. claude_mpm/services/socketio/server/eventbus_integration.py +245 -0
  722. claude_mpm/services/socketio/server/main.py +501 -0
  723. claude_mpm/services/socketio_client_manager.py +173 -143
  724. claude_mpm/services/socketio_server.py +38 -1657
  725. claude_mpm/services/subprocess_launcher_service.py +322 -0
  726. claude_mpm/services/system_instructions_service.py +270 -0
  727. claude_mpm/services/ticket_manager.py +25 -209
  728. claude_mpm/services/ticket_services/__init__.py +26 -0
  729. claude_mpm/services/ticket_services/crud_service.py +328 -0
  730. claude_mpm/services/ticket_services/formatter_service.py +290 -0
  731. claude_mpm/services/ticket_services/search_service.py +324 -0
  732. claude_mpm/services/ticket_services/validation_service.py +303 -0
  733. claude_mpm/services/ticket_services/workflow_service.py +244 -0
  734. claude_mpm/services/unified/__init__.py +65 -0
  735. claude_mpm/services/unified/analyzer_strategies/__init__.py +44 -0
  736. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +518 -0
  737. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +680 -0
  738. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +900 -0
  739. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +745 -0
  740. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +733 -0
  741. claude_mpm/services/unified/config_strategies/__init__.py +175 -0
  742. claude_mpm/services/unified/config_strategies/config_schema.py +731 -0
  743. claude_mpm/services/unified/config_strategies/context_strategy.py +747 -0
  744. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1005 -0
  745. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +881 -0
  746. claude_mpm/services/unified/config_strategies/unified_config_service.py +823 -0
  747. claude_mpm/services/unified/config_strategies/validation_strategy.py +1148 -0
  748. claude_mpm/services/unified/deployment_strategies/__init__.py +97 -0
  749. claude_mpm/services/unified/deployment_strategies/base.py +553 -0
  750. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +573 -0
  751. claude_mpm/services/unified/deployment_strategies/local.py +607 -0
  752. claude_mpm/services/unified/deployment_strategies/utils.py +667 -0
  753. claude_mpm/services/unified/deployment_strategies/vercel.py +471 -0
  754. claude_mpm/services/unified/interfaces.py +475 -0
  755. claude_mpm/services/unified/migration.py +509 -0
  756. claude_mpm/services/unified/strategies.py +534 -0
  757. claude_mpm/services/unified/unified_analyzer.py +542 -0
  758. claude_mpm/services/unified/unified_config.py +691 -0
  759. claude_mpm/services/unified/unified_deployment.py +466 -0
  760. claude_mpm/services/utility_service.py +280 -0
  761. claude_mpm/services/version_control/__init__.py +34 -37
  762. claude_mpm/services/version_control/branch_strategy.py +26 -17
  763. claude_mpm/services/version_control/conflict_resolution.py +52 -36
  764. claude_mpm/services/version_control/git_operations.py +183 -49
  765. claude_mpm/services/version_control/semantic_versioning.py +172 -61
  766. claude_mpm/services/version_control/version_parser.py +546 -0
  767. claude_mpm/services/version_service.py +379 -0
  768. claude_mpm/services/visualization/__init__.py +15 -0
  769. claude_mpm/services/visualization/mermaid_generator.py +937 -0
  770. claude_mpm/skills/__init__.py +42 -0
  771. claude_mpm/skills/agent_skills_injector.py +324 -0
  772. claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
  773. claude_mpm/skills/bundled/__init__.py +6 -0
  774. claude_mpm/skills/bundled/api-documentation.md +393 -0
  775. claude_mpm/skills/bundled/async-testing.md +571 -0
  776. claude_mpm/skills/bundled/code-review.md +143 -0
  777. claude_mpm/skills/bundled/database-migration.md +199 -0
  778. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  779. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  780. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  781. claude_mpm/skills/bundled/git-workflow.md +414 -0
  782. claude_mpm/skills/bundled/imagemagick.md +204 -0
  783. claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
  784. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  785. claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
  786. claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
  787. claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
  788. claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
  789. claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -0
  790. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  791. claude_mpm/skills/bundled/pdf.md +141 -0
  792. claude_mpm/skills/bundled/performance-profiling.md +573 -0
  793. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  794. claude_mpm/skills/bundled/security-scanning.md +439 -0
  795. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  796. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  797. claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
  798. claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
  799. claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
  800. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
  801. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  802. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  803. claude_mpm/skills/bundled/xlsx.md +157 -0
  804. claude_mpm/skills/registry.py +286 -0
  805. claude_mpm/skills/skill_manager.py +405 -0
  806. claude_mpm/skills/skills_registry.py +347 -0
  807. claude_mpm/skills/skills_service.py +739 -0
  808. claude_mpm/storage/__init__.py +9 -0
  809. claude_mpm/storage/state_storage.py +546 -0
  810. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  811. claude_mpm/templates/questions/__init__.py +38 -0
  812. claude_mpm/templates/questions/base.py +193 -0
  813. claude_mpm/templates/questions/pr_strategy.py +311 -0
  814. claude_mpm/templates/questions/project_init.py +385 -0
  815. claude_mpm/templates/questions/ticket_mgmt.py +394 -0
  816. claude_mpm/ticket_wrapper.py +2 -2
  817. claude_mpm/tools/__init__.py +10 -0
  818. claude_mpm/tools/__main__.py +208 -0
  819. claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
  820. claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
  821. claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
  822. claude_mpm/tools/code_tree_analyzer/core.py +380 -0
  823. claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
  824. claude_mpm/tools/code_tree_analyzer/events.py +168 -0
  825. claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
  826. claude_mpm/tools/code_tree_analyzer/models.py +39 -0
  827. claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
  828. claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
  829. claude_mpm/tools/code_tree_builder.py +631 -0
  830. claude_mpm/tools/code_tree_events.py +420 -0
  831. claude_mpm/tools/socketio_debug.py +671 -0
  832. claude_mpm/utils/__init__.py +8 -8
  833. claude_mpm/utils/agent_dependency_loader.py +1090 -0
  834. claude_mpm/utils/agent_filters.py +261 -0
  835. claude_mpm/utils/common.py +544 -0
  836. claude_mpm/utils/config_manager.py +168 -126
  837. claude_mpm/utils/console.py +11 -0
  838. claude_mpm/utils/database_connector.py +298 -0
  839. claude_mpm/utils/dependency_cache.py +373 -0
  840. claude_mpm/utils/dependency_manager.py +60 -59
  841. claude_mpm/utils/dependency_strategies.py +381 -0
  842. claude_mpm/utils/display_helper.py +260 -0
  843. claude_mpm/utils/environment_context.py +313 -0
  844. claude_mpm/utils/error_handler.py +78 -66
  845. claude_mpm/utils/file_utils.py +305 -0
  846. claude_mpm/utils/framework_detection.py +12 -11
  847. claude_mpm/utils/git_analyzer.py +407 -0
  848. claude_mpm/utils/gitignore.py +244 -0
  849. claude_mpm/utils/import_migration_example.py +12 -60
  850. claude_mpm/utils/imports.py +48 -45
  851. claude_mpm/utils/log_cleanup.py +627 -0
  852. claude_mpm/utils/migration.py +372 -0
  853. claude_mpm/utils/path_operations.py +110 -104
  854. claude_mpm/utils/progress.py +387 -0
  855. claude_mpm/utils/robust_installer.py +823 -0
  856. claude_mpm/utils/session_logging.py +121 -0
  857. claude_mpm/utils/structured_questions.py +619 -0
  858. claude_mpm/utils/subprocess_utils.py +343 -0
  859. claude_mpm/validation/__init__.py +1 -1
  860. claude_mpm/validation/agent_validator.py +214 -108
  861. claude_mpm/validation/frontmatter_validator.py +252 -0
  862. claude_mpm-5.4.55.dist-info/METADATA +999 -0
  863. claude_mpm-5.4.55.dist-info/RECORD +868 -0
  864. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.55.dist-info}/entry_points.txt +1 -3
  865. claude_mpm-5.4.55.dist-info/licenses/LICENSE +94 -0
  866. claude_mpm-5.4.55.dist-info/licenses/LICENSE-FAQ.md +153 -0
  867. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -88
  868. claude_mpm/agents/INSTRUCTIONS.md +0 -352
  869. claude_mpm/agents/backups/INSTRUCTIONS.md +0 -352
  870. claude_mpm/agents/base_agent_loader.py +0 -529
  871. claude_mpm/agents/schema/agent_schema.json +0 -314
  872. claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -36
  873. claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +0 -46
  874. claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +0 -45
  875. claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +0 -49
  876. claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +0 -46
  877. claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +0 -45
  878. claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +0 -49
  879. claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +0 -46
  880. claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +0 -46
  881. claude_mpm/agents/templates/data_engineer.json +0 -110
  882. claude_mpm/agents/templates/documentation.json +0 -109
  883. claude_mpm/agents/templates/engineer.json +0 -113
  884. claude_mpm/agents/templates/ops.json +0 -109
  885. claude_mpm/agents/templates/pm.json +0 -25
  886. claude_mpm/agents/templates/qa.json +0 -111
  887. claude_mpm/agents/templates/research.json +0 -65
  888. claude_mpm/agents/templates/security.json +0 -113
  889. claude_mpm/agents/templates/test_integration.json +0 -112
  890. claude_mpm/agents/templates/version_control.json +0 -107
  891. claude_mpm/cli/commands/ui.py +0 -57
  892. claude_mpm/core/simple_runner.py +0 -1046
  893. claude_mpm/dashboard/open_dashboard.py +0 -34
  894. claude_mpm/deployment_paths.py +0 -261
  895. claude_mpm/hooks/builtin/__init__.py +0 -1
  896. claude_mpm/hooks/builtin/logging_hook_example.py +0 -165
  897. claude_mpm/hooks/builtin/memory_hooks_example.py +0 -67
  898. claude_mpm/hooks/builtin/mpm_command_hook.py +0 -125
  899. claude_mpm/hooks/builtin/post_delegation_hook_example.py +0 -124
  900. claude_mpm/hooks/builtin/pre_delegation_hook_example.py +0 -125
  901. claude_mpm/hooks/builtin/submit_hook_example.py +0 -100
  902. claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +0 -237
  903. claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +0 -240
  904. claude_mpm/hooks/builtin/workflow_start_hook.py +0 -181
  905. claude_mpm/orchestration/__init__.py +0 -6
  906. claude_mpm/orchestration/archive/direct_orchestrator.py +0 -195
  907. claude_mpm/orchestration/archive/factory.py +0 -215
  908. claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +0 -188
  909. claude_mpm/orchestration/archive/hook_integration_example.py +0 -178
  910. claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +0 -826
  911. claude_mpm/orchestration/archive/orchestrator.py +0 -501
  912. claude_mpm/orchestration/archive/pexpect_orchestrator.py +0 -252
  913. claude_mpm/orchestration/archive/pty_orchestrator.py +0 -270
  914. claude_mpm/orchestration/archive/simple_orchestrator.py +0 -82
  915. claude_mpm/orchestration/archive/subprocess_orchestrator.py +0 -801
  916. claude_mpm/orchestration/archive/system_prompt_orchestrator.py +0 -278
  917. claude_mpm/orchestration/archive/wrapper_orchestrator.py +0 -187
  918. claude_mpm/schemas/workflow_validator.py +0 -411
  919. claude_mpm/services/agent_deployment.py +0 -1534
  920. claude_mpm/services/agent_lifecycle_manager.py +0 -1169
  921. claude_mpm/services/agent_memory_manager.py +0 -1415
  922. claude_mpm/services/agent_registry.py +0 -676
  923. claude_mpm/services/deployed_agent_discovery.py +0 -226
  924. claude_mpm/services/framework_agent_loader.py +0 -337
  925. claude_mpm/services/framework_claude_md_generator.py +0 -621
  926. claude_mpm/services/health_monitor.py +0 -892
  927. claude_mpm/services/memory_router.py +0 -538
  928. claude_mpm/services/parent_directory_manager/__init__.py +0 -577
  929. claude_mpm/services/parent_directory_manager/backup_manager.py +0 -258
  930. claude_mpm/services/parent_directory_manager/config_manager.py +0 -210
  931. claude_mpm/services/parent_directory_manager/deduplication_manager.py +0 -279
  932. claude_mpm/services/parent_directory_manager/framework_protector.py +0 -143
  933. claude_mpm/services/parent_directory_manager/operations.py +0 -186
  934. claude_mpm/services/parent_directory_manager/state_manager.py +0 -624
  935. claude_mpm/services/parent_directory_manager/template_deployer.py +0 -579
  936. claude_mpm/services/parent_directory_manager/validation_manager.py +0 -378
  937. claude_mpm/services/parent_directory_manager/version_control_helper.py +0 -339
  938. claude_mpm/services/parent_directory_manager/version_manager.py +0 -222
  939. claude_mpm/services/standalone_socketio_server.py +0 -1300
  940. claude_mpm/services/ticket_manager_di.py +0 -318
  941. claude_mpm/services/ticketing_service_original.py +0 -508
  942. claude_mpm/ui/__init__.py +0 -1
  943. claude_mpm/ui/rich_terminal_ui.py +0 -295
  944. claude_mpm/ui/terminal_ui.py +0 -328
  945. claude_mpm/utils/paths.py +0 -289
  946. claude_mpm-3.4.10.dist-info/METADATA +0 -183
  947. claude_mpm-3.4.10.dist-info/RECORD +0 -201
  948. claude_mpm-3.4.10.dist-info/licenses/LICENSE +0 -21
  949. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.55.dist-info}/WHEEL +0 -0
  950. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.55.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,798 @@
1
+ """
2
+ Event normalizer for Socket.IO events in claude-mpm.
3
+
4
+ WHY: The system currently has inconsistent event formats across different components.
5
+ This normalizer ensures all events follow a consistent schema before broadcasting,
6
+ providing backward compatibility while establishing a standard format.
7
+
8
+ DESIGN DECISION: Transform all events to a consistent schema:
9
+ - event: Socket.IO event name (always "mpm_event")
10
+ - type: Main category (hook, system, session, file, connection)
11
+ - subtype: Specific event type (pre_tool, heartbeat, started, etc.)
12
+ - timestamp: ISO format timestamp
13
+ - data: Raw event payload
14
+ """
15
+
16
+ import re
17
+ from dataclasses import dataclass, field
18
+ from datetime import datetime, timezone
19
+ from enum import Enum
20
+ from typing import Any, Dict, Optional, Tuple
21
+
22
+ from ...core.logging_config import get_logger
23
+
24
+
25
+ class EventSource(Enum):
26
+ """Event sources.
27
+
28
+ WHY: Identifying where events come from helps with debugging,
29
+ filtering, and understanding system behavior.
30
+ """
31
+
32
+ HOOK = "hook" # Events from Claude Code hooks
33
+ DASHBOARD = "dashboard" # Events from dashboard UI
34
+ SYSTEM = "system" # System/server operations
35
+ AGENT = "agent" # Agent operations
36
+ CLI = "cli" # CLI commands
37
+ API = "api" # API calls
38
+ TEST = "test" # Test scripts
39
+
40
+
41
+ class EventType(Enum):
42
+ """Main event categories.
43
+
44
+ WHY: Categorizing events helps with filtering, routing, and understanding
45
+ the system's behavior at a high level.
46
+ """
47
+
48
+ HOOK = "hook" # Claude Code hook events
49
+ SYSTEM = "system" # System health and status events
50
+ SESSION = "session" # Session lifecycle events
51
+ FILE = "file" # File system events
52
+ CONNECTION = "connection" # Client connection events
53
+ MEMORY = "memory" # Memory system events
54
+ GIT = "git" # Git operation events
55
+ TODO = "todo" # Todo list updates
56
+ TICKET = "ticket" # Ticket system events
57
+ AGENT = "agent" # Agent delegation events
58
+ ERROR = "error" # Error events
59
+ PERFORMANCE = "performance" # Performance metrics
60
+ CLAUDE = "claude" # Claude process events
61
+ TEST = "test" # Test events
62
+ CODE = "code" # Code analysis events
63
+ TOOL = "tool" # Tool events
64
+ SUBAGENT = "subagent" # Subagent events
65
+
66
+
67
+ @dataclass
68
+ class NormalizedEvent:
69
+ """Represents a normalized event with consistent structure.
70
+
71
+ WHY: Using a dataclass ensures type safety and makes the event
72
+ structure explicit and self-documenting.
73
+ """
74
+
75
+ event: str = "mpm_event" # Socket.IO event name
76
+ source: str = "" # WHERE the event comes from
77
+ type: str = "" # WHAT category of event
78
+ subtype: str = "" # Specific event type
79
+ timestamp: str = "" # ISO format timestamp
80
+ data: Dict[str, Any] = field(default_factory=dict) # Event payload
81
+ correlation_id: Optional[str] = (
82
+ None # For correlating related events (e.g., pre_tool/post_tool)
83
+ )
84
+ session_id: Optional[str] = None # Session identifier for stream grouping
85
+ cwd: Optional[str] = None # Working directory for project identification
86
+
87
+ def to_dict(self) -> Dict[str, Any]:
88
+ """Convert to dictionary for emission."""
89
+ result = {
90
+ "event": self.event,
91
+ "source": self.source,
92
+ "type": self.type,
93
+ "subtype": self.subtype,
94
+ "timestamp": self.timestamp,
95
+ "data": self.data,
96
+ }
97
+ # Include correlation_id if present
98
+ if self.correlation_id:
99
+ result["correlation_id"] = self.correlation_id
100
+ # Include session_id if present
101
+ if self.session_id:
102
+ result["session_id"] = self.session_id
103
+ # Include cwd if present
104
+ if self.cwd:
105
+ result["cwd"] = self.cwd
106
+ return result
107
+
108
+
109
+ class EventNormalizer:
110
+ """Normalizes events to a consistent schema.
111
+
112
+ WHY: This class handles the transformation of various event formats
113
+ into a single, consistent schema that clients can reliably parse.
114
+ """
115
+
116
+ # Mapping of event names to (type, subtype) tuples
117
+ EVENT_MAPPINGS = {
118
+ # Hook events
119
+ "pre_tool": (EventType.HOOK, "pre_tool"),
120
+ "post_tool": (EventType.HOOK, "post_tool"),
121
+ "pre_response": (EventType.HOOK, "pre_response"),
122
+ "post_response": (EventType.HOOK, "post_response"),
123
+ "hook_event": (EventType.HOOK, "generic"),
124
+ "hook_execution": (EventType.HOOK, "execution"), # Hook execution metadata
125
+ "UserPrompt": (EventType.HOOK, "user_prompt"), # Legacy format
126
+ # Test events (legacy format)
127
+ "TestStart": (EventType.TEST, "start"),
128
+ "TestEnd": (EventType.TEST, "end"),
129
+ # Tool events (legacy format)
130
+ "ToolCall": (EventType.TOOL, "call"),
131
+ # Subagent events (legacy format)
132
+ "SubagentStart": (EventType.SUBAGENT, "start"),
133
+ "SubagentStop": (EventType.SUBAGENT, "stop"),
134
+ # System events
135
+ "heartbeat": (EventType.SYSTEM, "heartbeat"),
136
+ "system_status": (EventType.SYSTEM, "status"),
137
+ "system_event": (EventType.SYSTEM, "generic"),
138
+ # Session events
139
+ "session_started": (EventType.SESSION, "started"),
140
+ "session_ended": (EventType.SESSION, "ended"),
141
+ "session_event": (EventType.SESSION, "generic"),
142
+ # File events
143
+ "file_changed": (EventType.FILE, "changed"),
144
+ "file_created": (EventType.FILE, "created"),
145
+ "file_deleted": (EventType.FILE, "deleted"),
146
+ "file_event": (EventType.FILE, "generic"),
147
+ # Connection events
148
+ "client_connected": (EventType.CONNECTION, "connected"),
149
+ "client_disconnected": (EventType.CONNECTION, "disconnected"),
150
+ "connection_event": (EventType.CONNECTION, "generic"),
151
+ # Memory events
152
+ "memory_loaded": (EventType.MEMORY, "loaded"),
153
+ "memory_created": (EventType.MEMORY, "created"),
154
+ "memory_updated": (EventType.MEMORY, "updated"),
155
+ "memory_injected": (EventType.MEMORY, "injected"),
156
+ "memory_event": (EventType.MEMORY, "generic"),
157
+ # Git events
158
+ "git_operation": (EventType.GIT, "operation"),
159
+ "git_commit": (EventType.GIT, "commit"),
160
+ "git_push": (EventType.GIT, "push"),
161
+ "git_pull": (EventType.GIT, "pull"),
162
+ # Todo events
163
+ "todo_updated": (EventType.TODO, "updated"),
164
+ "todo_created": (EventType.TODO, "created"),
165
+ "todo_completed": (EventType.TODO, "completed"),
166
+ # Ticket events
167
+ "ticket_created": (EventType.TICKET, "created"),
168
+ "ticket_updated": (EventType.TICKET, "updated"),
169
+ "ticket_closed": (EventType.TICKET, "closed"),
170
+ # Agent events
171
+ "agent_delegated": (EventType.AGENT, "delegated"),
172
+ "agent_completed": (EventType.AGENT, "completed"),
173
+ # Claude events
174
+ "claude_status": (EventType.CLAUDE, "status"),
175
+ "claude_output": (EventType.CLAUDE, "output"),
176
+ "claude_started": (EventType.CLAUDE, "started"),
177
+ "claude_stopped": (EventType.CLAUDE, "stopped"),
178
+ # Error events
179
+ "error": (EventType.ERROR, "general"),
180
+ "error_occurred": (EventType.ERROR, "occurred"),
181
+ # Performance events
182
+ "performance": (EventType.PERFORMANCE, "metric"),
183
+ "performance_metric": (EventType.PERFORMANCE, "metric"),
184
+ }
185
+
186
+ # Patterns to extract event type from various formats
187
+ TYPE_PATTERNS = [
188
+ # Pattern 1: event_type field
189
+ (r'"event_type"\s*:\s*"([^"]+)"', lambda m: m.group(1)),
190
+ # Pattern 2: type field
191
+ (r'"type"\s*:\s*"([^"]+)"', lambda m: m.group(1)),
192
+ # Pattern 3: event field
193
+ (r'"event"\s*:\s*"([^"]+)"', lambda m: m.group(1)),
194
+ # Pattern 4: Hook format (hook:event_name)
195
+ (r'"hook"\s*:\s*"([^"]+)"', lambda m: f"hook_{m.group(1)}"),
196
+ ]
197
+
198
+ def __init__(self):
199
+ self.logger = get_logger(self.__class__.__name__)
200
+ self.stats = {
201
+ "normalized": 0,
202
+ "already_normalized": 0,
203
+ "unknown_format": 0,
204
+ "errors": 0,
205
+ }
206
+
207
+ def normalize(
208
+ self, event_data: Any, source: Optional[str] = None
209
+ ) -> NormalizedEvent:
210
+ """Normalize an event to the standard schema.
211
+
212
+ WHY: This method handles various input formats and transforms them
213
+ into a consistent structure that all clients can understand.
214
+
215
+ Args:
216
+ event_data: The event data in any supported format
217
+ source: Optional source override (e.g., "hook", "dashboard", "test")
218
+
219
+ Returns:
220
+ NormalizedEvent with consistent structure
221
+ """
222
+ try:
223
+ # If already normalized (has all required fields), validate and return
224
+ if self._is_normalized(event_data):
225
+ self.stats["already_normalized"] += 1
226
+ return self._validate_normalized(event_data)
227
+
228
+ # Extract event information from various formats
229
+ event_type, subtype, data = self._extract_event_info(event_data)
230
+
231
+ # Determine event source
232
+ event_source = self._determine_source(event_data, event_type, source)
233
+
234
+ # Get or generate timestamp
235
+ timestamp = self._extract_timestamp(event_data)
236
+
237
+ # Extract correlation_id, session_id, and cwd if present
238
+ correlation_id = None
239
+ session_id = None
240
+ cwd = None
241
+ if isinstance(event_data, dict):
242
+ correlation_id = event_data.get("correlation_id")
243
+ # Try both naming conventions for session_id
244
+ session_id = event_data.get("session_id") or event_data.get("sessionId")
245
+ # Try multiple field names for working directory
246
+ cwd = (
247
+ event_data.get("cwd")
248
+ or event_data.get("working_directory")
249
+ or event_data.get("workingDirectory")
250
+ )
251
+
252
+ # Create normalized event
253
+ normalized = NormalizedEvent(
254
+ event="mpm_event",
255
+ source=event_source,
256
+ type=event_type,
257
+ subtype=subtype,
258
+ timestamp=timestamp,
259
+ data=data,
260
+ correlation_id=correlation_id,
261
+ session_id=session_id,
262
+ cwd=cwd,
263
+ )
264
+
265
+ self.stats["normalized"] += 1
266
+ self.logger.debug(f"Normalized event: {event_type}/{subtype}")
267
+
268
+ return normalized
269
+
270
+ except Exception as e:
271
+ self.stats["errors"] += 1
272
+ self.logger.error(f"Failed to normalize event: {e}")
273
+
274
+ # Return a generic event on error
275
+ return NormalizedEvent(
276
+ event="mpm_event",
277
+ source="system",
278
+ type="unknown",
279
+ subtype="error",
280
+ timestamp=datetime.now(timezone.utc).isoformat(),
281
+ data={"original": str(event_data), "error": str(e)},
282
+ )
283
+
284
+ def _is_normalized(self, event_data: Any) -> bool:
285
+ """Check if event is already in normalized format.
286
+
287
+ WHY: Avoid double-normalization and preserve already correct events.
288
+ """
289
+ if not isinstance(event_data, dict):
290
+ return False
291
+
292
+ # Check for normalized format (must have source, type, subtype, timestamp, and data)
293
+ required_fields = {"source", "type", "subtype", "timestamp", "data"}
294
+ return all(field in event_data for field in required_fields)
295
+
296
+ def _validate_normalized(self, event_data: Dict[str, Any]) -> NormalizedEvent:
297
+ """Validate and convert an already normalized event.
298
+
299
+ WHY: Ensure even pre-normalized events are valid and properly typed.
300
+ """
301
+ # Map source if it's a known indicator
302
+ source = event_data.get("source", "system")
303
+ if source == "claude_hooks":
304
+ source = EventSource.HOOK.value
305
+ elif source not in [e.value for e in EventSource]:
306
+ # If source is not a valid EventSource value, keep it as-is
307
+ pass
308
+
309
+ # Extract session_id and cwd, trying multiple naming conventions
310
+ session_id = event_data.get("session_id") or event_data.get("sessionId")
311
+ cwd = (
312
+ event_data.get("cwd")
313
+ or event_data.get("working_directory")
314
+ or event_data.get("workingDirectory")
315
+ )
316
+
317
+ return NormalizedEvent(
318
+ event="mpm_event", # Always use standard event name
319
+ source=source,
320
+ type=event_data.get("type", "unknown"),
321
+ subtype=event_data.get("subtype", "generic"),
322
+ timestamp=event_data.get(
323
+ "timestamp", datetime.now(timezone.utc).isoformat()
324
+ ),
325
+ data=event_data.get("data", {}),
326
+ correlation_id=event_data.get("correlation_id"),
327
+ session_id=session_id,
328
+ cwd=cwd,
329
+ )
330
+
331
+ def _extract_event_info(self, event_data: Any) -> Tuple[str, str, Dict[str, Any]]:
332
+ """Extract event type, subtype, and data from various formats.
333
+
334
+ WHY: The system has multiple event formats that need to be handled:
335
+ - Simple strings (event names)
336
+ - Dictionaries with type field
337
+ - Hook events with special structure
338
+ - Legacy formats
339
+ """
340
+ # Handle string events (just event name)
341
+ if isinstance(event_data, str):
342
+ event_type, subtype = self._map_event_name(event_data)
343
+ return event_type, subtype, {"event_name": event_data}
344
+
345
+ # Handle dictionary events
346
+ if isinstance(event_data, dict):
347
+ # Special case: type="hook" with event field (legacy hook format)
348
+ if event_data.get("type") == "hook" and "event" in event_data:
349
+ event_type = "hook"
350
+ subtype = event_data["event"]
351
+ data = self._extract_data_payload(event_data)
352
+ return event_type, subtype, data
353
+
354
+ # Try to extract event name/type
355
+ event_name = self._extract_event_name(event_data)
356
+
357
+ # Map to type and subtype
358
+ event_type, subtype = self._map_event_name(event_name)
359
+
360
+ # Extract data payload
361
+ data = self._extract_data_payload(event_data)
362
+
363
+ return event_type, subtype, data
364
+
365
+ # Unknown format
366
+ self.stats["unknown_format"] += 1
367
+ return "unknown", "generic", {"original": str(event_data)}
368
+
369
+ def _extract_event_name(self, event_dict: Dict[str, Any]) -> str:
370
+ """Extract event name from dictionary.
371
+
372
+ WHY: Events use different field names for the event identifier.
373
+ """
374
+ # Priority order for event name fields
375
+ for field in ["event_type", "type", "event", "hook", "name"]:
376
+ if field in event_dict:
377
+ value = event_dict[field]
378
+ if isinstance(value, str):
379
+ return value
380
+
381
+ # Try to extract from JSON string representation
382
+ event_str = str(event_dict)
383
+ for pattern, extractor in self.TYPE_PATTERNS:
384
+ match = re.search(pattern, event_str)
385
+ if match:
386
+ return extractor(match)
387
+
388
+ return "unknown"
389
+
390
+ def _map_event_name(self, event_name: str) -> Tuple[str, str]:
391
+ """Map event name to (type, subtype) tuple.
392
+
393
+ WHY: Consistent categorization helps clients filter and handle events.
394
+ """
395
+ # Direct mapping
396
+ if event_name in self.EVENT_MAPPINGS:
397
+ event_type, subtype = self.EVENT_MAPPINGS[event_name]
398
+ return (
399
+ event_type.value if isinstance(event_type, EventType) else event_type
400
+ ), subtype
401
+
402
+ # Handle colon-separated event names (e.g., "code:analysis:queued", "code:progress")
403
+ # These are commonly used by the code analysis system
404
+ if ":" in event_name:
405
+ parts = event_name.split(":", 2) # Split into max 3 parts
406
+ if len(parts) >= 2:
407
+ type_part = parts[0].lower()
408
+ # For events like "code:analysis:queued", combine the last parts as subtype
409
+ # Replace colons with underscores for clean subtypes
410
+ if len(parts) == 3:
411
+ subtype_part = f"{parts[1]}_{parts[2]}"
412
+ else:
413
+ subtype_part = parts[1].replace(":", "_")
414
+
415
+ # Map the type part to known types
416
+ if type_part in [
417
+ "code", # Code analysis events
418
+ "hook",
419
+ "session",
420
+ "file",
421
+ "system",
422
+ "connection",
423
+ "memory",
424
+ "git",
425
+ "todo",
426
+ "ticket",
427
+ "agent",
428
+ "claude",
429
+ "error",
430
+ "performance",
431
+ "test",
432
+ "tool",
433
+ "subagent",
434
+ ]:
435
+ return type_part, subtype_part
436
+
437
+ # Handle dotted event names (e.g., "connection.status", "session.started")
438
+ if "." in event_name:
439
+ parts = event_name.split(".", 1)
440
+ if len(parts) == 2:
441
+ type_part, subtype_part = parts
442
+ # Map the type part to known types
443
+ type_lower = type_part.lower()
444
+ if type_lower in [
445
+ "hook",
446
+ "session",
447
+ "file",
448
+ "system",
449
+ "connection",
450
+ "memory",
451
+ "git",
452
+ "todo",
453
+ "ticket",
454
+ "agent",
455
+ "claude",
456
+ "error",
457
+ "performance",
458
+ "test",
459
+ "tool",
460
+ "subagent",
461
+ ]:
462
+ return type_lower, subtype_part
463
+
464
+ # Try to infer from event name patterns
465
+ event_lower = event_name.lower()
466
+
467
+ # Check if event name matches a known EventType value directly
468
+ for event_type_enum in EventType:
469
+ if event_lower == event_type_enum.value:
470
+ return event_type_enum.value, "generic"
471
+
472
+ # Hook events (hook_* or *_hook or hook.*)
473
+ if "hook" in event_lower:
474
+ # Handle "hook.event_name" format
475
+ if "hook." in event_lower:
476
+ # Extract the part after "hook."
477
+ parts = event_name.split(".", 1)
478
+ if len(parts) > 1:
479
+ return EventType.HOOK.value, parts[1]
480
+ # Handle pre_ and post_ prefixes
481
+ if event_lower.startswith(("pre_", "post_")):
482
+ return EventType.HOOK.value, event_lower
483
+ return EventType.HOOK.value, "generic"
484
+
485
+ # Session events
486
+ if "session" in event_lower:
487
+ if "start" in event_lower:
488
+ return EventType.SESSION.value, "started"
489
+ if "end" in event_lower:
490
+ return EventType.SESSION.value, "ended"
491
+ return EventType.SESSION.value, "generic"
492
+
493
+ # File events
494
+ if "file" in event_lower:
495
+ if "create" in event_lower:
496
+ return EventType.FILE.value, "created"
497
+ if "delete" in event_lower:
498
+ return EventType.FILE.value, "deleted"
499
+ if "change" in event_lower or "modify" in event_lower:
500
+ return EventType.FILE.value, "changed"
501
+ return EventType.FILE.value, "generic"
502
+
503
+ # System events
504
+ if "system" in event_lower or "heartbeat" in event_lower:
505
+ if "heartbeat" in event_lower:
506
+ return EventType.SYSTEM.value, "heartbeat"
507
+ return EventType.SYSTEM.value, "status"
508
+
509
+ # Connection events
510
+ if "connect" in event_lower or "client" in event_lower:
511
+ if "disconnect" in event_lower:
512
+ return EventType.CONNECTION.value, "disconnected"
513
+ if "connect" in event_lower:
514
+ return EventType.CONNECTION.value, "connected"
515
+ return EventType.CONNECTION.value, "generic"
516
+
517
+ # Memory events
518
+ if "memory" in event_lower:
519
+ if "load" in event_lower:
520
+ return EventType.MEMORY.value, "loaded"
521
+ if "create" in event_lower:
522
+ return EventType.MEMORY.value, "created"
523
+ if "update" in event_lower:
524
+ return EventType.MEMORY.value, "updated"
525
+ if "inject" in event_lower:
526
+ return EventType.MEMORY.value, "injected"
527
+ return EventType.MEMORY.value, "generic"
528
+
529
+ # Code analysis events - using underscores for clean subtypes
530
+ if "code" in event_lower:
531
+ if "analysis" in event_lower:
532
+ if "queue" in event_lower:
533
+ return EventType.CODE.value, "analysis_queued"
534
+ if "start" in event_lower:
535
+ return EventType.CODE.value, "analysis_start"
536
+ if "complete" in event_lower:
537
+ return EventType.CODE.value, "analysis_complete"
538
+ if "error" in event_lower:
539
+ return EventType.CODE.value, "analysis_error"
540
+ if "cancel" in event_lower:
541
+ return EventType.CODE.value, "analysis_cancelled"
542
+ return EventType.CODE.value, "analysis_generic"
543
+ if "progress" in event_lower:
544
+ return EventType.CODE.value, "progress"
545
+ if "file" in event_lower:
546
+ if "discovered" in event_lower:
547
+ return EventType.CODE.value, "file_discovered"
548
+ if "analyzed" in event_lower:
549
+ return EventType.CODE.value, "file_analyzed"
550
+ return EventType.CODE.value, "file_complete"
551
+ if "directory" in event_lower:
552
+ return EventType.CODE.value, "directory_discovered"
553
+ if "node" in event_lower:
554
+ return EventType.CODE.value, "node_found"
555
+ return EventType.CODE.value, "generic"
556
+
557
+ # Default to unknown with lowercase subtype
558
+ return "unknown", event_name.lower() if event_name else ""
559
+
560
+ def _extract_data_payload(self, event_dict: Dict[str, Any]) -> Dict[str, Any]:
561
+ """Extract the data payload from an event dictionary.
562
+
563
+ WHY: Different event formats store the payload in different places.
564
+ """
565
+ # If there's a explicit data field, use it
566
+ if "data" in event_dict:
567
+ return (
568
+ event_dict["data"]
569
+ if isinstance(event_dict["data"], dict)
570
+ else {"value": event_dict["data"]}
571
+ )
572
+
573
+ # Otherwise, use the entire dict minus metadata fields
574
+ metadata_fields = {
575
+ "event",
576
+ "type",
577
+ "subtype",
578
+ "timestamp",
579
+ "event_type",
580
+ "hook",
581
+ }
582
+ data = {k: v for k, v in event_dict.items() if k not in metadata_fields}
583
+
584
+ return data if data else event_dict
585
+
586
+ def _extract_timestamp(self, event_data: Any) -> str:
587
+ """Extract or generate timestamp.
588
+
589
+ WHY: Consistent timestamp format is essential for event ordering
590
+ and debugging.
591
+ """
592
+ if isinstance(event_data, dict):
593
+ # Try various timestamp field names
594
+ for field in ["timestamp", "time", "created_at", "date"]:
595
+ if field in event_data:
596
+ timestamp = event_data[field]
597
+ # Validate it's a string in ISO format
598
+ if isinstance(timestamp, str) and "T" in timestamp:
599
+ return timestamp
600
+ # Convert other formats
601
+ try:
602
+ if isinstance(timestamp, (int, float)):
603
+ return datetime.fromtimestamp(
604
+ timestamp, tz=timezone.utc
605
+ ).isoformat()
606
+ except Exception:
607
+ pass
608
+
609
+ # Generate new timestamp if not found
610
+ return datetime.now(timezone.utc).isoformat()
611
+
612
+ def _determine_source(
613
+ self, event_data: Any, event_type: str, source_override: Optional[str] = None
614
+ ) -> str:
615
+ """Determine the source of an event.
616
+
617
+ WHY: Knowing where events originate helps with debugging,
618
+ filtering, and understanding system behavior.
619
+
620
+ Args:
621
+ event_data: The raw event data
622
+ event_type: The determined event type
623
+ source_override: Optional explicit source
624
+
625
+ Returns:
626
+ The event source as a string
627
+ """
628
+ # Use explicit source override if provided
629
+ if source_override:
630
+ return source_override
631
+
632
+ # Check if event data contains source field
633
+ if isinstance(event_data, dict):
634
+ # Direct source field
635
+ if "source" in event_data:
636
+ source = event_data["source"]
637
+ if isinstance(source, str):
638
+ # Map known source indicators to EventSource values
639
+ if source == "claude_hooks":
640
+ return EventSource.HOOK.value
641
+ # Return the source as-is if it's a valid EventSource value
642
+ valid_sources = [e.value for e in EventSource]
643
+ if source in valid_sources:
644
+ return source
645
+ # Otherwise, keep the original source value
646
+ return source
647
+
648
+ # Check for indicators of specific sources
649
+ # Test indicator - only if type is actually "test"
650
+ if event_type == "test" or (
651
+ isinstance(event_data.get("type"), str)
652
+ and event_data.get("type") == "test"
653
+ ):
654
+ return EventSource.TEST.value
655
+
656
+ # Dashboard indicator
657
+ if "dashboard" in str(event_data).lower() or "ui_action" in event_data:
658
+ return EventSource.DASHBOARD.value
659
+
660
+ # CLI indicator
661
+ if "cli" in str(event_data).lower() or "command" in event_data:
662
+ return EventSource.CLI.value
663
+
664
+ # API indicator
665
+ if "api" in str(event_data).lower() or "endpoint" in event_data:
666
+ return EventSource.API.value
667
+
668
+ # Infer from event type
669
+ if event_type == EventType.HOOK.value:
670
+ return EventSource.HOOK.value
671
+ if event_type == EventType.TEST.value:
672
+ return EventSource.TEST.value
673
+ if event_type in [EventType.AGENT.value, EventType.SUBAGENT.value]:
674
+ return EventSource.AGENT.value
675
+ if event_type in [
676
+ EventType.SYSTEM.value,
677
+ EventType.SESSION.value,
678
+ EventType.CONNECTION.value,
679
+ EventType.PERFORMANCE.value,
680
+ ]:
681
+ return EventSource.SYSTEM.value
682
+
683
+ # Default to system source
684
+ return EventSource.SYSTEM.value
685
+
686
+ def get_stats(self) -> Dict[str, int]:
687
+ """Get normalization statistics.
688
+
689
+ WHY: Monitoring normalization helps identify problematic event sources.
690
+ """
691
+ return self.stats.copy()
692
+
693
+ def reset_stats(self):
694
+ """Reset statistics counters.
695
+
696
+ WHY: Periodic reset prevents counter overflow and enables
697
+ rate calculations.
698
+ """
699
+ self.stats = {
700
+ "normalized": 0,
701
+ "already_normalized": 0,
702
+ "unknown_format": 0,
703
+ "errors": 0,
704
+ }
705
+
706
+
707
+ # Utility functions for consistent event type checking
708
+ def is_hook_event(event_data: Dict[str, Any]) -> bool:
709
+ """Check if an event is a hook event (handles both normalized and legacy formats).
710
+
711
+ WHY: Hook events can come in multiple formats and we need consistent checking
712
+ across the codebase to avoid missing events.
713
+
714
+ Args:
715
+ event_data: Event dictionary to check
716
+
717
+ Returns:
718
+ True if this is a hook event, False otherwise
719
+ """
720
+ if not isinstance(event_data, dict):
721
+ return False
722
+
723
+ event_type = event_data.get("type", "")
724
+
725
+ # Check normalized format: type="hook"
726
+ if event_type == "hook":
727
+ return True
728
+
729
+ # Check legacy format: type="hook.something"
730
+ return bool(isinstance(event_type, str) and event_type.startswith("hook."))
731
+
732
+
733
+ def get_hook_event_name(event_data: Dict[str, Any]) -> str:
734
+ """Extract the hook event name from either normalized or legacy format.
735
+
736
+ WHY: Hook events store their specific name differently in normalized vs legacy
737
+ formats, and we need a consistent way to extract it.
738
+
739
+ Args:
740
+ event_data: Event dictionary containing a hook event
741
+
742
+ Returns:
743
+ The specific hook event name (e.g., "pre_tool", "user_prompt")
744
+ or empty string if not a hook event
745
+ """
746
+ if not is_hook_event(event_data):
747
+ return ""
748
+
749
+ event_type = event_data.get("type", "")
750
+ event_subtype = event_data.get("subtype", "")
751
+
752
+ # Normalized format: type="hook", subtype="pre_tool"
753
+ if event_type == "hook" and event_subtype:
754
+ return event_subtype
755
+
756
+ # Legacy format: type="hook.pre_tool"
757
+ if isinstance(event_type, str) and event_type.startswith("hook."):
758
+ return event_type[5:] # Remove "hook." prefix
759
+
760
+ # Fallback: check 'event' field (another legacy format)
761
+ return event_data.get("event", "")
762
+
763
+
764
+ def is_event_type(
765
+ event_data: Dict[str, Any], type_name: str, subtype: Optional[str] = None
766
+ ) -> bool:
767
+ """Check if an event matches a specific type and optionally subtype.
768
+
769
+ WHY: This provides a consistent way to check event types that works with
770
+ both normalized and legacy formats.
771
+
772
+ Args:
773
+ event_data: Event dictionary to check
774
+ type_name: The type to check for (e.g., "hook", "session", "file")
775
+ subtype: Optional subtype to also check (e.g., "pre_tool", "started")
776
+
777
+ Returns:
778
+ True if the event matches the specified type (and subtype if provided)
779
+ """
780
+ if not isinstance(event_data, dict):
781
+ return False
782
+
783
+ event_type = event_data.get("type", "")
784
+ event_subtype = event_data.get("subtype", "")
785
+
786
+ # Check normalized format
787
+ if event_type == type_name:
788
+ if subtype is None:
789
+ return True
790
+ return event_subtype == subtype
791
+
792
+ # Check legacy dotted format (e.g., "hook.pre_tool")
793
+ if subtype and isinstance(event_type, str):
794
+ legacy_type = f"{type_name}.{subtype}"
795
+ if event_type == legacy_type:
796
+ return True
797
+
798
+ return False