claude-mpm 3.4.10__py3-none-any.whl → 5.4.85__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 (1062) 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_FOUNDERS_OUTPUT_STYLE.md +405 -0
  8. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +112 -0
  9. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +186 -0
  10. claude_mpm/agents/MEMORY.md +72 -0
  11. claude_mpm/agents/PM_INSTRUCTIONS.md +1429 -0
  12. claude_mpm/agents/WORKFLOW.md +111 -0
  13. claude_mpm/agents/__init__.py +92 -80
  14. claude_mpm/agents/agent-template.yaml +83 -0
  15. claude_mpm/agents/agent_loader.py +560 -745
  16. claude_mpm/agents/agent_loader_integration.py +53 -55
  17. claude_mpm/agents/agents_metadata.py +186 -27
  18. claude_mpm/agents/async_agent_loader.py +436 -0
  19. claude_mpm/agents/base_agent.json +8 -4
  20. claude_mpm/agents/frontmatter_validator.py +754 -0
  21. claude_mpm/agents/system_agent_config.py +222 -155
  22. claude_mpm/agents/templates/README.md +465 -0
  23. claude_mpm/agents/templates/__init__.py +17 -13
  24. claude_mpm/agents/templates/circuit-breakers.md +1391 -0
  25. claude_mpm/agents/templates/context-management-examples.md +544 -0
  26. claude_mpm/agents/templates/git-file-tracking.md +584 -0
  27. claude_mpm/agents/templates/pm-examples.md +474 -0
  28. claude_mpm/agents/templates/pm-red-flags.md +310 -0
  29. claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
  30. claude_mpm/agents/templates/research-gate-examples.md +669 -0
  31. claude_mpm/agents/templates/response-format.md +583 -0
  32. claude_mpm/agents/templates/structured-questions-examples.md +615 -0
  33. claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
  34. claude_mpm/agents/templates/ticketing-examples.md +277 -0
  35. claude_mpm/agents/templates/validation-templates.md +312 -0
  36. claude_mpm/cli/__init__.py +94 -128
  37. claude_mpm/cli/__main__.py +33 -0
  38. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  39. claude_mpm/cli/commands/__init__.py +36 -12
  40. claude_mpm/cli/commands/agent_manager.py +1403 -0
  41. claude_mpm/cli/commands/agent_source.py +774 -0
  42. claude_mpm/cli/commands/agent_state_manager.py +335 -0
  43. claude_mpm/cli/commands/agents.py +2501 -168
  44. claude_mpm/cli/commands/agents_cleanup.py +210 -0
  45. claude_mpm/cli/commands/agents_discover.py +338 -0
  46. claude_mpm/cli/commands/agents_reconcile.py +197 -0
  47. claude_mpm/cli/commands/aggregate.py +540 -0
  48. claude_mpm/cli/commands/analyze.py +553 -0
  49. claude_mpm/cli/commands/analyze_code.py +528 -0
  50. claude_mpm/cli/commands/auto_configure.py +1053 -0
  51. claude_mpm/cli/commands/cleanup.py +588 -0
  52. claude_mpm/cli/commands/cleanup_orphaned_agents.py +150 -0
  53. claude_mpm/cli/commands/config.py +586 -0
  54. claude_mpm/cli/commands/configure.py +3253 -0
  55. claude_mpm/cli/commands/configure_agent_display.py +282 -0
  56. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  57. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  58. claude_mpm/cli/commands/configure_models.py +18 -0
  59. claude_mpm/cli/commands/configure_navigation.py +184 -0
  60. claude_mpm/cli/commands/configure_paths.py +104 -0
  61. claude_mpm/cli/commands/configure_persistence.py +254 -0
  62. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  63. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  64. claude_mpm/cli/commands/configure_validators.py +73 -0
  65. claude_mpm/cli/commands/dashboard.py +286 -0
  66. claude_mpm/cli/commands/debug.py +1386 -0
  67. claude_mpm/cli/commands/doctor.py +243 -0
  68. claude_mpm/cli/commands/hook_errors.py +277 -0
  69. claude_mpm/cli/commands/info.py +195 -74
  70. claude_mpm/cli/commands/local_deploy.py +534 -0
  71. claude_mpm/cli/commands/mcp.py +205 -0
  72. claude_mpm/cli/commands/mcp_command_router.py +161 -0
  73. claude_mpm/cli/commands/mcp_config.py +154 -0
  74. claude_mpm/cli/commands/mcp_config_commands.py +20 -0
  75. claude_mpm/cli/commands/mcp_external_commands.py +249 -0
  76. claude_mpm/cli/commands/mcp_install_commands.py +346 -0
  77. claude_mpm/cli/commands/mcp_pipx_config.py +208 -0
  78. claude_mpm/cli/commands/mcp_server_commands.py +155 -0
  79. claude_mpm/cli/commands/mcp_setup_external.py +868 -0
  80. claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
  81. claude_mpm/cli/commands/memory.py +585 -846
  82. claude_mpm/cli/commands/monitor.py +228 -310
  83. claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
  84. claude_mpm/cli/commands/mpm_init/core.py +759 -0
  85. claude_mpm/cli/commands/mpm_init/display.py +341 -0
  86. claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
  87. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  88. claude_mpm/cli/commands/mpm_init/modes.py +397 -0
  89. claude_mpm/cli/commands/mpm_init/prompts.py +722 -0
  90. claude_mpm/cli/commands/mpm_init_cli.py +396 -0
  91. claude_mpm/cli/commands/mpm_init_handler.py +195 -0
  92. claude_mpm/cli/commands/postmortem.py +401 -0
  93. claude_mpm/cli/commands/profile.py +276 -0
  94. claude_mpm/cli/commands/run.py +910 -488
  95. claude_mpm/cli/commands/search.py +458 -0
  96. claude_mpm/cli/commands/skill_source.py +694 -0
  97. claude_mpm/cli/commands/skills.py +1398 -0
  98. claude_mpm/cli/commands/summarize.py +413 -0
  99. claude_mpm/cli/commands/tickets.py +536 -53
  100. claude_mpm/cli/commands/uninstall.py +176 -0
  101. claude_mpm/cli/commands/upgrade.py +152 -0
  102. claude_mpm/cli/commands/verify.py +119 -0
  103. claude_mpm/cli/executor.py +298 -0
  104. claude_mpm/cli/helpers.py +105 -0
  105. claude_mpm/cli/interactive/__init__.py +31 -0
  106. claude_mpm/cli/interactive/agent_wizard.py +1927 -0
  107. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  108. claude_mpm/cli/interactive/skill_selector.py +481 -0
  109. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  110. claude_mpm/cli/parser.py +87 -563
  111. claude_mpm/cli/parsers/__init__.py +35 -0
  112. claude_mpm/cli/parsers/agent_manager_parser.py +393 -0
  113. claude_mpm/cli/parsers/agent_source_parser.py +171 -0
  114. claude_mpm/cli/parsers/agents_parser.py +575 -0
  115. claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
  116. claude_mpm/cli/parsers/analyze_parser.py +135 -0
  117. claude_mpm/cli/parsers/auto_configure_parser.py +120 -0
  118. claude_mpm/cli/parsers/base_parser.py +649 -0
  119. claude_mpm/cli/parsers/config_parser.py +208 -0
  120. claude_mpm/cli/parsers/configure_parser.py +138 -0
  121. claude_mpm/cli/parsers/dashboard_parser.py +113 -0
  122. claude_mpm/cli/parsers/debug_parser.py +319 -0
  123. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  124. claude_mpm/cli/parsers/mcp_parser.py +195 -0
  125. claude_mpm/cli/parsers/memory_parser.py +138 -0
  126. claude_mpm/cli/parsers/monitor_parser.py +142 -0
  127. claude_mpm/cli/parsers/mpm_init_parser.py +311 -0
  128. claude_mpm/cli/parsers/profile_parser.py +147 -0
  129. claude_mpm/cli/parsers/run_parser.py +157 -0
  130. claude_mpm/cli/parsers/search_parser.py +245 -0
  131. claude_mpm/cli/parsers/skill_source_parser.py +169 -0
  132. claude_mpm/cli/parsers/skills_parser.py +277 -0
  133. claude_mpm/cli/parsers/source_parser.py +138 -0
  134. claude_mpm/cli/parsers/tickets_parser.py +203 -0
  135. claude_mpm/cli/shared/__init__.py +40 -0
  136. claude_mpm/cli/shared/argument_patterns.py +205 -0
  137. claude_mpm/cli/shared/base_command.py +242 -0
  138. claude_mpm/cli/shared/error_handling.py +242 -0
  139. claude_mpm/cli/shared/output_formatters.py +241 -0
  140. claude_mpm/cli/startup.py +1578 -0
  141. claude_mpm/cli/startup_display.py +480 -0
  142. claude_mpm/cli/startup_logging.py +839 -0
  143. claude_mpm/cli/utils.py +136 -47
  144. claude_mpm/cli_module/__init__.py +6 -6
  145. claude_mpm/cli_module/args.py +188 -140
  146. claude_mpm/cli_module/commands.py +79 -70
  147. claude_mpm/cli_module/migration_example.py +42 -64
  148. claude_mpm/commands/__init__.py +14 -0
  149. claude_mpm/commands/mpm-config.md +28 -0
  150. claude_mpm/commands/mpm-doctor.md +20 -0
  151. claude_mpm/commands/mpm-help.md +20 -0
  152. claude_mpm/commands/mpm-init.md +120 -0
  153. claude_mpm/commands/mpm-monitor.md +31 -0
  154. claude_mpm/commands/mpm-organize.md +120 -0
  155. claude_mpm/commands/mpm-postmortem.md +21 -0
  156. claude_mpm/commands/mpm-session-resume.md +30 -0
  157. claude_mpm/commands/mpm-status.md +20 -0
  158. claude_mpm/commands/mpm-ticket-view.md +109 -0
  159. claude_mpm/commands/mpm-version.md +20 -0
  160. claude_mpm/commands/mpm.md +31 -0
  161. claude_mpm/config/__init__.py +42 -2
  162. claude_mpm/config/agent_config.py +402 -0
  163. claude_mpm/config/agent_presets.py +488 -0
  164. claude_mpm/config/agent_sources.py +352 -0
  165. claude_mpm/config/experimental_features.py +217 -0
  166. claude_mpm/config/model_config.py +428 -0
  167. claude_mpm/config/paths.py +258 -0
  168. claude_mpm/config/skill_presets.py +392 -0
  169. claude_mpm/config/skill_sources.py +590 -0
  170. claude_mpm/config/socketio_config.py +125 -83
  171. claude_mpm/constants.py +133 -22
  172. claude_mpm/core/__init__.py +62 -36
  173. claude_mpm/core/agent_name_normalizer.py +71 -73
  174. claude_mpm/core/agent_registry.py +385 -492
  175. claude_mpm/core/agent_session_manager.py +81 -70
  176. claude_mpm/core/api_validator.py +330 -0
  177. claude_mpm/core/base_service.py +159 -122
  178. claude_mpm/core/cache.py +560 -0
  179. claude_mpm/core/claude_runner.py +696 -916
  180. claude_mpm/core/config.py +613 -122
  181. claude_mpm/core/config_aliases.py +74 -73
  182. claude_mpm/core/config_constants.py +314 -0
  183. claude_mpm/core/constants.py +361 -0
  184. claude_mpm/core/container.py +646 -104
  185. claude_mpm/core/enums.py +452 -0
  186. claude_mpm/core/error_handler.py +623 -0
  187. claude_mpm/core/exceptions.py +536 -0
  188. claude_mpm/core/factories.py +105 -109
  189. claude_mpm/core/file_utils.py +764 -0
  190. claude_mpm/core/framework/__init__.py +25 -0
  191. claude_mpm/core/framework/formatters/__init__.py +11 -0
  192. claude_mpm/core/framework/formatters/capability_generator.py +367 -0
  193. claude_mpm/core/framework/formatters/content_formatter.py +278 -0
  194. claude_mpm/core/framework/formatters/context_generator.py +185 -0
  195. claude_mpm/core/framework/loaders/__init__.py +13 -0
  196. claude_mpm/core/framework/loaders/agent_loader.py +213 -0
  197. claude_mpm/core/framework/loaders/file_loader.py +176 -0
  198. claude_mpm/core/framework/loaders/instruction_loader.py +222 -0
  199. claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
  200. claude_mpm/core/framework/processors/__init__.py +11 -0
  201. claude_mpm/core/framework/processors/memory_processor.py +230 -0
  202. claude_mpm/core/framework/processors/metadata_processor.py +146 -0
  203. claude_mpm/core/framework/processors/template_processor.py +244 -0
  204. claude_mpm/core/framework_loader.py +485 -414
  205. claude_mpm/core/hook_error_memory.py +381 -0
  206. claude_mpm/core/hook_manager.py +246 -86
  207. claude_mpm/core/hook_performance_config.py +147 -0
  208. claude_mpm/core/injectable_service.py +72 -63
  209. claude_mpm/core/instruction_reinforcement_hook.py +267 -0
  210. claude_mpm/core/interactive_session.py +670 -0
  211. claude_mpm/core/interfaces.py +570 -164
  212. claude_mpm/core/lazy.py +467 -0
  213. claude_mpm/core/log_manager.py +707 -0
  214. claude_mpm/core/logger.py +295 -134
  215. claude_mpm/core/logging_config.py +474 -0
  216. claude_mpm/core/logging_utils.py +520 -0
  217. claude_mpm/core/minimal_framework_loader.py +24 -22
  218. claude_mpm/core/mixins.py +30 -29
  219. claude_mpm/core/oneshot_session.py +594 -0
  220. claude_mpm/core/optimized_agent_loader.py +479 -0
  221. claude_mpm/core/optimized_startup.py +554 -0
  222. claude_mpm/core/output_style_manager.py +491 -0
  223. claude_mpm/core/pm_hook_interceptor.py +197 -82
  224. claude_mpm/core/protocols/__init__.py +23 -0
  225. claude_mpm/core/protocols/runner_protocol.py +103 -0
  226. claude_mpm/core/protocols/session_protocol.py +131 -0
  227. claude_mpm/core/service_registry.py +153 -116
  228. claude_mpm/core/session_manager.py +179 -64
  229. claude_mpm/core/shared/__init__.py +17 -0
  230. claude_mpm/core/shared/config_loader.py +326 -0
  231. claude_mpm/core/shared/path_resolver.py +281 -0
  232. claude_mpm/core/shared/singleton_manager.py +221 -0
  233. claude_mpm/core/socketio_pool.py +400 -137
  234. claude_mpm/core/system_context.py +38 -0
  235. claude_mpm/core/tool_access_control.py +64 -57
  236. claude_mpm/core/types.py +307 -0
  237. claude_mpm/core/typing_utils.py +553 -0
  238. claude_mpm/core/unified_agent_registry.py +969 -0
  239. claude_mpm/core/unified_config.py +612 -0
  240. claude_mpm/core/unified_paths.py +958 -0
  241. claude_mpm/dashboard/__init__.py +12 -0
  242. claude_mpm/dashboard/api/simple_directory.py +261 -0
  243. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  244. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +1 -0
  245. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +1 -0
  246. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +1 -0
  247. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +24 -0
  248. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B0uc0UOD.js +36 -0
  249. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7RN905-.js +1 -0
  250. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7xVLGWV.js +2 -0
  251. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BIF9m_hv.js +61 -0
  252. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +1 -0
  253. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BPYeabCQ.js +1 -0
  254. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  255. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
  256. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Be7GpZd6.js +7 -0
  257. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bh0LDWpI.js +145 -0
  258. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BofRWZRR.js +10 -0
  259. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BovzEFCE.js +30 -0
  260. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C30mlcqg.js +165 -0
  261. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4B-KCzX.js +1 -0
  262. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4JcI4KD.js +122 -0
  263. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CBBdVcY8.js +1 -0
  264. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CDuw-vjf.js +1 -0
  265. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C_Usid8X.js +15 -0
  266. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cfqx1Qun.js +10 -0
  267. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CiIAseT4.js +128 -0
  268. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  269. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CnA0NrzZ.js +1 -0
  270. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cs_tUR18.js +24 -0
  271. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  272. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CyWMqx4W.js +43 -0
  273. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzZX-COe.js +220 -0
  274. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzeYkLYB.js +65 -0
  275. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D3k0OPJN.js +4 -0
  276. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9lljYKQ.js +1 -0
  277. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DGkLK5U1.js +267 -0
  278. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DI7hHRFL.js +1 -0
  279. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DLVjFsZ3.js +139 -0
  280. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUrLdbGD.js +89 -0
  281. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  282. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DY1XQ8fi.js +2 -0
  283. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DZX00Y4g.js +1 -0
  284. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +1 -0
  285. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DaimHw_p.js +68 -0
  286. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +323 -0
  287. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dhb8PKl3.js +1 -0
  288. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dle-35c7.js +64 -0
  289. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DmxopI1J.js +1 -0
  290. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DwBR2MJi.js +60 -0
  291. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/GYwsonyD.js +1 -0
  292. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  293. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
  294. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/RJiighC3.js +1 -0
  295. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Vzk33B_K.js +2 -0
  296. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ZGh7QtNv.js +7 -0
  297. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bT1r9zLR.js +1 -0
  298. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bTOqqlTd.js +1 -0
  299. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/eNVUfhuA.js +1 -0
  300. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/iEWssX7S.js +162 -0
  301. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/sQeU3Y1z.js +1 -0
  302. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uuIeMWc-.js +1 -0
  303. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.D6-I5TpK.js +2 -0
  304. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +1 -0
  305. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.m1gL8KXf.js +1 -0
  306. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.CgNOuw-d.js +1 -0
  307. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +1 -0
  308. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  309. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  310. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  311. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  312. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  313. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  314. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  315. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  316. claude_mpm/experimental/__init__.py +10 -0
  317. claude_mpm/experimental/cli_enhancements.py +104 -89
  318. claude_mpm/generators/__init__.py +1 -1
  319. claude_mpm/generators/agent_profile_generator.py +76 -66
  320. claude_mpm/hooks/__init__.py +37 -1
  321. claude_mpm/hooks/base_hook.py +37 -32
  322. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  323. claude_mpm/hooks/claude_hooks/connection_pool.py +250 -0
  324. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  325. claude_mpm/hooks/claude_hooks/event_handlers.py +888 -0
  326. claude_mpm/hooks/claude_hooks/hook_handler.py +652 -875
  327. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +10 -7
  328. claude_mpm/hooks/claude_hooks/installer.py +806 -0
  329. claude_mpm/hooks/claude_hooks/memory_integration.py +249 -0
  330. claude_mpm/hooks/claude_hooks/response_tracking.py +412 -0
  331. claude_mpm/hooks/claude_hooks/services/__init__.py +15 -0
  332. claude_mpm/hooks/claude_hooks/services/connection_manager.py +229 -0
  333. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +254 -0
  334. claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
  335. claude_mpm/hooks/claude_hooks/services/state_manager.py +284 -0
  336. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
  337. claude_mpm/hooks/claude_hooks/tool_analysis.py +224 -0
  338. claude_mpm/hooks/failure_learning/__init__.py +54 -0
  339. claude_mpm/hooks/failure_learning/failure_detection_hook.py +230 -0
  340. claude_mpm/hooks/failure_learning/fix_detection_hook.py +212 -0
  341. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +281 -0
  342. claude_mpm/hooks/instruction_reinforcement.py +301 -0
  343. claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
  344. claude_mpm/hooks/kuzu_memory_hook.py +386 -0
  345. claude_mpm/hooks/kuzu_response_hook.py +179 -0
  346. claude_mpm/hooks/memory_integration_hook.py +201 -107
  347. claude_mpm/hooks/session_resume_hook.py +121 -0
  348. claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
  349. claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
  350. claude_mpm/hooks/tool_call_interceptor.py +92 -76
  351. claude_mpm/hooks/validation_hooks.py +62 -54
  352. claude_mpm/init.py +518 -83
  353. claude_mpm/models/__init__.py +9 -9
  354. claude_mpm/models/agent_definition.py +40 -23
  355. claude_mpm/models/agent_session.py +538 -0
  356. claude_mpm/models/git_repository.py +198 -0
  357. claude_mpm/models/resume_log.py +340 -0
  358. claude_mpm/schemas/__init__.py +12 -0
  359. claude_mpm/scripts/__init__.py +15 -0
  360. claude_mpm/scripts/claude-hook-handler.sh +227 -0
  361. claude_mpm/scripts/launch_monitor.py +165 -0
  362. claude_mpm/scripts/mpm_doctor.py +322 -0
  363. claude_mpm/scripts/socketio_daemon.py +189 -200
  364. claude_mpm/scripts/start_activity_logging.py +91 -0
  365. claude_mpm/services/__init__.py +208 -39
  366. claude_mpm/services/agent_capabilities_service.py +266 -0
  367. claude_mpm/services/agents/__init__.py +89 -0
  368. claude_mpm/services/agents/agent_builder.py +514 -0
  369. claude_mpm/services/agents/agent_preset_service.py +238 -0
  370. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  371. claude_mpm/services/agents/agent_review_service.py +280 -0
  372. claude_mpm/services/agents/agent_selection_service.py +484 -0
  373. claude_mpm/services/agents/auto_config_manager.py +796 -0
  374. claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
  375. claude_mpm/services/agents/cache_git_manager.py +621 -0
  376. claude_mpm/services/agents/deployment/__init__.py +21 -0
  377. claude_mpm/services/agents/deployment/agent_config_provider.py +410 -0
  378. claude_mpm/services/agents/deployment/agent_configuration_manager.py +358 -0
  379. claude_mpm/services/agents/deployment/agent_definition_factory.py +80 -0
  380. claude_mpm/services/agents/deployment/agent_deployment.py +1037 -0
  381. claude_mpm/services/agents/deployment/agent_discovery_service.py +546 -0
  382. claude_mpm/services/agents/deployment/agent_environment_manager.py +288 -0
  383. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +383 -0
  384. claude_mpm/services/agents/deployment/agent_format_converter.py +505 -0
  385. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +160 -0
  386. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +957 -0
  387. claude_mpm/services/agents/deployment/agent_metrics_collector.py +273 -0
  388. claude_mpm/services/agents/deployment/agent_operation_service.py +573 -0
  389. claude_mpm/services/agents/deployment/agent_record_service.py +418 -0
  390. claude_mpm/services/agents/deployment/agent_restore_handler.py +84 -0
  391. claude_mpm/services/agents/deployment/agent_state_service.py +381 -0
  392. claude_mpm/services/agents/deployment/agent_template_builder.py +1377 -0
  393. claude_mpm/services/agents/deployment/agent_validator.py +376 -0
  394. claude_mpm/services/agents/deployment/agent_version_manager.py +322 -0
  395. claude_mpm/services/{agent_versioning.py → agents/deployment/agent_versioning.py} +10 -13
  396. claude_mpm/services/agents/deployment/agents_directory_resolver.py +149 -0
  397. claude_mpm/services/agents/deployment/async_agent_deployment.py +768 -0
  398. claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
  399. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  400. claude_mpm/services/agents/deployment/config/deployment_config.py +181 -0
  401. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  402. claude_mpm/services/agents/deployment/deployment_config_loader.py +178 -0
  403. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  404. claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
  405. claude_mpm/services/agents/deployment/deployment_type_detector.py +120 -0
  406. claude_mpm/services/agents/deployment/deployment_wrapper.py +129 -0
  407. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  408. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  409. claude_mpm/services/agents/deployment/facade/deployment_executor.py +70 -0
  410. claude_mpm/services/agents/deployment/facade/deployment_facade.py +269 -0
  411. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  412. claude_mpm/services/agents/deployment/interface_adapter.py +226 -0
  413. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  414. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  415. claude_mpm/services/agents/deployment/local_template_deployment.py +362 -0
  416. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +1478 -0
  417. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  418. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  419. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +162 -0
  420. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  421. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  422. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +240 -0
  423. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +110 -0
  424. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +80 -0
  425. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +92 -0
  426. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +101 -0
  427. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  428. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +102 -0
  429. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  430. claude_mpm/services/agents/deployment/processors/agent_processor.py +269 -0
  431. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +311 -0
  432. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +862 -0
  433. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  434. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  435. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  436. claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
  437. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  438. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  439. claude_mpm/services/agents/deployment/strategies/base_strategy.py +113 -0
  440. claude_mpm/services/agents/deployment/strategies/project_strategy.py +148 -0
  441. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  442. claude_mpm/services/agents/deployment/strategies/system_strategy.py +131 -0
  443. claude_mpm/services/agents/deployment/strategies/user_strategy.py +130 -0
  444. claude_mpm/services/agents/deployment/system_instructions_deployer.py +228 -0
  445. claude_mpm/services/agents/deployment/validation/__init__.py +21 -0
  446. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  447. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  448. claude_mpm/services/agents/deployment/validation/template_validator.py +319 -0
  449. claude_mpm/services/agents/deployment/validation/validation_result.py +214 -0
  450. claude_mpm/services/agents/git_source_manager.py +682 -0
  451. claude_mpm/services/agents/loading/__init__.py +11 -0
  452. claude_mpm/services/{agent_profile_loader.py → agents/loading/agent_profile_loader.py} +306 -228
  453. claude_mpm/services/{base_agent_manager.py → agents/loading/base_agent_manager.py} +106 -91
  454. claude_mpm/services/agents/loading/framework_agent_loader.py +433 -0
  455. claude_mpm/services/agents/local_template_manager.py +784 -0
  456. claude_mpm/services/agents/management/__init__.py +9 -0
  457. claude_mpm/services/{agent_capabilities_generator.py → agents/management/agent_capabilities_generator.py} +92 -69
  458. claude_mpm/services/{agent_management_service.py → agents/management/agent_management_service.py} +219 -168
  459. claude_mpm/services/agents/memory/__init__.py +22 -0
  460. claude_mpm/services/agents/memory/agent_memory_manager.py +784 -0
  461. claude_mpm/services/{agent_persistence_service.py → agents/memory/agent_persistence_service.py} +20 -18
  462. claude_mpm/services/agents/memory/content_manager.py +470 -0
  463. claude_mpm/services/agents/memory/memory_categorization_service.py +167 -0
  464. claude_mpm/services/agents/memory/memory_file_service.py +129 -0
  465. claude_mpm/services/agents/memory/memory_format_service.py +201 -0
  466. claude_mpm/services/agents/memory/memory_limits_service.py +101 -0
  467. claude_mpm/services/agents/memory/template_generator.py +83 -0
  468. claude_mpm/services/agents/observers.py +547 -0
  469. claude_mpm/services/agents/recommender.py +617 -0
  470. claude_mpm/services/agents/registry/__init__.py +30 -0
  471. claude_mpm/services/agents/registry/deployed_agent_discovery.py +273 -0
  472. claude_mpm/services/{agent_modification_tracker.py → agents/registry/modification_tracker.py} +370 -295
  473. claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
  474. claude_mpm/services/agents/sources/__init__.py +13 -0
  475. claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
  476. claude_mpm/services/agents/sources/git_source_sync_service.py +1205 -0
  477. claude_mpm/services/agents/startup_sync.py +262 -0
  478. claude_mpm/services/agents/toolchain_detector.py +478 -0
  479. claude_mpm/services/analysis/__init__.py +35 -0
  480. claude_mpm/services/analysis/clone_detector.py +1030 -0
  481. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  482. claude_mpm/services/analysis/postmortem_service.py +765 -0
  483. claude_mpm/services/async_session_logger.py +665 -0
  484. claude_mpm/services/claude_session_logger.py +321 -0
  485. claude_mpm/services/cli/__init__.py +18 -0
  486. claude_mpm/services/cli/agent_cleanup_service.py +408 -0
  487. claude_mpm/services/cli/agent_dependency_service.py +395 -0
  488. claude_mpm/services/cli/agent_listing_service.py +463 -0
  489. claude_mpm/services/cli/agent_output_formatter.py +605 -0
  490. claude_mpm/services/cli/agent_validation_service.py +590 -0
  491. claude_mpm/services/cli/memory_crud_service.py +622 -0
  492. claude_mpm/services/cli/memory_output_formatter.py +604 -0
  493. claude_mpm/services/cli/resume_service.py +617 -0
  494. claude_mpm/services/cli/session_manager.py +604 -0
  495. claude_mpm/services/cli/session_pause_manager.py +504 -0
  496. claude_mpm/services/cli/session_resume_helper.py +372 -0
  497. claude_mpm/services/cli/startup_checker.py +362 -0
  498. claude_mpm/services/cli/unified_dashboard_manager.py +439 -0
  499. claude_mpm/services/command_deployment_service.py +446 -0
  500. claude_mpm/services/command_handler_service.py +221 -0
  501. claude_mpm/services/communication/__init__.py +22 -0
  502. claude_mpm/services/core/__init__.py +108 -0
  503. claude_mpm/services/core/base.py +269 -0
  504. claude_mpm/services/core/cache_manager.py +309 -0
  505. claude_mpm/services/core/interfaces/__init__.py +273 -0
  506. claude_mpm/services/core/interfaces/agent.py +514 -0
  507. claude_mpm/services/core/interfaces/communication.py +316 -0
  508. claude_mpm/services/core/interfaces/health.py +169 -0
  509. claude_mpm/services/core/interfaces/infrastructure.py +357 -0
  510. claude_mpm/services/core/interfaces/model.py +281 -0
  511. claude_mpm/services/core/interfaces/process.py +372 -0
  512. claude_mpm/services/core/interfaces/project.py +121 -0
  513. claude_mpm/services/core/interfaces/restart.py +307 -0
  514. claude_mpm/services/core/interfaces/service.py +405 -0
  515. claude_mpm/services/core/interfaces/stability.py +260 -0
  516. claude_mpm/services/core/interfaces.py +81 -0
  517. claude_mpm/services/core/memory_manager.py +682 -0
  518. claude_mpm/services/core/models/__init__.py +70 -0
  519. claude_mpm/services/core/models/agent_config.py +384 -0
  520. claude_mpm/services/core/models/health.py +162 -0
  521. claude_mpm/services/core/models/process.py +239 -0
  522. claude_mpm/services/core/models/restart.py +302 -0
  523. claude_mpm/services/core/models/stability.py +264 -0
  524. claude_mpm/services/core/models/toolchain.py +306 -0
  525. claude_mpm/services/core/path_resolver.py +517 -0
  526. claude_mpm/services/core/service_container.py +520 -0
  527. claude_mpm/services/core/service_interfaces.py +436 -0
  528. claude_mpm/services/diagnostics/__init__.py +18 -0
  529. claude_mpm/services/diagnostics/checks/__init__.py +38 -0
  530. claude_mpm/services/diagnostics/checks/agent_check.py +370 -0
  531. claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
  532. claude_mpm/services/diagnostics/checks/base_check.py +60 -0
  533. claude_mpm/services/diagnostics/checks/claude_code_check.py +270 -0
  534. claude_mpm/services/diagnostics/checks/common_issues_check.py +363 -0
  535. claude_mpm/services/diagnostics/checks/configuration_check.py +306 -0
  536. claude_mpm/services/diagnostics/checks/filesystem_check.py +233 -0
  537. claude_mpm/services/diagnostics/checks/installation_check.py +520 -0
  538. claude_mpm/services/diagnostics/checks/instructions_check.py +415 -0
  539. claude_mpm/services/diagnostics/checks/mcp_check.py +330 -0
  540. claude_mpm/services/diagnostics/checks/mcp_services_check.py +1058 -0
  541. claude_mpm/services/diagnostics/checks/monitor_check.py +281 -0
  542. claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
  543. claude_mpm/services/diagnostics/checks/startup_log_check.py +319 -0
  544. claude_mpm/services/diagnostics/diagnostic_runner.py +286 -0
  545. claude_mpm/services/diagnostics/doctor_reporter.py +578 -0
  546. claude_mpm/services/diagnostics/models.py +138 -0
  547. claude_mpm/services/event_aggregator.py +582 -0
  548. claude_mpm/services/event_bus/__init__.py +18 -0
  549. claude_mpm/services/event_bus/config.py +186 -0
  550. claude_mpm/services/event_bus/direct_relay.py +312 -0
  551. claude_mpm/services/event_bus/event_bus.py +396 -0
  552. claude_mpm/services/event_bus/relay.py +326 -0
  553. claude_mpm/services/events/__init__.py +44 -0
  554. claude_mpm/services/events/consumers/__init__.py +18 -0
  555. claude_mpm/services/events/consumers/dead_letter.py +306 -0
  556. claude_mpm/services/events/consumers/logging.py +184 -0
  557. claude_mpm/services/events/consumers/metrics.py +241 -0
  558. claude_mpm/services/events/consumers/socketio.py +377 -0
  559. claude_mpm/services/events/core.py +480 -0
  560. claude_mpm/services/events/interfaces.py +214 -0
  561. claude_mpm/services/events/producers/__init__.py +14 -0
  562. claude_mpm/services/events/producers/hook.py +269 -0
  563. claude_mpm/services/events/producers/system.py +329 -0
  564. claude_mpm/services/exceptions.py +433 -353
  565. claude_mpm/services/framework_claude_md_generator/__init__.py +81 -80
  566. claude_mpm/services/framework_claude_md_generator/content_assembler.py +74 -67
  567. claude_mpm/services/framework_claude_md_generator/content_validator.py +66 -62
  568. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +82 -60
  569. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +36 -37
  570. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +41 -40
  571. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +15 -15
  572. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +5 -4
  573. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  574. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  575. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  576. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  577. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +5 -4
  578. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  579. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  580. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +26 -30
  581. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +6 -5
  582. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  583. claude_mpm/services/framework_claude_md_generator/version_manager.py +31 -30
  584. claude_mpm/services/git/__init__.py +21 -0
  585. claude_mpm/services/git/git_operations_service.py +579 -0
  586. claude_mpm/services/github/__init__.py +21 -0
  587. claude_mpm/services/github/github_cli_service.py +397 -0
  588. claude_mpm/services/hook_installer_service.py +506 -0
  589. claude_mpm/services/hook_service.py +159 -111
  590. claude_mpm/services/infrastructure/__init__.py +52 -0
  591. claude_mpm/services/infrastructure/context_preservation.py +569 -0
  592. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  593. claude_mpm/services/infrastructure/logging.py +209 -0
  594. claude_mpm/services/infrastructure/monitoring/__init__.py +39 -0
  595. claude_mpm/services/infrastructure/monitoring/aggregator.py +432 -0
  596. claude_mpm/services/infrastructure/monitoring/base.py +122 -0
  597. claude_mpm/services/infrastructure/monitoring/legacy.py +203 -0
  598. claude_mpm/services/infrastructure/monitoring/network.py +219 -0
  599. claude_mpm/services/infrastructure/monitoring/process.py +343 -0
  600. claude_mpm/services/infrastructure/monitoring/resources.py +244 -0
  601. claude_mpm/services/infrastructure/monitoring/service.py +368 -0
  602. claude_mpm/services/infrastructure/monitoring.py +71 -0
  603. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  604. claude_mpm/services/instructions/__init__.py +9 -0
  605. claude_mpm/services/instructions/instruction_cache_service.py +374 -0
  606. claude_mpm/services/local_ops/__init__.py +155 -0
  607. claude_mpm/services/local_ops/crash_detector.py +257 -0
  608. claude_mpm/services/local_ops/health_checks/__init__.py +26 -0
  609. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  610. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  611. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  612. claude_mpm/services/local_ops/health_manager.py +427 -0
  613. claude_mpm/services/local_ops/log_monitor.py +396 -0
  614. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  615. claude_mpm/services/local_ops/process_manager.py +595 -0
  616. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  617. claude_mpm/services/local_ops/restart_manager.py +401 -0
  618. claude_mpm/services/local_ops/restart_policy.py +387 -0
  619. claude_mpm/services/local_ops/state_manager.py +372 -0
  620. claude_mpm/services/local_ops/unified_manager.py +600 -0
  621. claude_mpm/services/mcp_config_manager.py +1542 -0
  622. claude_mpm/services/mcp_service_verifier.py +732 -0
  623. claude_mpm/services/memory/__init__.py +19 -0
  624. claude_mpm/services/{memory_builder.py → memory/builder.py} +465 -373
  625. claude_mpm/services/memory/cache/__init__.py +14 -0
  626. claude_mpm/services/{shared_prompt_cache.py → memory/cache/shared_prompt_cache.py} +237 -200
  627. claude_mpm/services/memory/cache/simple_cache.py +331 -0
  628. claude_mpm/services/memory/failure_tracker.py +578 -0
  629. claude_mpm/services/memory/indexed_memory.py +648 -0
  630. claude_mpm/services/{memory_optimizer.py → memory/optimizer.py} +272 -243
  631. claude_mpm/services/memory/router.py +951 -0
  632. claude_mpm/services/memory_hook_service.py +470 -0
  633. claude_mpm/services/model/__init__.py +147 -0
  634. claude_mpm/services/model/base_provider.py +365 -0
  635. claude_mpm/services/model/claude_provider.py +412 -0
  636. claude_mpm/services/model/model_router.py +452 -0
  637. claude_mpm/services/model/ollama_provider.py +415 -0
  638. claude_mpm/services/monitor/__init__.py +20 -0
  639. claude_mpm/services/monitor/daemon.py +698 -0
  640. claude_mpm/services/monitor/daemon_manager.py +1076 -0
  641. claude_mpm/services/monitor/event_emitter.py +350 -0
  642. claude_mpm/services/monitor/handlers/__init__.py +21 -0
  643. claude_mpm/services/monitor/handlers/code_analysis.py +332 -0
  644. claude_mpm/services/monitor/handlers/dashboard.py +299 -0
  645. claude_mpm/services/monitor/handlers/file.py +264 -0
  646. claude_mpm/services/monitor/handlers/hooks.py +512 -0
  647. claude_mpm/services/monitor/management/__init__.py +18 -0
  648. claude_mpm/services/monitor/management/health.py +124 -0
  649. claude_mpm/services/monitor/management/lifecycle.py +730 -0
  650. claude_mpm/services/monitor/server.py +1493 -0
  651. claude_mpm/services/monitor_build_service.py +349 -0
  652. claude_mpm/services/native_agent_converter.py +356 -0
  653. claude_mpm/services/orphan_detection.py +786 -0
  654. claude_mpm/services/pm_skills_deployer.py +711 -0
  655. claude_mpm/services/port_manager.py +597 -0
  656. claude_mpm/services/pr/__init__.py +14 -0
  657. claude_mpm/services/pr/pr_template_service.py +329 -0
  658. claude_mpm/services/profile_manager.py +337 -0
  659. claude_mpm/services/project/__init__.py +44 -0
  660. claude_mpm/services/{project_analyzer.py → project/analyzer.py} +541 -291
  661. claude_mpm/services/project/analyzer_v2.py +566 -0
  662. claude_mpm/services/project/architecture_analyzer.py +461 -0
  663. claude_mpm/services/project/archive_manager.py +1045 -0
  664. claude_mpm/services/project/dependency_analyzer.py +462 -0
  665. claude_mpm/services/project/detection_strategies.py +719 -0
  666. claude_mpm/services/project/documentation_manager.py +554 -0
  667. claude_mpm/services/project/enhanced_analyzer.py +572 -0
  668. claude_mpm/services/project/language_analyzer.py +265 -0
  669. claude_mpm/services/project/metrics_collector.py +407 -0
  670. claude_mpm/services/project/project_organizer.py +1009 -0
  671. claude_mpm/services/project/registry.py +636 -0
  672. claude_mpm/services/project/toolchain_analyzer.py +583 -0
  673. claude_mpm/services/project_port_allocator.py +596 -0
  674. claude_mpm/services/recovery_manager.py +293 -240
  675. claude_mpm/services/response_tracker.py +267 -0
  676. claude_mpm/services/runner_configuration_service.py +605 -0
  677. claude_mpm/services/self_upgrade_service.py +608 -0
  678. claude_mpm/services/session_management_service.py +314 -0
  679. claude_mpm/services/session_manager.py +380 -0
  680. claude_mpm/services/shared/__init__.py +21 -0
  681. claude_mpm/services/shared/async_service_base.py +216 -0
  682. claude_mpm/services/shared/config_service_base.py +301 -0
  683. claude_mpm/services/shared/lifecycle_service_base.py +308 -0
  684. claude_mpm/services/shared/manager_base.py +315 -0
  685. claude_mpm/services/shared/service_factory.py +309 -0
  686. claude_mpm/services/skills/__init__.py +21 -0
  687. claude_mpm/services/skills/git_skill_source_manager.py +1340 -0
  688. claude_mpm/services/skills/selective_skill_deployer.py +743 -0
  689. claude_mpm/services/skills/skill_discovery_service.py +568 -0
  690. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  691. claude_mpm/services/skills_config.py +547 -0
  692. claude_mpm/services/skills_deployer.py +1168 -0
  693. claude_mpm/services/socketio/__init__.py +25 -0
  694. claude_mpm/services/socketio/client_proxy.py +229 -0
  695. claude_mpm/services/socketio/dashboard_server.py +362 -0
  696. claude_mpm/services/socketio/event_normalizer.py +798 -0
  697. claude_mpm/services/socketio/handlers/__init__.py +30 -0
  698. claude_mpm/services/socketio/handlers/base.py +136 -0
  699. claude_mpm/services/socketio/handlers/code_analysis.py +682 -0
  700. claude_mpm/services/socketio/handlers/connection.py +643 -0
  701. claude_mpm/services/socketio/handlers/connection_handler.py +333 -0
  702. claude_mpm/services/socketio/handlers/file.py +263 -0
  703. claude_mpm/services/socketio/handlers/git.py +962 -0
  704. claude_mpm/services/socketio/handlers/hook.py +211 -0
  705. claude_mpm/services/socketio/handlers/memory.py +26 -0
  706. claude_mpm/services/socketio/handlers/project.py +24 -0
  707. claude_mpm/services/socketio/handlers/registry.py +214 -0
  708. claude_mpm/services/socketio/migration_utils.py +343 -0
  709. claude_mpm/services/socketio/monitor_client.py +364 -0
  710. claude_mpm/services/socketio/server/__init__.py +18 -0
  711. claude_mpm/services/socketio/server/broadcaster.py +569 -0
  712. claude_mpm/services/socketio/server/connection_manager.py +579 -0
  713. claude_mpm/services/socketio/server/core.py +1079 -0
  714. claude_mpm/services/socketio/server/eventbus_integration.py +245 -0
  715. claude_mpm/services/socketio/server/main.py +501 -0
  716. claude_mpm/services/socketio_client_manager.py +173 -143
  717. claude_mpm/services/socketio_server.py +38 -1657
  718. claude_mpm/services/subprocess_launcher_service.py +322 -0
  719. claude_mpm/services/system_instructions_service.py +270 -0
  720. claude_mpm/services/ticket_manager.py +25 -209
  721. claude_mpm/services/ticket_services/__init__.py +26 -0
  722. claude_mpm/services/ticket_services/crud_service.py +328 -0
  723. claude_mpm/services/ticket_services/formatter_service.py +290 -0
  724. claude_mpm/services/ticket_services/search_service.py +324 -0
  725. claude_mpm/services/ticket_services/validation_service.py +303 -0
  726. claude_mpm/services/ticket_services/workflow_service.py +244 -0
  727. claude_mpm/services/unified/__init__.py +65 -0
  728. claude_mpm/services/unified/analyzer_strategies/__init__.py +44 -0
  729. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +518 -0
  730. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +680 -0
  731. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +900 -0
  732. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +745 -0
  733. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +733 -0
  734. claude_mpm/services/unified/config_strategies/__init__.py +175 -0
  735. claude_mpm/services/unified/config_strategies/config_schema.py +731 -0
  736. claude_mpm/services/unified/config_strategies/context_strategy.py +747 -0
  737. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1005 -0
  738. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +881 -0
  739. claude_mpm/services/unified/config_strategies/unified_config_service.py +823 -0
  740. claude_mpm/services/unified/config_strategies/validation_strategy.py +1148 -0
  741. claude_mpm/services/unified/deployment_strategies/__init__.py +97 -0
  742. claude_mpm/services/unified/deployment_strategies/base.py +553 -0
  743. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +573 -0
  744. claude_mpm/services/unified/deployment_strategies/local.py +607 -0
  745. claude_mpm/services/unified/deployment_strategies/utils.py +667 -0
  746. claude_mpm/services/unified/deployment_strategies/vercel.py +471 -0
  747. claude_mpm/services/unified/interfaces.py +475 -0
  748. claude_mpm/services/unified/migration.py +509 -0
  749. claude_mpm/services/unified/strategies.py +534 -0
  750. claude_mpm/services/unified/unified_analyzer.py +542 -0
  751. claude_mpm/services/unified/unified_config.py +691 -0
  752. claude_mpm/services/unified/unified_deployment.py +466 -0
  753. claude_mpm/services/utility_service.py +280 -0
  754. claude_mpm/services/version_control/__init__.py +34 -37
  755. claude_mpm/services/version_control/branch_strategy.py +26 -17
  756. claude_mpm/services/version_control/conflict_resolution.py +52 -36
  757. claude_mpm/services/version_control/git_operations.py +183 -49
  758. claude_mpm/services/version_control/semantic_versioning.py +172 -61
  759. claude_mpm/services/version_control/version_parser.py +546 -0
  760. claude_mpm/services/version_service.py +379 -0
  761. claude_mpm/services/visualization/__init__.py +15 -0
  762. claude_mpm/services/visualization/mermaid_generator.py +937 -0
  763. claude_mpm/skills/__init__.py +42 -0
  764. claude_mpm/skills/agent_skills_injector.py +324 -0
  765. claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
  766. claude_mpm/skills/bundled/__init__.py +6 -0
  767. claude_mpm/skills/bundled/api-documentation.md +393 -0
  768. claude_mpm/skills/bundled/async-testing.md +571 -0
  769. claude_mpm/skills/bundled/code-review.md +143 -0
  770. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  771. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  772. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  773. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  774. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  775. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  776. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  777. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  778. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  779. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  780. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  781. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  782. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  783. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  784. claude_mpm/skills/bundled/database-migration.md +199 -0
  785. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  786. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  787. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  788. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  789. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  790. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  791. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  792. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  793. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  794. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  795. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  796. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  797. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  798. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  799. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  800. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  801. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  802. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  803. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  804. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  805. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  806. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  807. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  808. claude_mpm/skills/bundled/git-workflow.md +414 -0
  809. claude_mpm/skills/bundled/imagemagick.md +204 -0
  810. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  811. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  812. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  813. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  814. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  815. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  816. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  817. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  818. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  819. claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
  820. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  821. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  822. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  823. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  824. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  825. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  826. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  827. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  828. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  829. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  830. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  831. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  832. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  833. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  834. claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
  835. claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
  836. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  837. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  838. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  839. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  840. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  841. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  842. claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
  843. claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
  844. claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -0
  845. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  846. claude_mpm/skills/bundled/pdf.md +141 -0
  847. claude_mpm/skills/bundled/performance-profiling.md +573 -0
  848. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  849. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  850. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  851. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  852. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  853. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  854. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  855. claude_mpm/skills/bundled/pm/pm-bug-reporting/pm-bug-reporting.md +248 -0
  856. claude_mpm/skills/bundled/pm/pm-delegation-patterns/SKILL.md +167 -0
  857. claude_mpm/skills/bundled/pm/pm-git-file-tracking/SKILL.md +113 -0
  858. claude_mpm/skills/bundled/pm/pm-pr-workflow/SKILL.md +124 -0
  859. claude_mpm/skills/bundled/pm/pm-teaching-mode/SKILL.md +657 -0
  860. claude_mpm/skills/bundled/pm/pm-ticketing-integration/SKILL.md +154 -0
  861. claude_mpm/skills/bundled/pm/pm-verification-protocols/SKILL.md +198 -0
  862. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  863. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  864. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  865. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  866. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  867. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  868. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  869. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  870. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  871. claude_mpm/skills/bundled/security-scanning.md +439 -0
  872. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  873. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  874. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  875. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  876. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  877. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  878. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  879. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  880. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  881. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  882. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  883. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  884. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  885. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  886. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  887. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  888. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  889. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  890. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  891. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  892. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  893. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  894. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  895. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  896. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  897. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  898. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  899. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  900. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  901. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  902. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  903. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  904. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  905. claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
  906. claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
  907. claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
  908. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  909. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  910. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
  911. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  912. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  913. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  914. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  915. claude_mpm/skills/bundled/xlsx.md +157 -0
  916. claude_mpm/skills/registry.py +286 -0
  917. claude_mpm/skills/skill_manager.py +405 -0
  918. claude_mpm/skills/skills_registry.py +347 -0
  919. claude_mpm/skills/skills_service.py +739 -0
  920. claude_mpm/storage/__init__.py +9 -0
  921. claude_mpm/storage/state_storage.py +546 -0
  922. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  923. claude_mpm/templates/questions/__init__.py +38 -0
  924. claude_mpm/templates/questions/base.py +193 -0
  925. claude_mpm/templates/questions/pr_strategy.py +311 -0
  926. claude_mpm/templates/questions/project_init.py +385 -0
  927. claude_mpm/templates/questions/ticket_mgmt.py +394 -0
  928. claude_mpm/ticket_wrapper.py +2 -2
  929. claude_mpm/tools/__init__.py +10 -0
  930. claude_mpm/tools/__main__.py +208 -0
  931. claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
  932. claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
  933. claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
  934. claude_mpm/tools/code_tree_analyzer/core.py +380 -0
  935. claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
  936. claude_mpm/tools/code_tree_analyzer/events.py +168 -0
  937. claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
  938. claude_mpm/tools/code_tree_analyzer/models.py +39 -0
  939. claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
  940. claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
  941. claude_mpm/tools/code_tree_builder.py +631 -0
  942. claude_mpm/tools/code_tree_events.py +420 -0
  943. claude_mpm/tools/socketio_debug.py +671 -0
  944. claude_mpm/utils/__init__.py +8 -8
  945. claude_mpm/utils/agent_dependency_loader.py +1189 -0
  946. claude_mpm/utils/agent_filters.py +261 -0
  947. claude_mpm/utils/common.py +544 -0
  948. claude_mpm/utils/config_manager.py +168 -126
  949. claude_mpm/utils/console.py +11 -0
  950. claude_mpm/utils/database_connector.py +298 -0
  951. claude_mpm/utils/dependency_cache.py +373 -0
  952. claude_mpm/utils/dependency_manager.py +60 -59
  953. claude_mpm/utils/dependency_strategies.py +381 -0
  954. claude_mpm/utils/display_helper.py +260 -0
  955. claude_mpm/utils/environment_context.py +313 -0
  956. claude_mpm/utils/error_handler.py +78 -66
  957. claude_mpm/utils/file_utils.py +305 -0
  958. claude_mpm/utils/framework_detection.py +12 -11
  959. claude_mpm/utils/git_analyzer.py +407 -0
  960. claude_mpm/utils/gitignore.py +244 -0
  961. claude_mpm/utils/import_migration_example.py +12 -60
  962. claude_mpm/utils/imports.py +48 -45
  963. claude_mpm/utils/log_cleanup.py +627 -0
  964. claude_mpm/utils/migration.py +372 -0
  965. claude_mpm/utils/path_operations.py +110 -104
  966. claude_mpm/utils/progress.py +387 -0
  967. claude_mpm/utils/robust_installer.py +844 -0
  968. claude_mpm/utils/session_logging.py +121 -0
  969. claude_mpm/utils/structured_questions.py +619 -0
  970. claude_mpm/utils/subprocess_utils.py +343 -0
  971. claude_mpm/validation/__init__.py +1 -1
  972. claude_mpm/validation/agent_validator.py +214 -108
  973. claude_mpm/validation/frontmatter_validator.py +252 -0
  974. claude_mpm-5.4.85.dist-info/METADATA +1023 -0
  975. claude_mpm-5.4.85.dist-info/RECORD +980 -0
  976. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.85.dist-info}/entry_points.txt +1 -3
  977. claude_mpm-5.4.85.dist-info/licenses/LICENSE +94 -0
  978. claude_mpm-5.4.85.dist-info/licenses/LICENSE-FAQ.md +153 -0
  979. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -88
  980. claude_mpm/agents/INSTRUCTIONS.md +0 -352
  981. claude_mpm/agents/backups/INSTRUCTIONS.md +0 -352
  982. claude_mpm/agents/base_agent_loader.py +0 -529
  983. claude_mpm/agents/schema/agent_schema.json +0 -314
  984. claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -36
  985. claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +0 -46
  986. claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +0 -45
  987. claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +0 -49
  988. claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +0 -46
  989. claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +0 -45
  990. claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +0 -49
  991. claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +0 -46
  992. claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +0 -46
  993. claude_mpm/agents/templates/data_engineer.json +0 -110
  994. claude_mpm/agents/templates/documentation.json +0 -109
  995. claude_mpm/agents/templates/engineer.json +0 -113
  996. claude_mpm/agents/templates/ops.json +0 -109
  997. claude_mpm/agents/templates/pm.json +0 -25
  998. claude_mpm/agents/templates/qa.json +0 -111
  999. claude_mpm/agents/templates/research.json +0 -65
  1000. claude_mpm/agents/templates/security.json +0 -113
  1001. claude_mpm/agents/templates/test_integration.json +0 -112
  1002. claude_mpm/agents/templates/version_control.json +0 -107
  1003. claude_mpm/cli/commands/ui.py +0 -57
  1004. claude_mpm/core/simple_runner.py +0 -1046
  1005. claude_mpm/dashboard/open_dashboard.py +0 -34
  1006. claude_mpm/deployment_paths.py +0 -261
  1007. claude_mpm/hooks/builtin/__init__.py +0 -1
  1008. claude_mpm/hooks/builtin/logging_hook_example.py +0 -165
  1009. claude_mpm/hooks/builtin/memory_hooks_example.py +0 -67
  1010. claude_mpm/hooks/builtin/mpm_command_hook.py +0 -125
  1011. claude_mpm/hooks/builtin/post_delegation_hook_example.py +0 -124
  1012. claude_mpm/hooks/builtin/pre_delegation_hook_example.py +0 -125
  1013. claude_mpm/hooks/builtin/submit_hook_example.py +0 -100
  1014. claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +0 -237
  1015. claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +0 -240
  1016. claude_mpm/hooks/builtin/workflow_start_hook.py +0 -181
  1017. claude_mpm/orchestration/__init__.py +0 -6
  1018. claude_mpm/orchestration/archive/direct_orchestrator.py +0 -195
  1019. claude_mpm/orchestration/archive/factory.py +0 -215
  1020. claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +0 -188
  1021. claude_mpm/orchestration/archive/hook_integration_example.py +0 -178
  1022. claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +0 -826
  1023. claude_mpm/orchestration/archive/orchestrator.py +0 -501
  1024. claude_mpm/orchestration/archive/pexpect_orchestrator.py +0 -252
  1025. claude_mpm/orchestration/archive/pty_orchestrator.py +0 -270
  1026. claude_mpm/orchestration/archive/simple_orchestrator.py +0 -82
  1027. claude_mpm/orchestration/archive/subprocess_orchestrator.py +0 -801
  1028. claude_mpm/orchestration/archive/system_prompt_orchestrator.py +0 -278
  1029. claude_mpm/orchestration/archive/wrapper_orchestrator.py +0 -187
  1030. claude_mpm/schemas/workflow_validator.py +0 -411
  1031. claude_mpm/services/agent_deployment.py +0 -1534
  1032. claude_mpm/services/agent_lifecycle_manager.py +0 -1169
  1033. claude_mpm/services/agent_memory_manager.py +0 -1415
  1034. claude_mpm/services/agent_registry.py +0 -676
  1035. claude_mpm/services/deployed_agent_discovery.py +0 -226
  1036. claude_mpm/services/framework_agent_loader.py +0 -337
  1037. claude_mpm/services/framework_claude_md_generator.py +0 -621
  1038. claude_mpm/services/health_monitor.py +0 -892
  1039. claude_mpm/services/memory_router.py +0 -538
  1040. claude_mpm/services/parent_directory_manager/__init__.py +0 -577
  1041. claude_mpm/services/parent_directory_manager/backup_manager.py +0 -258
  1042. claude_mpm/services/parent_directory_manager/config_manager.py +0 -210
  1043. claude_mpm/services/parent_directory_manager/deduplication_manager.py +0 -279
  1044. claude_mpm/services/parent_directory_manager/framework_protector.py +0 -143
  1045. claude_mpm/services/parent_directory_manager/operations.py +0 -186
  1046. claude_mpm/services/parent_directory_manager/state_manager.py +0 -624
  1047. claude_mpm/services/parent_directory_manager/template_deployer.py +0 -579
  1048. claude_mpm/services/parent_directory_manager/validation_manager.py +0 -378
  1049. claude_mpm/services/parent_directory_manager/version_control_helper.py +0 -339
  1050. claude_mpm/services/parent_directory_manager/version_manager.py +0 -222
  1051. claude_mpm/services/standalone_socketio_server.py +0 -1300
  1052. claude_mpm/services/ticket_manager_di.py +0 -318
  1053. claude_mpm/services/ticketing_service_original.py +0 -508
  1054. claude_mpm/ui/__init__.py +0 -1
  1055. claude_mpm/ui/rich_terminal_ui.py +0 -295
  1056. claude_mpm/ui/terminal_ui.py +0 -328
  1057. claude_mpm/utils/paths.py +0 -289
  1058. claude_mpm-3.4.10.dist-info/METADATA +0 -183
  1059. claude_mpm-3.4.10.dist-info/RECORD +0 -201
  1060. claude_mpm-3.4.10.dist-info/licenses/LICENSE +0 -21
  1061. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.85.dist-info}/WHEEL +0 -0
  1062. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.85.dist-info}/top_level.txt +0 -0
@@ -1,932 +1,709 @@
1
1
  #!/usr/bin/env python3
2
- """Optimized Claude Code hook handler with Socket.IO connection pooling.
2
+ """Refactored Claude Code hook handler with modular service architecture.
3
3
 
4
- This handler now uses a connection pool for Socket.IO clients to reduce
5
- connection overhead and implement circuit breaker and batching patterns.
4
+ This handler uses a service-oriented architecture with:
5
+ - StateManagerService: Manages state and delegation tracking
6
+ - ConnectionManagerService: Handles SocketIO connections with HTTP fallback
7
+ - SubagentResponseProcessor: Processes complex subagent responses
8
+ - DuplicateEventDetector: Detects and filters duplicate events
6
9
 
7
- WHY connection pooling approach:
8
- - Reduces connection setup/teardown overhead by 80%
9
- - Implements circuit breaker for resilience during outages
10
- - Provides micro-batching for high-frequency events
11
- - Maintains persistent connections for better performance
12
- - Falls back gracefully when Socket.IO unavailable
10
+ WHY service-oriented approach:
11
+ - Better separation of concerns and modularity
12
+ - Easier testing and maintenance
13
+ - Reduced file size from 1040 to ~400 lines
14
+ - Clear service boundaries and responsibilities
15
+
16
+ NOTE: Requires Claude Code version 1.0.92 or higher for proper hook support.
17
+ Earlier versions do not support matcher-based hook configuration.
13
18
  """
14
19
 
15
20
  import json
16
- import sys
17
21
  import os
22
+ import re
23
+ import select
24
+ import signal
18
25
  import subprocess
19
- from datetime import datetime
20
- from pathlib import Path
21
- from collections import deque
22
-
23
- # Quick environment check - must be defined before any code that might use it
24
- DEBUG = os.environ.get('CLAUDE_MPM_HOOK_DEBUG', '').lower() == 'true'
26
+ import sys
27
+ import threading
28
+ from datetime import datetime, timezone
29
+ from typing import Optional, Tuple
25
30
 
26
- # Add imports for memory hook integration with comprehensive error handling
27
- MEMORY_HOOKS_AVAILABLE = False
31
+ # Import extracted modules with fallback for direct execution
28
32
  try:
29
- # Try to add src to path if not already there (fallback for missing PYTHONPATH)
30
- import sys
33
+ # Try relative imports first (when imported as module)
34
+ from .event_handlers import EventHandlers
35
+ from .memory_integration import MemoryHookManager
36
+ from .response_tracking import ResponseTrackingManager
37
+ from .services import (
38
+ ConnectionManagerService,
39
+ DuplicateEventDetector,
40
+ StateManagerService,
41
+ SubagentResponseProcessor,
42
+ )
43
+ except ImportError:
44
+ # Fall back to absolute imports (when run directly)
31
45
  from pathlib import Path
32
- src_path = Path(__file__).parent.parent.parent.parent
33
- if src_path.exists() and str(src_path) not in sys.path:
34
- sys.path.insert(0, str(src_path))
35
-
36
- from claude_mpm.services.hook_service import HookService
37
- from claude_mpm.hooks.memory_integration_hook import (
38
- MemoryPreDelegationHook,
39
- MemoryPostDelegationHook
46
+
47
+ # Add parent directory to path
48
+ sys.path.insert(0, str(Path(__file__).parent))
49
+
50
+ from event_handlers import EventHandlers
51
+ from memory_integration import MemoryHookManager
52
+ from response_tracking import ResponseTrackingManager
53
+ from services import (
54
+ ConnectionManagerService,
55
+ DuplicateEventDetector,
56
+ StateManagerService,
57
+ SubagentResponseProcessor,
40
58
  )
41
- from claude_mpm.hooks.base_hook import HookContext, HookType
42
- from claude_mpm.core.config import Config
43
- MEMORY_HOOKS_AVAILABLE = True
44
- except Exception as e:
45
- # Catch all exceptions to prevent any import errors from breaking the handler
46
- if DEBUG:
47
- print(f"Memory hooks not available: {e}", file=sys.stderr)
48
- MEMORY_HOOKS_AVAILABLE = False
49
-
50
- # Socket.IO import
59
+
60
+ """
61
+ Debug mode configuration for hook processing.
62
+
63
+ WHY enabled by default: Hook processing can be complex and hard to debug.
64
+ Having debug output available by default helps diagnose issues during development.
65
+ Production deployments can disable via environment variable.
66
+
67
+ Performance Impact: Debug logging adds ~5-10% overhead but provides crucial
68
+ visibility into event flow, timing, and error conditions.
69
+ """
70
+ DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "true").lower() != "false"
71
+
72
+ """
73
+ Conditional imports with graceful fallbacks for testing and modularity.
74
+
75
+ WHY conditional imports:
76
+ - Tests may not have full environment setup
77
+ - Allows hooks to work in minimal configurations
78
+ - Graceful degradation when dependencies unavailable
79
+ """
80
+
81
+ # Import get_connection_pool for backward compatibility with tests
51
82
  try:
52
- import socketio
53
- SOCKETIO_AVAILABLE = True
83
+ from claude_mpm.core.socketio_pool import get_connection_pool
54
84
  except ImportError:
55
- SOCKETIO_AVAILABLE = False
56
- socketio = None
85
+ get_connection_pool = None
86
+
87
+ """
88
+ Global singleton pattern for hook handler.
89
+
90
+ WHY singleton:
91
+ - Only one handler should process Claude Code events
92
+ - Maintains consistent state across all hook invocations
93
+ - Prevents duplicate event processing
94
+ - Thread-safe initialization with lock
95
+
96
+ GOTCHA: Must use get_global_handler() not direct access to avoid race conditions.
97
+ """
98
+ _global_handler = None
99
+ _handler_lock = threading.Lock()
100
+
101
+ """
102
+ Version compatibility checking.
103
+
104
+ WHY version checking:
105
+ - Claude Code hook support was added in v1.0.92
106
+ - Earlier versions don't support matcher-based configuration
107
+ - Prevents confusing errors with unsupported versions
108
+
109
+ Security: Version checking prevents execution on incompatible environments.
110
+ """
111
+ MIN_CLAUDE_VERSION = "1.0.92"
112
+
113
+
114
+ def check_claude_version() -> Tuple[bool, Optional[str]]:
115
+ """
116
+ Verify Claude Code version compatibility for hook support.
117
+
118
+ Executes 'claude --version' command to detect installed version and
119
+ compares against minimum required version for hook functionality.
120
+
121
+ Version Checking Logic:
122
+ 1. Execute 'claude --version' with timeout
123
+ 2. Parse version string using regex
124
+ 3. Compare against MIN_CLAUDE_VERSION (1.0.92)
125
+ 4. Return compatibility status and detected version
126
+
127
+ WHY this check is critical:
128
+ - Hook support was added in Claude Code v1.0.92
129
+ - Earlier versions don't understand matcher-based hooks
130
+ - Prevents cryptic errors from unsupported configurations
131
+ - Allows graceful fallback or user notification
132
+
133
+ Error Handling:
134
+ - Command timeout after 5 seconds
135
+ - Subprocess errors caught and logged
136
+ - Invalid version formats handled gracefully
137
+ - Returns (False, None) on any failure
138
+
139
+ Performance Notes:
140
+ - Subprocess call has ~100ms overhead
141
+ - Result should be cached by caller
142
+ - Only called during initialization
143
+
144
+ Returns:
145
+ Tuple[bool, Optional[str]]:
146
+ - bool: True if version is compatible
147
+ - str|None: Detected version string, None if detection failed
148
+
149
+ Examples:
150
+ >>> is_compatible, version = check_claude_version()
151
+ >>> if not is_compatible:
152
+ ... print(f"Claude Code {version or 'unknown'} is not supported")
153
+ """
154
+ try:
155
+ # Try to detect Claude Code version
156
+ result = subprocess.run(
157
+ ["claude", "--version"],
158
+ capture_output=True,
159
+ text=True,
160
+ timeout=5,
161
+ check=False,
162
+ )
163
+
164
+ if result.returncode == 0:
165
+ version_text = result.stdout.strip()
166
+ # Extract version number (e.g., "1.0.92 (Claude Code)" -> "1.0.92")
167
+ match = re.match(r"^([\d\.]+)", version_text)
168
+ if match:
169
+ version = match.group(1)
170
+
171
+ # Compare versions
172
+ def parse_version(v: str):
173
+ try:
174
+ return [int(x) for x in v.split(".")]
175
+ except (ValueError, AttributeError):
176
+ return [0]
177
+
178
+ current = parse_version(version)
179
+ required = parse_version(MIN_CLAUDE_VERSION)
180
+
181
+ # Check if current version meets minimum
182
+ for i in range(max(len(current), len(required))):
183
+ curr_part = current[i] if i < len(current) else 0
184
+ req_part = required[i] if i < len(required) else 0
185
+
186
+ if curr_part < req_part:
187
+ if DEBUG:
188
+ print(
189
+ f"⚠️ Claude Code {version} does not support matcher-based hooks "
190
+ f"(requires {MIN_CLAUDE_VERSION}+). Hook monitoring disabled.",
191
+ file=sys.stderr,
192
+ )
193
+ return False, version
194
+ if curr_part > req_part:
195
+ return True, version
196
+
197
+ return True, version
198
+ except Exception as e:
199
+ if DEBUG:
200
+ print(
201
+ f"Warning: Could not detect Claude Code version: {e}", file=sys.stderr
202
+ )
57
203
 
58
- # No fallback needed - we only use Socket.IO now
204
+ return False, None
59
205
 
60
206
 
61
207
  class ClaudeHookHandler:
62
- """Optimized hook handler with direct Socket.IO client.
63
-
64
- WHY direct client approach:
65
- - Simple and reliable synchronous operation
66
- - No complex threading or async issues
67
- - Fast connection reuse when possible
68
- - Graceful fallback when Socket.IO unavailable
208
+ """Refactored hook handler with service-oriented architecture.
209
+
210
+ WHY service-oriented approach:
211
+ - Modular design with clear service boundaries
212
+ - Each service handles a specific responsibility
213
+ - Easier to test, maintain, and extend
214
+ - Reduced complexity in main handler class
69
215
  """
70
-
216
+
71
217
  def __init__(self):
72
- # Socket.IO client (persistent if possible)
73
- self.sio_client = None
74
- self.sio_connected = False
75
-
76
- # Agent delegation tracking
77
- # Store recent Task delegations: session_id -> agent_type
78
- self.active_delegations = {}
79
- # Use deque to limit memory usage (keep last 100 delegations)
80
- self.delegation_history = deque(maxlen=100)
81
-
82
- # Git branch cache (to avoid repeated subprocess calls)
218
+ # Initialize services
219
+ self.state_manager = StateManagerService()
220
+ self.connection_manager = ConnectionManagerService()
221
+ self.duplicate_detector = DuplicateEventDetector()
222
+
223
+ # Initialize extracted managers
224
+ self.memory_hook_manager = MemoryHookManager()
225
+ self.response_tracking_manager = ResponseTrackingManager()
226
+ self.event_handlers = EventHandlers(self)
227
+
228
+ # Initialize subagent processor with dependencies
229
+ self.subagent_processor = SubagentResponseProcessor(
230
+ self.state_manager, self.response_tracking_manager, self.connection_manager
231
+ )
232
+
233
+ # Backward compatibility properties for tests
234
+ self.connection_pool = self.connection_manager.connection_pool
235
+
236
+ # Expose state manager properties for backward compatibility
237
+ self.active_delegations = self.state_manager.active_delegations
238
+ self.delegation_history = self.state_manager.delegation_history
239
+ self.delegation_requests = self.state_manager.delegation_requests
240
+ self.pending_prompts = self.state_manager.pending_prompts
241
+
242
+ # Initialize git branch cache (used by event_handlers)
83
243
  self._git_branch_cache = {}
84
244
  self._git_branch_cache_time = {}
85
-
86
- # Initialize memory hooks if available
87
- self.memory_hooks_initialized = False
88
- self.pre_delegation_hook = None
89
- self.post_delegation_hook = None
90
- if MEMORY_HOOKS_AVAILABLE:
91
- self._initialize_memory_hooks()
92
-
93
- # No fallback server needed - we only use Socket.IO now
94
-
95
- def _track_delegation(self, session_id: str, agent_type: str):
96
- """Track a new agent delegation."""
97
- if session_id and agent_type and agent_type != 'unknown':
98
- self.active_delegations[session_id] = agent_type
99
- key = f"{session_id}:{datetime.now().timestamp()}"
100
- self.delegation_history.append((key, agent_type))
101
-
102
- # Clean up old delegations (older than 5 minutes)
103
- cutoff_time = datetime.now().timestamp() - 300
104
- keys_to_remove = []
105
- for sid in list(self.active_delegations.keys()):
106
- # Check if this is an old entry by looking in history
107
- found_recent = False
108
- for hist_key, _ in reversed(self.delegation_history):
109
- if hist_key.startswith(sid):
110
- _, timestamp = hist_key.split(':', 1)
111
- if float(timestamp) > cutoff_time:
112
- found_recent = True
113
- break
114
- if not found_recent:
115
- keys_to_remove.append(sid)
116
-
117
- for key in keys_to_remove:
118
- del self.active_delegations[key]
119
-
120
- def _get_delegation_agent_type(self, session_id: str) -> str:
121
- """Get the agent type for a session's active delegation."""
122
- # First try exact session match
123
- if session_id and session_id in self.active_delegations:
124
- return self.active_delegations[session_id]
125
-
126
- # Then try to find in recent history
127
- if session_id:
128
- for key, agent_type in reversed(self.delegation_history):
129
- if key.startswith(session_id):
130
- return agent_type
131
-
132
- return 'unknown'
133
-
134
- def _initialize_memory_hooks(self):
135
- """Initialize memory hooks for automatic agent memory management.
136
-
137
- WHY: This activates the memory system by connecting Claude Code hook events
138
- to our memory integration hooks. This enables automatic memory injection
139
- before delegations and learning extraction after delegations.
140
-
141
- DESIGN DECISION: We initialize hooks here in the Claude hook handler because
142
- this is where Claude Code events are processed. This ensures memory hooks
143
- are triggered at the right times during agent delegation.
245
+
246
+ def handle(self):
247
+ """Process hook event with minimal overhead and timeout protection.
248
+
249
+ WHY this approach:
250
+ - Fast path processing for minimal latency (no blocking waits)
251
+ - Non-blocking Socket.IO connection and event emission
252
+ - Timeout protection prevents indefinite hangs
253
+ - Connection timeout prevents indefinite hangs
254
+ - Graceful degradation if Socket.IO unavailable
255
+ - Always continues regardless of event status
256
+ - Process exits after handling to prevent accumulation
144
257
  """
258
+ _continue_sent = False # Track if continue has been sent
259
+
260
+ def timeout_handler(signum, frame):
261
+ """Handle timeout by forcing exit."""
262
+ nonlocal _continue_sent
263
+ if DEBUG:
264
+ print(f"Hook handler timeout (pid: {os.getpid()})", file=sys.stderr)
265
+ if not _continue_sent:
266
+ self._continue_execution()
267
+ _continue_sent = True
268
+ sys.exit(0)
269
+
145
270
  try:
146
- # Create configuration
147
- config = Config()
148
-
149
- # Only initialize if memory system is enabled
150
- if not config.get('memory.enabled', True):
271
+ # Set a 10-second timeout for the entire operation
272
+ signal.signal(signal.SIGALRM, timeout_handler)
273
+ signal.alarm(10)
274
+
275
+ # Read and parse event
276
+ event = self._read_hook_event()
277
+ if not event:
278
+ if not _continue_sent:
279
+ self._continue_execution()
280
+ _continue_sent = True
281
+ return
282
+
283
+ # Check for duplicate events (same event within 100ms)
284
+ if self.duplicate_detector.is_duplicate(event):
151
285
  if DEBUG:
152
- print("Memory system disabled - skipping hook initialization", file=sys.stderr)
286
+ print(
287
+ f"[{datetime.now(timezone.utc).isoformat()}] Skipping duplicate event: {event.get('hook_event_name', 'unknown')} (PID: {os.getpid()})",
288
+ file=sys.stderr,
289
+ )
290
+ # Still need to output continue for this invocation
291
+ if not _continue_sent:
292
+ self._continue_execution()
293
+ _continue_sent = True
153
294
  return
154
-
155
- # Initialize pre-delegation hook for memory injection
156
- self.pre_delegation_hook = MemoryPreDelegationHook(config)
157
-
158
- # Initialize post-delegation hook if auto-learning is enabled
159
- if config.get('memory.auto_learning', True): # Default to True now
160
- self.post_delegation_hook = MemoryPostDelegationHook(config)
161
-
162
- self.memory_hooks_initialized = True
163
-
164
- if DEBUG:
165
- hooks_info = []
166
- if self.pre_delegation_hook:
167
- hooks_info.append("pre-delegation")
168
- if self.post_delegation_hook:
169
- hooks_info.append("post-delegation")
170
- print(f"✅ Memory hooks initialized: {', '.join(hooks_info)}", file=sys.stderr)
171
-
172
- except Exception as e:
295
+
296
+ # Debug: Log that we're processing an event
173
297
  if DEBUG:
174
- print(f"❌ Failed to initialize memory hooks: {e}", file=sys.stderr)
175
- # Don't fail the entire handler - memory system is optional
176
-
177
- def _get_git_branch(self, working_dir: str = None) -> str:
178
- """Get git branch for the given directory with caching.
179
-
180
- WHY caching approach:
181
- - Avoids repeated subprocess calls which are expensive
182
- - Caches results for 30 seconds per directory
183
- - Falls back gracefully if git command fails
184
- - Returns 'Unknown' for non-git directories
298
+ hook_type = event.get("hook_event_name", "unknown")
299
+ print(
300
+ f"\n[{datetime.now(timezone.utc).isoformat()}] Processing hook event: {hook_type} (PID: {os.getpid()})",
301
+ file=sys.stderr,
302
+ )
303
+
304
+ # Perform periodic cleanup if needed
305
+ if self.state_manager.increment_events_processed():
306
+ self.state_manager.cleanup_old_entries()
307
+ # Also cleanup old correlation files
308
+ from .correlation_manager import CorrelationManager
309
+
310
+ CorrelationManager.cleanup_old()
311
+ if DEBUG:
312
+ print(
313
+ f"🧹 Performed cleanup after {self.state_manager.events_processed} events",
314
+ file=sys.stderr,
315
+ )
316
+
317
+ # Route event to appropriate handler
318
+ # Handlers can optionally return modified input for PreToolUse events
319
+ modified_input = self._route_event(event)
320
+
321
+ # Always continue execution (only if not already sent)
322
+ if not _continue_sent:
323
+ self._continue_execution(modified_input)
324
+ _continue_sent = True
325
+
326
+ except Exception:
327
+ # Fail fast and silent (only send continue if not already sent)
328
+ if not _continue_sent:
329
+ self._continue_execution()
330
+ _continue_sent = True
331
+ finally:
332
+ # Cancel the alarm
333
+ signal.alarm(0)
334
+
335
+ def _read_hook_event(self) -> dict:
185
336
  """
186
- # Use current working directory if not specified
187
- if not working_dir:
188
- working_dir = os.getcwd()
189
-
190
- # Check cache first (cache for 30 seconds)
191
- current_time = datetime.now().timestamp()
192
- cache_key = working_dir
193
-
194
- if (cache_key in self._git_branch_cache
195
- and cache_key in self._git_branch_cache_time
196
- and current_time - self._git_branch_cache_time[cache_key] < 30):
197
- return self._git_branch_cache[cache_key]
198
-
199
- # Try to get git branch
200
- try:
201
- # Change to the working directory temporarily
202
- original_cwd = os.getcwd()
203
- os.chdir(working_dir)
204
-
205
- # Run git command to get current branch
206
- result = subprocess.run(
207
- ['git', 'branch', '--show-current'],
208
- capture_output=True,
209
- text=True,
210
- timeout=2 # Quick timeout to avoid hanging
211
- )
212
-
213
- # Restore original directory
214
- os.chdir(original_cwd)
215
-
216
- if result.returncode == 0 and result.stdout.strip():
217
- branch = result.stdout.strip()
218
- # Cache the result
219
- self._git_branch_cache[cache_key] = branch
220
- self._git_branch_cache_time[cache_key] = current_time
221
- return branch
222
- else:
223
- # Not a git repository or no branch
224
- self._git_branch_cache[cache_key] = 'Unknown'
225
- self._git_branch_cache_time[cache_key] = current_time
226
- return 'Unknown'
227
-
228
- except (subprocess.TimeoutExpired, subprocess.CalledProcessError, FileNotFoundError, OSError):
229
- # Git not available or command failed
230
- self._git_branch_cache[cache_key] = 'Unknown'
231
- self._git_branch_cache_time[cache_key] = current_time
232
- return 'Unknown'
233
-
234
- def _get_socketio_client(self):
235
- """Get or create Socket.IO client.
236
-
237
- WHY this approach:
238
- - Reuses existing connection when possible
239
- - Creates new connection only when needed
240
- - Handles connection failures gracefully
337
+ Read and parse hook event from stdin with timeout.
338
+
339
+ WHY: Centralized event reading with error handling and timeout
340
+ ensures consistent parsing and validation while preventing
341
+ processes from hanging indefinitely on stdin.read().
342
+
343
+ Returns:
344
+ Parsed event dictionary or None if invalid/timeout
241
345
  """
242
- if not SOCKETIO_AVAILABLE:
243
- return None
244
-
245
- # Check if we have a connected client
246
- if self.sio_client and self.sio_connected:
247
- try:
248
- # Test if still connected
249
- if self.sio_client.connected:
250
- return self.sio_client
251
- except:
252
- pass
253
-
254
- # Need to create new client
255
346
  try:
256
- port = int(os.environ.get('CLAUDE_MPM_SOCKETIO_PORT', '8765'))
257
- self.sio_client = socketio.Client(
258
- reconnection=False, # Don't auto-reconnect in hooks
259
- logger=False,
260
- engineio_logger=False
261
- )
262
-
263
- # Try to connect with short timeout
264
- self.sio_client.connect(f'http://localhost:{port}', wait_timeout=1)
265
- self.sio_connected = True
266
-
347
+ # Check if data is available on stdin with 1 second timeout
348
+ if sys.stdin.isatty():
349
+ # Interactive terminal - no data expected
350
+ return None
351
+
352
+ ready, _, _ = select.select([sys.stdin], [], [], 1.0)
353
+ if not ready:
354
+ # No data available within timeout
355
+ if DEBUG:
356
+ print("No hook event data received within timeout", file=sys.stderr)
357
+ return None
358
+
359
+ # Data is available, read it
360
+ event_data = sys.stdin.read()
361
+ if not event_data.strip():
362
+ # Empty or whitespace-only data
363
+ return None
364
+
365
+ parsed = json.loads(event_data)
366
+ # Debug: Log the actual event format we receive
267
367
  if DEBUG:
268
- print(f"Hook handler: Connected to Socket.IO server on port {port}", file=sys.stderr)
269
-
270
- return self.sio_client
271
-
368
+ print(
369
+ f"Received event with keys: {list(parsed.keys())}", file=sys.stderr
370
+ )
371
+ for key in ["hook_event_name", "event", "type", "event_type"]:
372
+ if key in parsed:
373
+ print(f" {key} = '{parsed[key]}'", file=sys.stderr)
374
+ return parsed
375
+ except (json.JSONDecodeError, ValueError) as e:
376
+ if DEBUG:
377
+ print(f"Failed to parse hook event: {e}", file=sys.stderr)
378
+ return None
272
379
  except Exception as e:
273
380
  if DEBUG:
274
- print(f"Hook handler: Failed to connect to Socket.IO: {e}", file=sys.stderr)
275
- self.sio_client = None
276
- self.sio_connected = False
381
+ print(f"Error reading hook event: {e}", file=sys.stderr)
277
382
  return None
278
-
279
- def handle(self):
280
- """Process hook event with minimal overhead and zero blocking delays.
281
-
282
- WHY this approach:
283
- - Fast path processing for minimal latency (no blocking waits)
284
- - Non-blocking Socket.IO connection and event emission
285
- - Removed sleep() delays that were adding 100ms+ to every hook
286
- - Connection timeout prevents indefinite hangs
287
- - Graceful degradation if Socket.IO unavailable
288
- - Always continues regardless of event status
383
+
384
+ def _route_event(self, event: dict) -> Optional[dict]:
289
385
  """
290
- try:
291
- # Read event
292
- event_data = sys.stdin.read()
293
- event = json.loads(event_data)
294
- hook_type = event.get('hook_event_name', 'unknown')
295
-
296
- # Fast path for common events
297
- if hook_type == 'UserPromptSubmit':
298
- self._handle_user_prompt_fast(event)
299
- elif hook_type == 'PreToolUse':
300
- self._handle_pre_tool_fast(event)
301
- elif hook_type == 'PostToolUse':
302
- self._handle_post_tool_fast(event)
303
- elif hook_type == 'Notification':
304
- self._handle_notification_fast(event)
305
- elif hook_type == 'Stop':
306
- self._handle_stop_fast(event)
307
- elif hook_type == 'SubagentStop':
308
- self._handle_subagent_stop_fast(event)
309
-
310
- # Socket.IO emit is non-blocking and will complete asynchronously
311
- # Removed sleep() to eliminate 100ms delay that was blocking Claude execution
312
-
313
- # Always continue
314
- print(json.dumps({"action": "continue"}))
315
-
316
- except:
317
- # Fail fast and silent
318
- print(json.dumps({"action": "continue"}))
319
-
320
- def _emit_socketio_event(self, namespace: str, event: str, data: dict):
321
- """Emit Socket.IO event using direct client.
322
-
323
- WHY direct client approach:
324
- - Simple synchronous emission
325
- - No threading complexity
326
- - Reliable delivery
327
- - Fast when connection is reused
386
+ Route event to appropriate handler based on type.
387
+
388
+ WHY: Centralized routing reduces complexity and makes
389
+ it easier to add new event types.
390
+
391
+ Args:
392
+ event: Hook event dictionary
393
+
394
+ Returns:
395
+ Modified input for PreToolUse events (v2.0.30+), None otherwise
328
396
  """
329
- # Fast path: Skip all Socket.IO operations unless configured
330
- if not os.environ.get('CLAUDE_MPM_SOCKETIO_PORT') and not DEBUG:
331
- return
332
-
333
- # Get Socket.IO client
334
- client = self._get_socketio_client()
335
- if client:
397
+ import time
398
+
399
+ # Try multiple field names for compatibility
400
+ hook_type = (
401
+ event.get("hook_event_name")
402
+ or event.get("event")
403
+ or event.get("type")
404
+ or event.get("event_type")
405
+ or event.get("hook_event_type")
406
+ or "unknown"
407
+ )
408
+
409
+ # Log the actual event structure for debugging
410
+ if DEBUG and hook_type == "unknown":
411
+ print(f"Unknown event format, keys: {list(event.keys())}", file=sys.stderr)
412
+ print(f"Event sample: {str(event)[:200]}", file=sys.stderr)
413
+
414
+ # Map event types to handlers
415
+ event_handlers = {
416
+ "UserPromptSubmit": self.event_handlers.handle_user_prompt_fast,
417
+ "PreToolUse": self.event_handlers.handle_pre_tool_fast,
418
+ "PostToolUse": self.event_handlers.handle_post_tool_fast,
419
+ "Notification": self.event_handlers.handle_notification_fast,
420
+ "Stop": self.event_handlers.handle_stop_fast,
421
+ "SubagentStop": self.event_handlers.handle_subagent_stop_fast,
422
+ "SubagentStart": self.event_handlers.handle_session_start_fast,
423
+ "SessionStart": self.event_handlers.handle_session_start_fast,
424
+ "AssistantResponse": self.event_handlers.handle_assistant_response,
425
+ }
426
+
427
+ # Call appropriate handler if exists
428
+ handler = event_handlers.get(hook_type)
429
+ if handler:
430
+ # Track execution timing for hook emission
431
+ start_time = time.time()
432
+ success = False
433
+ error_message = None
434
+ result = None
435
+
336
436
  try:
337
- # Format event for Socket.IO server
338
- claude_event_data = {
339
- 'type': f'hook.{event}',
340
- 'timestamp': datetime.now().isoformat(),
341
- 'data': data
342
- }
343
-
344
- # Emit synchronously
345
- client.emit('claude_event', claude_event_data)
346
-
347
- if DEBUG:
348
- print(f"Emitted Socket.IO event: hook.{event}", file=sys.stderr)
349
-
437
+ # Handlers can optionally return modified input
438
+ result = handler(event)
439
+ success = True
440
+ # Only PreToolUse handlers should return modified input
441
+ if hook_type == "PreToolUse" and result is not None:
442
+ return_value = result
443
+ else:
444
+ return_value = None
350
445
  except Exception as e:
446
+ error_message = str(e)
447
+ return_value = None
351
448
  if DEBUG:
352
- print(f"Socket.IO emit failed: {e}", file=sys.stderr)
353
- # Mark as disconnected so next call will reconnect
354
- self.sio_connected = False
355
-
356
- def _handle_user_prompt_fast(self, event):
357
- """Handle user prompt with comprehensive data capture.
358
-
359
- WHY enhanced data capture:
360
- - Provides full context for debugging and monitoring
361
- - Captures prompt text, working directory, and session context
362
- - Enables better filtering and analysis in dashboard
363
- """
364
- prompt = event.get('prompt', '')
365
-
366
- # Skip /mpm commands to reduce noise unless debug is enabled
367
- if prompt.startswith('/mpm') and not DEBUG:
368
- return
369
-
370
- # Get working directory and git branch
371
- working_dir = event.get('cwd', '')
372
- git_branch = self._get_git_branch(working_dir) if working_dir else 'Unknown'
373
-
374
- # Extract comprehensive prompt data
375
- prompt_data = {
376
- 'event_type': 'user_prompt',
377
- 'prompt_text': prompt,
378
- 'prompt_preview': prompt[:200] if len(prompt) > 200 else prompt,
379
- 'prompt_length': len(prompt),
380
- 'session_id': event.get('session_id', ''),
381
- 'working_directory': working_dir,
382
- 'git_branch': git_branch,
383
- 'timestamp': datetime.now().isoformat(),
384
- 'is_command': prompt.startswith('/'),
385
- 'contains_code': '```' in prompt or 'python' in prompt.lower() or 'javascript' in prompt.lower(),
386
- 'urgency': 'high' if any(word in prompt.lower() for word in ['urgent', 'error', 'bug', 'fix', 'broken']) else 'normal'
387
- }
388
-
389
- # Emit to /hook namespace
390
- self._emit_socketio_event('/hook', 'user_prompt', prompt_data)
391
-
392
- def _handle_pre_tool_fast(self, event):
393
- """Handle pre-tool use with comprehensive data capture.
394
-
395
- WHY comprehensive capture:
396
- - Captures tool parameters for debugging and security analysis
397
- - Provides context about what Claude is about to do
398
- - Enables pattern analysis and security monitoring
399
- """
400
- tool_name = event.get('tool_name', '')
401
- tool_input = event.get('tool_input', {})
402
-
403
- # Extract key parameters based on tool type
404
- tool_params = self._extract_tool_parameters(tool_name, tool_input)
405
-
406
- # Classify tool operation
407
- operation_type = self._classify_tool_operation(tool_name, tool_input)
408
-
409
- # Get working directory and git branch
410
- working_dir = event.get('cwd', '')
411
- git_branch = self._get_git_branch(working_dir) if working_dir else 'Unknown'
412
-
413
- pre_tool_data = {
414
- 'event_type': 'pre_tool',
415
- 'tool_name': tool_name,
416
- 'operation_type': operation_type,
417
- 'tool_parameters': tool_params,
418
- 'session_id': event.get('session_id', ''),
419
- 'working_directory': working_dir,
420
- 'git_branch': git_branch,
421
- 'timestamp': datetime.now().isoformat(),
422
- 'parameter_count': len(tool_input) if isinstance(tool_input, dict) else 0,
423
- 'is_file_operation': tool_name in ['Write', 'Edit', 'MultiEdit', 'Read', 'LS', 'Glob'],
424
- 'is_execution': tool_name in ['Bash', 'NotebookEdit'],
425
- 'is_delegation': tool_name == 'Task',
426
- 'security_risk': self._assess_security_risk(tool_name, tool_input)
427
- }
428
-
429
- # Add delegation-specific data if this is a Task tool
430
- if tool_name == 'Task' and isinstance(tool_input, dict):
431
- agent_type = tool_input.get('subagent_type', 'unknown')
432
- pre_tool_data['delegation_details'] = {
433
- 'agent_type': agent_type,
434
- 'prompt': tool_input.get('prompt', ''),
435
- 'description': tool_input.get('description', ''),
436
- 'task_preview': (tool_input.get('prompt', '') or tool_input.get('description', ''))[:100]
437
- }
438
-
439
- # Track this delegation for SubagentStop correlation
440
- session_id = event.get('session_id', '')
441
- if session_id and agent_type != 'unknown':
442
- self._track_delegation(session_id, agent_type)
443
-
444
- # Trigger memory pre-delegation hook
445
- self._trigger_memory_pre_delegation_hook(agent_type, tool_input, session_id)
446
-
447
- self._emit_socketio_event('/hook', 'pre_tool', pre_tool_data)
448
-
449
- def _handle_post_tool_fast(self, event):
450
- """Handle post-tool use with comprehensive data capture.
451
-
452
- WHY comprehensive capture:
453
- - Captures execution results and success/failure status
454
- - Provides duration and performance metrics
455
- - Enables pattern analysis of tool usage and success rates
456
- """
457
- tool_name = event.get('tool_name', '')
458
- exit_code = event.get('exit_code', 0)
459
-
460
- # Extract result data
461
- result_data = self._extract_tool_results(event)
462
-
463
- # Calculate duration if timestamps are available
464
- duration = self._calculate_duration(event)
465
-
466
- # Get working directory and git branch
467
- working_dir = event.get('cwd', '')
468
- git_branch = self._get_git_branch(working_dir) if working_dir else 'Unknown'
469
-
470
- post_tool_data = {
471
- 'event_type': 'post_tool',
472
- 'tool_name': tool_name,
473
- 'exit_code': exit_code,
474
- 'success': exit_code == 0,
475
- 'status': 'success' if exit_code == 0 else 'blocked' if exit_code == 2 else 'error',
476
- 'duration_ms': duration,
477
- 'result_summary': result_data,
478
- 'session_id': event.get('session_id', ''),
479
- 'working_directory': working_dir,
480
- 'git_branch': git_branch,
481
- 'timestamp': datetime.now().isoformat(),
482
- 'has_output': bool(result_data.get('output')),
483
- 'has_error': bool(result_data.get('error')),
484
- 'output_size': len(str(result_data.get('output', ''))) if result_data.get('output') else 0
485
- }
486
-
487
- # Handle Task delegation completion for memory hooks
488
- if tool_name == 'Task':
489
- session_id = event.get('session_id', '')
490
- agent_type = self._get_delegation_agent_type(session_id)
491
- self._trigger_memory_post_delegation_hook(agent_type, event, session_id)
492
-
493
- self._emit_socketio_event('/hook', 'post_tool', post_tool_data)
494
-
495
- def _extract_tool_parameters(self, tool_name: str, tool_input: dict) -> dict:
496
- """Extract relevant parameters based on tool type.
497
-
498
- WHY tool-specific extraction:
499
- - Different tools have different important parameters
500
- - Provides meaningful context for dashboard display
501
- - Enables tool-specific analysis and monitoring
502
- """
503
- if not isinstance(tool_input, dict):
504
- return {'raw_input': str(tool_input)}
505
-
506
- # Common parameters across all tools
507
- params = {
508
- 'input_type': type(tool_input).__name__,
509
- 'param_keys': list(tool_input.keys()) if tool_input else []
510
- }
511
-
512
- # Tool-specific parameter extraction
513
- if tool_name in ['Write', 'Edit', 'MultiEdit', 'Read', 'NotebookRead', 'NotebookEdit']:
514
- params.update({
515
- 'file_path': tool_input.get('file_path') or tool_input.get('notebook_path'),
516
- 'content_length': len(str(tool_input.get('content', tool_input.get('new_string', '')))),
517
- 'is_create': tool_name == 'Write',
518
- 'is_edit': tool_name in ['Edit', 'MultiEdit', 'NotebookEdit']
519
- })
520
- elif tool_name == 'Bash':
521
- command = tool_input.get('command', '')
522
- params.update({
523
- 'command': command[:100], # Truncate long commands
524
- 'command_length': len(command),
525
- 'has_pipe': '|' in command,
526
- 'has_redirect': '>' in command or '<' in command,
527
- 'timeout': tool_input.get('timeout')
528
- })
529
- elif tool_name in ['Grep', 'Glob']:
530
- params.update({
531
- 'pattern': tool_input.get('pattern', ''),
532
- 'path': tool_input.get('path', ''),
533
- 'output_mode': tool_input.get('output_mode')
534
- })
535
- elif tool_name == 'WebFetch':
536
- params.update({
537
- 'url': tool_input.get('url', ''),
538
- 'prompt': tool_input.get('prompt', '')[:50] # Truncate prompt
539
- })
540
- elif tool_name == 'Task':
541
- # Special handling for Task tool (agent delegations)
542
- params.update({
543
- 'subagent_type': tool_input.get('subagent_type', 'unknown'),
544
- 'description': tool_input.get('description', ''),
545
- 'prompt': tool_input.get('prompt', ''),
546
- 'prompt_preview': tool_input.get('prompt', '')[:200] if tool_input.get('prompt') else '',
547
- 'is_pm_delegation': tool_input.get('subagent_type') == 'pm',
548
- 'is_research_delegation': tool_input.get('subagent_type') == 'research',
549
- 'is_engineer_delegation': tool_input.get('subagent_type') == 'engineer'
550
- })
551
- elif tool_name == 'TodoWrite':
552
- # Special handling for TodoWrite tool (task management)
553
- todos = tool_input.get('todos', [])
554
- params.update({
555
- 'todo_count': len(todos),
556
- 'todos': todos, # Full todo list
557
- 'todo_summary': self._summarize_todos(todos),
558
- 'has_in_progress': any(t.get('status') == 'in_progress' for t in todos),
559
- 'has_pending': any(t.get('status') == 'pending' for t in todos),
560
- 'has_completed': any(t.get('status') == 'completed' for t in todos),
561
- 'priorities': list(set(t.get('priority', 'medium') for t in todos))
562
- })
563
-
564
- return params
565
-
566
- def _summarize_todos(self, todos: list) -> dict:
567
- """Create a summary of the todo list for quick understanding."""
568
- if not todos:
569
- return {'total': 0, 'summary': 'Empty todo list'}
570
-
571
- status_counts = {'pending': 0, 'in_progress': 0, 'completed': 0}
572
- priority_counts = {'high': 0, 'medium': 0, 'low': 0}
573
-
574
- for todo in todos:
575
- status = todo.get('status', 'pending')
576
- priority = todo.get('priority', 'medium')
577
-
578
- if status in status_counts:
579
- status_counts[status] += 1
580
- if priority in priority_counts:
581
- priority_counts[priority] += 1
582
-
583
- # Create a text summary
584
- summary_parts = []
585
- if status_counts['completed'] > 0:
586
- summary_parts.append(f"{status_counts['completed']} completed")
587
- if status_counts['in_progress'] > 0:
588
- summary_parts.append(f"{status_counts['in_progress']} in progress")
589
- if status_counts['pending'] > 0:
590
- summary_parts.append(f"{status_counts['pending']} pending")
591
-
592
- return {
593
- 'total': len(todos),
594
- 'status_counts': status_counts,
595
- 'priority_counts': priority_counts,
596
- 'summary': ', '.join(summary_parts) if summary_parts else 'No tasks'
597
- }
598
-
599
- def _classify_tool_operation(self, tool_name: str, tool_input: dict) -> str:
600
- """Classify the type of operation being performed."""
601
- if tool_name in ['Read', 'LS', 'Glob', 'Grep', 'NotebookRead']:
602
- return 'read'
603
- elif tool_name in ['Write', 'Edit', 'MultiEdit', 'NotebookEdit']:
604
- return 'write'
605
- elif tool_name == 'Bash':
606
- return 'execute'
607
- elif tool_name in ['WebFetch', 'WebSearch']:
608
- return 'network'
609
- elif tool_name == 'TodoWrite':
610
- return 'task_management'
611
- elif tool_name == 'Task':
612
- return 'delegation'
613
- else:
614
- return 'other'
615
-
616
- def _assess_security_risk(self, tool_name: str, tool_input: dict) -> str:
617
- """Assess the security risk level of the tool operation."""
618
- if tool_name == 'Bash':
619
- command = tool_input.get('command', '').lower()
620
- # Check for potentially dangerous commands
621
- dangerous_patterns = ['rm -rf', 'sudo', 'chmod 777', 'curl', 'wget', '> /etc/', 'dd if=']
622
- if any(pattern in command for pattern in dangerous_patterns):
623
- return 'high'
624
- elif any(word in command for word in ['install', 'delete', 'format', 'kill']):
625
- return 'medium'
626
- else:
627
- return 'low'
628
- elif tool_name in ['Write', 'Edit', 'MultiEdit']:
629
- file_path = tool_input.get('file_path', '')
630
- # Check for system file modifications
631
- if any(path in file_path for path in ['/etc/', '/usr/', '/var/', '/sys/']):
632
- return 'high'
633
- elif file_path.startswith('/'):
634
- return 'medium'
635
- else:
636
- return 'low'
637
- else:
638
- return 'low'
639
-
640
- def _extract_tool_results(self, event: dict) -> dict:
641
- """Extract and summarize tool execution results."""
642
- result = {
643
- 'exit_code': event.get('exit_code', 0),
644
- 'has_output': False,
645
- 'has_error': False
646
- }
647
-
648
- # Extract output if available
649
- if 'output' in event:
650
- output = str(event['output'])
651
- result.update({
652
- 'has_output': bool(output.strip()),
653
- 'output_preview': output[:200] if len(output) > 200 else output,
654
- 'output_lines': len(output.split('\n')) if output else 0
655
- })
656
-
657
- # Extract error information
658
- if 'error' in event or event.get('exit_code', 0) != 0:
659
- error = str(event.get('error', ''))
660
- result.update({
661
- 'has_error': True,
662
- 'error_preview': error[:200] if len(error) > 200 else error
663
- })
664
-
665
- return result
666
-
667
- def _calculate_duration(self, event: dict) -> int:
668
- """Calculate operation duration in milliseconds if timestamps are available."""
669
- # This would require start/end timestamps from Claude Code
670
- # For now, return None as we don't have this data
449
+ print(f"Error handling {hook_type}: {e}", file=sys.stderr)
450
+ finally:
451
+ # Calculate duration
452
+ duration_ms = int((time.time() - start_time) * 1000)
453
+
454
+ # Emit hook execution event
455
+ self._emit_hook_execution_event(
456
+ hook_type=hook_type,
457
+ event=event,
458
+ success=success,
459
+ duration_ms=duration_ms,
460
+ error_message=error_message,
461
+ )
462
+
463
+ return return_value
464
+
671
465
  return None
672
-
673
- def _handle_notification_fast(self, event):
674
- """Handle notification events from Claude.
675
-
676
- WHY enhanced notification capture:
677
- - Provides visibility into Claude's status and communication flow
678
- - Captures notification type, content, and context for monitoring
679
- - Enables pattern analysis of Claude's notification behavior
680
- - Useful for debugging communication issues and user experience
466
+
467
+ def handle_subagent_stop(self, event: dict):
468
+ """Delegate subagent stop processing to the specialized processor."""
469
+ self.subagent_processor.process_subagent_stop(event)
470
+
471
+ def _continue_execution(self, modified_input: Optional[dict] = None) -> None:
681
472
  """
682
- notification_type = event.get('notification_type', 'unknown')
683
- message = event.get('message', '')
684
-
685
- # Get working directory and git branch
686
- working_dir = event.get('cwd', '')
687
- git_branch = self._get_git_branch(working_dir) if working_dir else 'Unknown'
688
-
689
- notification_data = {
690
- 'event_type': 'notification',
691
- 'notification_type': notification_type,
692
- 'message': message,
693
- 'message_preview': message[:200] if len(message) > 200 else message,
694
- 'message_length': len(message),
695
- 'session_id': event.get('session_id', ''),
696
- 'working_directory': working_dir,
697
- 'git_branch': git_branch,
698
- 'timestamp': datetime.now().isoformat(),
699
- 'is_user_input_request': 'input' in message.lower() or 'waiting' in message.lower(),
700
- 'is_error_notification': 'error' in message.lower() or 'failed' in message.lower(),
701
- 'is_status_update': any(word in message.lower() for word in ['processing', 'analyzing', 'working', 'thinking'])
702
- }
703
-
704
- # Emit to /hook namespace
705
- self._emit_socketio_event('/hook', 'notification', notification_data)
706
-
707
- def _handle_stop_fast(self, event):
708
- """Handle stop events when Claude processing stops.
709
-
710
- WHY comprehensive stop capture:
711
- - Provides visibility into Claude's session lifecycle
712
- - Captures stop reason and context for analysis
713
- - Enables tracking of session completion patterns
714
- - Useful for understanding when and why Claude stops responding
473
+ Send continue action to Claude with optional input modification.
474
+
475
+ WHY: Centralized response ensures consistent format
476
+ and makes it easier to add response modifications.
477
+
478
+ Args:
479
+ modified_input: Modified tool parameters for PreToolUse hooks (v2.0.30+)
715
480
  """
716
- reason = event.get('reason', 'unknown')
717
- stop_type = event.get('stop_type', 'normal')
718
-
719
- # Get working directory and git branch
720
- working_dir = event.get('cwd', '')
721
- git_branch = self._get_git_branch(working_dir) if working_dir else 'Unknown'
722
-
723
- stop_data = {
724
- 'event_type': 'stop',
725
- 'reason': reason,
726
- 'stop_type': stop_type,
727
- 'session_id': event.get('session_id', ''),
728
- 'working_directory': working_dir,
729
- 'git_branch': git_branch,
730
- 'timestamp': datetime.now().isoformat(),
731
- 'is_user_initiated': reason in ['user_stop', 'user_cancel', 'interrupt'],
732
- 'is_error_stop': reason in ['error', 'timeout', 'failed'],
733
- 'is_completion_stop': reason in ['completed', 'finished', 'done'],
734
- 'has_output': bool(event.get('final_output'))
735
- }
736
-
737
- # Emit to /hook namespace
738
- self._emit_socketio_event('/hook', 'stop', stop_data)
739
-
740
- def _handle_subagent_stop_fast(self, event):
741
- """Handle subagent stop events when subagent processing stops.
742
-
743
- WHY comprehensive subagent stop capture:
744
- - Provides visibility into subagent lifecycle and delegation patterns
745
- - Captures agent type, ID, reason, and results for analysis
746
- - Enables tracking of delegation success/failure patterns
747
- - Useful for understanding subagent performance and reliability
481
+ if modified_input is not None:
482
+ # Claude Code v2.0.30+ supports modifying PreToolUse tool inputs
483
+ print(json.dumps({"action": "continue", "tool_input": modified_input}))
484
+ else:
485
+ print(json.dumps({"action": "continue"}))
486
+
487
+ # Delegation methods for compatibility with event_handlers
488
+ def _track_delegation(self, session_id: str, agent_type: str, request_data=None):
489
+ """Track delegation through state manager."""
490
+ self.state_manager.track_delegation(session_id, agent_type, request_data)
491
+
492
+ def _get_delegation_agent_type(self, session_id: str) -> str:
493
+ """Get delegation agent type through state manager."""
494
+ return self.state_manager.get_delegation_agent_type(session_id)
495
+
496
+ def _get_git_branch(self, working_dir=None) -> str:
497
+ """Get git branch through state manager."""
498
+ return self.state_manager.get_git_branch(working_dir)
499
+
500
+ def _emit_socketio_event(self, namespace: str, event: str, data: dict):
501
+ """Emit event through connection manager."""
502
+ self.connection_manager.emit_event(namespace, event, data)
503
+
504
+ def _get_event_key(self, event: dict) -> str:
505
+ """Generate event key through duplicate detector (backward compatibility)."""
506
+ return self.duplicate_detector.generate_event_key(event)
507
+
508
+ def _emit_hook_execution_event(
509
+ self,
510
+ hook_type: str,
511
+ event: dict,
512
+ success: bool,
513
+ duration_ms: int,
514
+ error_message: Optional[str] = None,
515
+ ):
516
+ """Emit a structured JSON event for hook execution.
517
+
518
+ This emits a normalized event following the claude_event schema to provide
519
+ visibility into hook processing, timing, and success/failure status.
520
+
521
+ Args:
522
+ hook_type: The type of hook that executed (e.g., "UserPromptSubmit", "PreToolUse")
523
+ event: The original hook event data
524
+ success: Whether the hook executed successfully
525
+ duration_ms: How long the hook took to execute in milliseconds
526
+ error_message: Optional error message if the hook failed
748
527
  """
749
- # First try to get agent type from our tracking
750
- session_id = event.get('session_id', '')
751
- agent_type = self._get_delegation_agent_type(session_id) if session_id else 'unknown'
752
-
753
- # Fall back to event data if tracking didn't have it
754
- if agent_type == 'unknown':
755
- agent_type = event.get('agent_type', event.get('subagent_type', 'unknown'))
756
-
757
- agent_id = event.get('agent_id', event.get('subagent_id', ''))
758
- reason = event.get('reason', event.get('stop_reason', 'unknown'))
759
-
760
- # Try to infer agent type from other fields if still unknown
761
- if agent_type == 'unknown' and 'task' in event:
762
- task_desc = str(event.get('task', '')).lower()
763
- if 'research' in task_desc:
764
- agent_type = 'research'
765
- elif 'engineer' in task_desc or 'code' in task_desc:
766
- agent_type = 'engineer'
767
- elif 'pm' in task_desc or 'project' in task_desc:
768
- agent_type = 'pm'
769
-
770
- # Get working directory and git branch
771
- working_dir = event.get('cwd', '')
772
- git_branch = self._get_git_branch(working_dir) if working_dir else 'Unknown'
773
-
774
- subagent_stop_data = {
775
- 'event_type': 'subagent_stop',
776
- 'agent_type': agent_type,
777
- 'agent_id': agent_id,
778
- 'reason': reason,
779
- 'session_id': event.get('session_id', ''),
780
- 'working_directory': working_dir,
781
- 'git_branch': git_branch,
782
- 'timestamp': datetime.now().isoformat(),
783
- 'is_successful_completion': reason in ['completed', 'finished', 'done'],
784
- 'is_error_termination': reason in ['error', 'timeout', 'failed', 'blocked'],
785
- 'is_delegation_related': agent_type in ['research', 'engineer', 'pm', 'ops'],
786
- 'has_results': bool(event.get('results') or event.get('output')),
787
- 'duration_context': event.get('duration_ms')
528
+ # Generate a human-readable summary based on hook type
529
+ summary = self._generate_hook_summary(hook_type, event, success)
530
+
531
+ # Extract common fields
532
+ session_id = event.get("session_id", "")
533
+ working_dir = event.get("cwd", "")
534
+
535
+ # Build hook execution data
536
+ hook_data = {
537
+ "hook_name": hook_type,
538
+ "hook_type": hook_type,
539
+ "session_id": session_id,
540
+ "working_directory": working_dir,
541
+ "success": success,
542
+ "duration_ms": duration_ms,
543
+ "result_summary": summary,
544
+ "timestamp": datetime.now(timezone.utc).isoformat(),
788
545
  }
789
-
790
- # Debug log the raw event data
546
+
547
+ # Add error information if present
548
+ if error_message:
549
+ hook_data["error_message"] = error_message
550
+
551
+ # Add hook-specific context
552
+ if hook_type == "PreToolUse":
553
+ hook_data["tool_name"] = event.get("tool_name", "")
554
+ elif hook_type == "PostToolUse":
555
+ hook_data["tool_name"] = event.get("tool_name", "")
556
+ hook_data["exit_code"] = event.get("exit_code", 0)
557
+ elif hook_type == "UserPromptSubmit":
558
+ prompt = event.get("prompt", "")
559
+ hook_data["prompt_preview"] = prompt[:100] if len(prompt) > 100 else prompt
560
+ hook_data["prompt_length"] = len(prompt)
561
+ elif hook_type == "SubagentStop":
562
+ hook_data["agent_type"] = event.get("agent_type", "unknown")
563
+ hook_data["reason"] = event.get("reason", "unknown")
564
+
565
+ # Emit through connection manager with proper structure
566
+ # This uses the existing event infrastructure
567
+ self._emit_socketio_event("", "hook_execution", hook_data)
568
+
791
569
  if DEBUG:
792
- print(f"SubagentStop raw event data: {json.dumps(event, indent=2)}", file=sys.stderr)
793
-
794
- # Emit to /hook namespace
795
- self._emit_socketio_event('/hook', 'subagent_stop', subagent_stop_data)
796
-
797
- def _trigger_memory_pre_delegation_hook(self, agent_type: str, tool_input: dict, session_id: str):
798
- """Trigger memory pre-delegation hook for agent memory injection.
799
-
800
- WHY: This connects Claude Code's Task delegation events to our memory system.
801
- When Claude is about to delegate to an agent, we inject the agent's memory
802
- into the delegation context so the agent has access to accumulated knowledge.
803
-
804
- DESIGN DECISION: We modify the tool_input in place to inject memory context.
805
- This ensures the agent receives the memory as part of their initial context.
806
- """
807
- if not self.memory_hooks_initialized or not self.pre_delegation_hook:
808
- return
809
-
810
- try:
811
- # Create hook context for memory injection
812
- hook_context = HookContext(
813
- hook_type=HookType.PRE_DELEGATION,
814
- data={
815
- 'agent': agent_type,
816
- 'context': tool_input,
817
- 'session_id': session_id
818
- },
819
- metadata={
820
- 'source': 'claude_hook_handler',
821
- 'tool_name': 'Task'
822
- },
823
- timestamp=datetime.now().isoformat(),
824
- session_id=session_id
570
+ print(
571
+ f"📊 Hook execution event: {hook_type} - {duration_ms}ms - {'✅' if success else '❌'}",
572
+ file=sys.stderr,
825
573
  )
826
-
827
- # Execute pre-delegation hook
828
- result = self.pre_delegation_hook.execute(hook_context)
829
-
830
- if result.success and result.modified and result.data:
831
- # Update tool_input with memory-enhanced context
832
- enhanced_context = result.data.get('context', {})
833
- if enhanced_context and 'agent_memory' in enhanced_context:
834
- # Inject memory into the task prompt/description
835
- original_prompt = tool_input.get('prompt', '')
836
- memory_section = enhanced_context['agent_memory']
837
-
838
- # Prepend memory to the original prompt
839
- enhanced_prompt = f"{memory_section}\n\n{original_prompt}"
840
- tool_input['prompt'] = enhanced_prompt
841
-
842
- if DEBUG:
843
- memory_size = len(memory_section.encode('utf-8'))
844
- print(f"✅ Injected {memory_size} bytes of memory for agent '{agent_type}'", file=sys.stderr)
845
-
846
- except Exception as e:
847
- if DEBUG:
848
- print(f"❌ Memory pre-delegation hook failed: {e}", file=sys.stderr)
849
- # Don't fail the delegation - memory is optional
850
-
851
- def _trigger_memory_post_delegation_hook(self, agent_type: str, event: dict, session_id: str):
852
- """Trigger memory post-delegation hook for learning extraction.
853
-
854
- WHY: This connects Claude Code's Task completion events to our memory system.
855
- When an agent completes a task, we extract learnings from the result and
856
- store them in the agent's memory for future use.
857
-
858
- DESIGN DECISION: We extract learnings from both the tool output and any
859
- error messages, providing comprehensive context for the memory system.
574
+
575
+ def _generate_hook_summary(self, hook_type: str, event: dict, success: bool) -> str:
576
+ """Generate a human-readable summary of what the hook did.
577
+
578
+ Args:
579
+ hook_type: The type of hook
580
+ event: The hook event data
581
+ success: Whether the hook executed successfully
582
+
583
+ Returns:
584
+ A brief description of what happened
860
585
  """
861
- if not self.memory_hooks_initialized or not self.post_delegation_hook:
862
- return
863
-
864
- try:
865
- # Extract result content from the event
866
- result_content = ""
867
- output = event.get('output', '')
868
- error = event.get('error', '')
869
- exit_code = event.get('exit_code', 0)
870
-
871
- # Build result content
872
- if output:
873
- result_content = str(output)
874
- elif error:
875
- result_content = f"Error: {str(error)}"
876
- else:
877
- result_content = f"Task completed with exit code: {exit_code}"
878
-
879
- # Create hook context for learning extraction
880
- hook_context = HookContext(
881
- hook_type=HookType.POST_DELEGATION,
882
- data={
883
- 'agent': agent_type,
884
- 'result': {
885
- 'content': result_content,
886
- 'success': exit_code == 0,
887
- 'exit_code': exit_code
888
- },
889
- 'session_id': session_id
890
- },
891
- metadata={
892
- 'source': 'claude_hook_handler',
893
- 'tool_name': 'Task',
894
- 'duration_ms': event.get('duration_ms', 0)
895
- },
896
- timestamp=datetime.now().isoformat(),
897
- session_id=session_id
898
- )
899
-
900
- # Execute post-delegation hook
901
- result = self.post_delegation_hook.execute(hook_context)
902
-
903
- if result.success and result.metadata:
904
- learnings_extracted = result.metadata.get('learnings_extracted', 0)
905
- if learnings_extracted > 0 and DEBUG:
906
- print(f"✅ Extracted {learnings_extracted} learnings for agent '{agent_type}'", file=sys.stderr)
907
-
908
- except Exception as e:
909
- if DEBUG:
910
- print(f"❌ Memory post-delegation hook failed: {e}", file=sys.stderr)
911
- # Don't fail the delegation result - memory is optional
912
-
586
+ if not success:
587
+ return f"Hook {hook_type} failed during processing"
588
+
589
+ # Generate hook-specific summaries
590
+ if hook_type == "UserPromptSubmit":
591
+ prompt = event.get("prompt", "")
592
+ if prompt.startswith("/"):
593
+ return f"Processed command: {prompt.split()[0]}"
594
+ return f"Processed user prompt ({len(prompt)} chars)"
595
+
596
+ if hook_type == "PreToolUse":
597
+ tool_name = event.get("tool_name", "unknown")
598
+ return f"Pre-processing tool call: {tool_name}"
599
+
600
+ if hook_type == "PostToolUse":
601
+ tool_name = event.get("tool_name", "unknown")
602
+ exit_code = event.get("exit_code", 0)
603
+ status = "success" if exit_code == 0 else "failed"
604
+ return f"Completed tool call: {tool_name} ({status})"
605
+
606
+ if hook_type == "SubagentStop":
607
+ agent_type = event.get("agent_type", "unknown")
608
+ reason = event.get("reason", "unknown")
609
+ return f"Subagent {agent_type} stopped: {reason}"
610
+
611
+ if hook_type == "SessionStart":
612
+ return "New session started"
613
+
614
+ if hook_type == "Stop":
615
+ reason = event.get("reason", "unknown")
616
+ return f"Session stopped: {reason}"
617
+
618
+ if hook_type == "Notification":
619
+ notification_type = event.get("notification_type", "unknown")
620
+ return f"Notification received: {notification_type}"
621
+
622
+ if hook_type == "AssistantResponse":
623
+ response_len = len(event.get("response", ""))
624
+ return f"Assistant response generated ({response_len} chars)"
625
+
626
+ # Default summary
627
+ return f"Hook {hook_type} processed successfully"
628
+
913
629
  def __del__(self):
914
- """Cleanup Socket.IO client on handler destruction."""
915
- if self.sio_client and self.sio_connected:
630
+ """Cleanup on handler destruction."""
631
+ # Clean up connection manager if it exists
632
+ if hasattr(self, "connection_manager") and self.connection_manager:
916
633
  try:
917
- self.sio_client.disconnect()
918
- except:
919
- pass
634
+ self.connection_manager.cleanup()
635
+ except Exception:
636
+ pass # Ignore cleanup errors during destruction
920
637
 
921
638
 
922
639
  def main():
923
- """Entry point with comprehensive error handling."""
640
+ """Entry point with singleton pattern and proper cleanup."""
641
+ global _global_handler
642
+ _continue_printed = False # Track if we've already printed continue
643
+
644
+ # Check Claude Code version compatibility first
645
+ is_compatible, version = check_claude_version()
646
+ if not is_compatible:
647
+ # Version incompatible - just continue without processing
648
+ # This prevents errors on older Claude Code versions
649
+ if DEBUG and version:
650
+ print(
651
+ f"Skipping hook processing due to version incompatibility ({version})",
652
+ file=sys.stderr,
653
+ )
654
+ print(json.dumps({"action": "continue"}))
655
+ sys.exit(0)
656
+
657
+ def cleanup_handler(signum=None, frame=None):
658
+ """Cleanup handler for signals and exit."""
659
+ nonlocal _continue_printed
660
+ if DEBUG:
661
+ print(
662
+ f"Hook handler cleanup (pid: {os.getpid()}, signal: {signum})",
663
+ file=sys.stderr,
664
+ )
665
+ # Only output continue if we haven't already (i.e., if interrupted by signal)
666
+ if signum is not None and not _continue_printed:
667
+ print(json.dumps({"action": "continue"}))
668
+ _continue_printed = True
669
+ sys.exit(0)
670
+
671
+ # Register cleanup handlers
672
+ signal.signal(signal.SIGTERM, cleanup_handler)
673
+ signal.signal(signal.SIGINT, cleanup_handler)
674
+ # Don't register atexit handler since we're handling exit properly in main
675
+
924
676
  try:
925
- handler = ClaudeHookHandler()
677
+ # Use singleton pattern to prevent creating multiple instances
678
+ with _handler_lock:
679
+ if _global_handler is None:
680
+ _global_handler = ClaudeHookHandler()
681
+ if DEBUG:
682
+ print(
683
+ f"✅ Created new ClaudeHookHandler singleton (pid: {os.getpid()})",
684
+ file=sys.stderr,
685
+ )
686
+ elif DEBUG:
687
+ print(
688
+ f"♻️ Reusing existing ClaudeHookHandler singleton (pid: {os.getpid()})",
689
+ file=sys.stderr,
690
+ )
691
+
692
+ handler = _global_handler
693
+
694
+ # Mark that handle() will print continue
926
695
  handler.handle()
696
+ _continue_printed = True # Mark as printed since handle() always prints it
697
+
698
+ # handler.handle() already calls _continue_execution(), so we don't need to do it again
699
+ # Just exit cleanly
700
+ sys.exit(0)
701
+
927
702
  except Exception as e:
928
- # Always output continue action to not block Claude
929
- print(json.dumps({"action": "continue"}))
703
+ # Only output continue if not already printed
704
+ if not _continue_printed:
705
+ print(json.dumps({"action": "continue"}))
706
+ _continue_printed = True
930
707
  # Log error for debugging
931
708
  if DEBUG:
932
709
  print(f"Hook handler error: {e}", file=sys.stderr)
@@ -934,4 +711,4 @@ def main():
934
711
 
935
712
 
936
713
  if __name__ == "__main__":
937
- main()
714
+ main()