claude-mpm 5.0.9__py3-none-any.whl → 5.4.41__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.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (263) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +4 -0
  3. claude_mpm/agents/BASE_AGENT.md +164 -0
  4. claude_mpm/agents/{PM_INSTRUCTIONS_TEACH.md → CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md} +721 -41
  5. claude_mpm/agents/MEMORY.md +1 -1
  6. claude_mpm/agents/PM_INSTRUCTIONS.md +468 -468
  7. claude_mpm/agents/WORKFLOW.md +5 -254
  8. claude_mpm/agents/agent_loader.py +13 -44
  9. claude_mpm/agents/base_agent.json +1 -1
  10. claude_mpm/agents/frontmatter_validator.py +70 -2
  11. claude_mpm/agents/templates/circuit-breakers.md +431 -45
  12. claude_mpm/cli/__init__.py +0 -1
  13. claude_mpm/cli/__main__.py +4 -0
  14. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  15. claude_mpm/cli/commands/agent_state_manager.py +18 -27
  16. claude_mpm/cli/commands/agents.py +175 -37
  17. claude_mpm/cli/commands/auto_configure.py +723 -236
  18. claude_mpm/cli/commands/config.py +88 -2
  19. claude_mpm/cli/commands/configure.py +1262 -157
  20. claude_mpm/cli/commands/configure_agent_display.py +25 -6
  21. claude_mpm/cli/commands/mpm_init/core.py +225 -46
  22. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  23. claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
  24. claude_mpm/cli/commands/postmortem.py +1 -1
  25. claude_mpm/cli/commands/profile.py +277 -0
  26. claude_mpm/cli/commands/skills.py +214 -189
  27. claude_mpm/cli/commands/summarize.py +413 -0
  28. claude_mpm/cli/executor.py +21 -3
  29. claude_mpm/cli/interactive/agent_wizard.py +85 -10
  30. claude_mpm/cli/parsers/agents_parser.py +54 -9
  31. claude_mpm/cli/parsers/auto_configure_parser.py +13 -138
  32. claude_mpm/cli/parsers/base_parser.py +12 -0
  33. claude_mpm/cli/parsers/config_parser.py +153 -83
  34. claude_mpm/cli/parsers/profile_parser.py +148 -0
  35. claude_mpm/cli/parsers/skills_parser.py +3 -2
  36. claude_mpm/cli/startup.py +879 -149
  37. claude_mpm/commands/mpm-config.md +28 -0
  38. claude_mpm/commands/mpm-doctor.md +9 -22
  39. claude_mpm/commands/mpm-help.md +5 -287
  40. claude_mpm/commands/mpm-init.md +81 -507
  41. claude_mpm/commands/mpm-monitor.md +15 -402
  42. claude_mpm/commands/mpm-organize.md +120 -0
  43. claude_mpm/commands/mpm-postmortem.md +6 -108
  44. claude_mpm/commands/mpm-session-resume.md +12 -363
  45. claude_mpm/commands/mpm-status.md +5 -69
  46. claude_mpm/commands/mpm-ticket-view.md +52 -495
  47. claude_mpm/commands/mpm-version.md +5 -107
  48. claude_mpm/config/agent_sources.py +27 -0
  49. claude_mpm/core/config.py +2 -4
  50. claude_mpm/core/framework/formatters/content_formatter.py +3 -13
  51. claude_mpm/core/framework/loaders/agent_loader.py +8 -5
  52. claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
  53. claude_mpm/core/framework_loader.py +4 -2
  54. claude_mpm/core/logger.py +13 -0
  55. claude_mpm/core/optimized_startup.py +59 -0
  56. claude_mpm/core/output_style_manager.py +173 -43
  57. claude_mpm/core/shared/config_loader.py +1 -1
  58. claude_mpm/core/socketio_pool.py +3 -3
  59. claude_mpm/core/unified_agent_registry.py +134 -16
  60. claude_mpm/core/unified_config.py +22 -0
  61. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  62. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +1 -0
  63. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +1 -0
  64. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +1 -0
  65. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +1 -0
  66. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +1 -0
  67. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +2 -0
  68. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DjhvlsAc.js +1 -0
  69. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/N4qtv3Hx.js +2 -0
  70. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uj46x2Wr.js +1 -0
  71. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +2 -0
  72. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +1 -0
  73. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.CAGBuiOw.js +1 -0
  74. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +1 -0
  75. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +10 -0
  76. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  77. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  78. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  79. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  80. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  81. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  82. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  83. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  84. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  85. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  86. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  87. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  88. claude_mpm/hooks/claude_hooks/event_handlers.py +211 -78
  89. claude_mpm/hooks/claude_hooks/hook_handler.py +155 -1
  90. claude_mpm/hooks/claude_hooks/installer.py +33 -10
  91. claude_mpm/hooks/claude_hooks/memory_integration.py +28 -0
  92. claude_mpm/hooks/claude_hooks/response_tracking.py +2 -3
  93. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  94. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  95. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  96. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  97. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  98. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  99. claude_mpm/hooks/claude_hooks/services/connection_manager.py +30 -6
  100. claude_mpm/hooks/memory_integration_hook.py +46 -1
  101. claude_mpm/init.py +63 -19
  102. claude_mpm/models/agent_definition.py +7 -0
  103. claude_mpm/models/git_repository.py +3 -3
  104. claude_mpm/scripts/claude-hook-handler.sh +58 -18
  105. claude_mpm/scripts/launch_monitor.py +93 -13
  106. claude_mpm/scripts/start_activity_logging.py +0 -0
  107. claude_mpm/services/agents/agent_builder.py +3 -3
  108. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  109. claude_mpm/services/agents/agent_review_service.py +280 -0
  110. claude_mpm/services/agents/cache_git_manager.py +6 -6
  111. claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
  112. claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -5
  113. claude_mpm/services/agents/deployment/agent_template_builder.py +5 -3
  114. claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
  115. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +320 -29
  116. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +546 -68
  117. claude_mpm/services/agents/git_source_manager.py +36 -2
  118. claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
  119. claude_mpm/services/agents/recommender.py +5 -3
  120. claude_mpm/services/agents/single_tier_deployment_service.py +2 -2
  121. claude_mpm/services/agents/sources/git_source_sync_service.py +13 -6
  122. claude_mpm/services/agents/startup_sync.py +22 -2
  123. claude_mpm/services/agents/toolchain_detector.py +10 -6
  124. claude_mpm/services/analysis/__init__.py +11 -1
  125. claude_mpm/services/analysis/clone_detector.py +1030 -0
  126. claude_mpm/services/command_deployment_service.py +81 -10
  127. claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
  128. claude_mpm/services/diagnostics/checks/agent_sources_check.py +1 -1
  129. claude_mpm/services/event_bus/config.py +3 -1
  130. claude_mpm/services/git/git_operations_service.py +101 -16
  131. claude_mpm/services/monitor/daemon.py +9 -2
  132. claude_mpm/services/monitor/daemon_manager.py +39 -3
  133. claude_mpm/services/monitor/management/lifecycle.py +8 -1
  134. claude_mpm/services/monitor/server.py +698 -22
  135. claude_mpm/services/pm_skills_deployer.py +676 -0
  136. claude_mpm/services/profile_manager.py +331 -0
  137. claude_mpm/services/project/project_organizer.py +4 -0
  138. claude_mpm/services/self_upgrade_service.py +120 -12
  139. claude_mpm/services/skills/__init__.py +3 -0
  140. claude_mpm/services/skills/git_skill_source_manager.py +130 -2
  141. claude_mpm/services/skills/selective_skill_deployer.py +704 -0
  142. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  143. claude_mpm/services/skills_deployer.py +126 -9
  144. claude_mpm/services/socketio/dashboard_server.py +1 -0
  145. claude_mpm/services/socketio/event_normalizer.py +51 -6
  146. claude_mpm/services/socketio/server/core.py +386 -108
  147. claude_mpm/services/version_control/git_operations.py +103 -0
  148. claude_mpm/skills/skill_manager.py +92 -3
  149. claude_mpm/utils/agent_dependency_loader.py +14 -2
  150. claude_mpm/utils/agent_filters.py +17 -44
  151. claude_mpm/utils/gitignore.py +3 -0
  152. claude_mpm/utils/migration.py +4 -4
  153. claude_mpm/utils/robust_installer.py +47 -3
  154. {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/METADATA +57 -87
  155. {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/RECORD +160 -211
  156. claude_mpm-5.4.41.dist-info/entry_points.txt +5 -0
  157. claude_mpm-5.4.41.dist-info/licenses/LICENSE +94 -0
  158. claude_mpm-5.4.41.dist-info/licenses/LICENSE-FAQ.md +153 -0
  159. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
  160. claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
  161. claude_mpm/agents/BASE_OPS.md +0 -219
  162. claude_mpm/agents/BASE_PM.md +0 -480
  163. claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
  164. claude_mpm/agents/BASE_QA.md +0 -167
  165. claude_mpm/agents/BASE_RESEARCH.md +0 -53
  166. claude_mpm/agents/base_agent_loader.py +0 -601
  167. claude_mpm/cli/commands/agents_detect.py +0 -380
  168. claude_mpm/cli/commands/agents_recommend.py +0 -309
  169. claude_mpm/cli/ticket_cli.py +0 -35
  170. claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
  171. claude_mpm/commands/mpm-agents-detect.md +0 -177
  172. claude_mpm/commands/mpm-agents-list.md +0 -131
  173. claude_mpm/commands/mpm-agents-recommend.md +0 -223
  174. claude_mpm/commands/mpm-config-view.md +0 -150
  175. claude_mpm/commands/mpm-ticket-organize.md +0 -304
  176. claude_mpm/dashboard/analysis_runner.py +0 -455
  177. claude_mpm/dashboard/index.html +0 -13
  178. claude_mpm/dashboard/open_dashboard.py +0 -66
  179. claude_mpm/dashboard/static/css/activity.css +0 -1958
  180. claude_mpm/dashboard/static/css/connection-status.css +0 -370
  181. claude_mpm/dashboard/static/css/dashboard.css +0 -4701
  182. claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
  183. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
  184. claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
  185. claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
  186. claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
  187. claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
  188. claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
  189. claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
  190. claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
  191. claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
  192. claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
  193. claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
  194. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
  195. claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
  196. claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
  197. claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
  198. claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
  199. claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
  200. claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
  201. claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
  202. claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
  203. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
  204. claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
  205. claude_mpm/dashboard/static/js/connection-manager.js +0 -536
  206. claude_mpm/dashboard/static/js/dashboard.js +0 -1914
  207. claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
  208. claude_mpm/dashboard/static/js/socket-client.js +0 -1474
  209. claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
  210. claude_mpm/dashboard/static/socket.io.min.js +0 -7
  211. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
  212. claude_mpm/dashboard/templates/code_simple.html +0 -153
  213. claude_mpm/dashboard/templates/index.html +0 -606
  214. claude_mpm/dashboard/test_dashboard.html +0 -372
  215. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  216. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  217. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  218. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  219. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  220. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  221. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  222. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  223. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  224. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  225. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  226. claude_mpm/scripts/mcp_server.py +0 -75
  227. claude_mpm/scripts/mcp_wrapper.py +0 -39
  228. claude_mpm/services/mcp_gateway/__init__.py +0 -159
  229. claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
  230. claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
  231. claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
  232. claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
  233. claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
  234. claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
  235. claude_mpm/services/mcp_gateway/core/base.py +0 -312
  236. claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
  237. claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
  238. claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
  239. claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
  240. claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
  241. claude_mpm/services/mcp_gateway/main.py +0 -589
  242. claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
  243. claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
  244. claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
  245. claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
  246. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
  247. claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
  248. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
  249. claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
  250. claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
  251. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
  252. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
  253. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
  254. claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
  255. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
  256. claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
  257. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
  258. claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
  259. claude_mpm-5.0.9.dist-info/entry_points.txt +0 -10
  260. claude_mpm-5.0.9.dist-info/licenses/LICENSE +0 -21
  261. /claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +0 -0
  262. {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/WHEEL +0 -0
  263. {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,36 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
+
8
+ <link rel="modulepreload" href="/_app/immutable/entry/start.DzuEhzqh.js">
9
+ <link rel="modulepreload" href="/_app/immutable/chunks/CIXEwuWe.js">
10
+ <link rel="modulepreload" href="/_app/immutable/chunks/DjhvlsAc.js">
11
+ <link rel="modulepreload" href="/_app/immutable/entry/app.DTL5mJO-.js">
12
+ <link rel="modulepreload" href="/_app/immutable/chunks/DMkZpdF2.js">
13
+ <link rel="modulepreload" href="/_app/immutable/chunks/CWc5urbQ.js">
14
+ <link rel="modulepreload" href="/_app/immutable/chunks/BgChzWQ1.js">
15
+ </head>
16
+ <body data-sveltekit-preload-data="hover">
17
+ <div style="display: contents">
18
+ <script>
19
+ {
20
+ __sveltekit_16ujgvz = {
21
+ base: ""
22
+ };
23
+
24
+ const element = document.currentScript.parentElement;
25
+
26
+ Promise.all([
27
+ import("/_app/immutable/entry/start.DzuEhzqh.js"),
28
+ import("/_app/immutable/entry/app.DTL5mJO-.js")
29
+ ]).then(([kit, app]) => {
30
+ kit.start(app, element);
31
+ });
32
+ }
33
+ </script>
34
+ </div>
35
+ </body>
36
+ </html>
@@ -0,0 +1,60 @@
1
+ """Cross-process correlation storage using .claude-mpm directory."""
2
+
3
+ import json
4
+ import time
5
+ from pathlib import Path
6
+
7
+
8
+ def get_correlation_dir() -> Path:
9
+ """Get correlation directory in project's .claude-mpm folder."""
10
+ # Use CWD's .claude-mpm directory (where hooks run from)
11
+ cwd = Path.cwd()
12
+ return cwd / ".claude-mpm" / "correlations"
13
+
14
+
15
+ TTL_SECONDS = 3600 # 1 hour
16
+
17
+
18
+ class CorrelationManager:
19
+ """Manages correlation IDs across separate hook processes."""
20
+
21
+ @staticmethod
22
+ def store(session_id: str, tool_call_id: str, tool_name: str) -> None:
23
+ """Store correlation data for later retrieval by post_tool."""
24
+ correlation_dir = get_correlation_dir()
25
+ correlation_dir.mkdir(parents=True, exist_ok=True)
26
+ filepath = correlation_dir / f"correlation_{session_id}.json"
27
+ data = {
28
+ "tool_call_id": tool_call_id,
29
+ "tool_name": tool_name,
30
+ "timestamp": time.time(),
31
+ }
32
+ filepath.write_text(json.dumps(data))
33
+
34
+ @staticmethod
35
+ def retrieve(session_id: str) -> str | None:
36
+ """Retrieve and delete correlation data from temp file."""
37
+ correlation_dir = get_correlation_dir()
38
+ filepath = correlation_dir / f"correlation_{session_id}.json"
39
+ if not filepath.exists():
40
+ return None
41
+ try:
42
+ data = json.loads(filepath.read_text())
43
+ filepath.unlink() # Delete after reading
44
+ return data.get("tool_call_id")
45
+ except (json.JSONDecodeError, OSError):
46
+ return None
47
+
48
+ @staticmethod
49
+ def cleanup_old() -> None:
50
+ """Remove correlation files older than TTL."""
51
+ correlation_dir = get_correlation_dir()
52
+ if not correlation_dir.exists():
53
+ return
54
+ now = time.time()
55
+ for filepath in correlation_dir.glob("correlation_*.json"):
56
+ try:
57
+ if now - filepath.stat().st_mtime > TTL_SECONDS:
58
+ filepath.unlink()
59
+ except OSError:
60
+ pass
@@ -9,6 +9,7 @@ import os
9
9
  import re
10
10
  import subprocess
11
11
  import sys
12
+ import uuid
12
13
  from datetime import datetime, timezone
13
14
  from pathlib import Path
14
15
  from typing import Optional
@@ -94,22 +95,29 @@ class EventHandlers:
94
95
  }
95
96
 
96
97
  # Store prompt for comprehensive response tracking if enabled
97
- if (
98
- self.hook_handler.response_tracking_manager.response_tracking_enabled
99
- and self.hook_handler.response_tracking_manager.track_all_interactions
100
- ):
101
- session_id = event.get("session_id", "")
102
- if session_id:
103
- self.hook_handler.pending_prompts[session_id] = {
104
- "prompt": prompt,
105
- "timestamp": datetime.now(timezone.utc).isoformat(),
106
- "working_directory": working_dir,
107
- }
108
- if DEBUG:
109
- print(
110
- f"Stored prompt for comprehensive tracking: session {session_id[:8]}...",
111
- file=sys.stderr,
112
- )
98
+ try:
99
+ rtm = getattr(self.hook_handler, "response_tracking_manager", None)
100
+ if (
101
+ rtm
102
+ and getattr(rtm, "response_tracking_enabled", False)
103
+ and getattr(rtm, "track_all_interactions", False)
104
+ ):
105
+ session_id = event.get("session_id", "")
106
+ if session_id:
107
+ pending_prompts = getattr(self.hook_handler, "pending_prompts", {})
108
+ pending_prompts[session_id] = {
109
+ "prompt": prompt,
110
+ "timestamp": datetime.now(timezone.utc).isoformat(),
111
+ "working_directory": working_dir,
112
+ }
113
+ if DEBUG:
114
+ print(
115
+ f"Stored prompt for comprehensive tracking: session {session_id[:8]}...",
116
+ file=sys.stderr,
117
+ )
118
+ except Exception:
119
+ # Response tracking is optional - silently continue if it fails
120
+ pass
113
121
 
114
122
  # Emit normalized event (namespace no longer needed with normalized events)
115
123
  self.hook_handler._emit_socketio_event("", "user_prompt", prompt_data)
@@ -134,6 +142,9 @@ class EventHandlers:
134
142
  tool_name = event.get("tool_name", "")
135
143
  tool_input = event.get("tool_input", {})
136
144
 
145
+ # Generate unique tool call ID for correlation with post_tool event
146
+ tool_call_id = str(uuid.uuid4())
147
+
137
148
  # Extract key parameters based on tool type
138
149
  tool_params = extract_tool_parameters(tool_name, tool_input)
139
150
 
@@ -144,6 +155,8 @@ class EventHandlers:
144
155
  working_dir = event.get("cwd", "")
145
156
  git_branch = self._get_git_branch(working_dir) if working_dir else "Unknown"
146
157
 
158
+ timestamp = datetime.now(timezone.utc).isoformat()
159
+
147
160
  pre_tool_data = {
148
161
  "tool_name": tool_name,
149
162
  "operation_type": operation_type,
@@ -151,15 +164,27 @@ class EventHandlers:
151
164
  "session_id": event.get("session_id", ""),
152
165
  "working_directory": working_dir,
153
166
  "git_branch": git_branch,
154
- "timestamp": datetime.now(timezone.utc).isoformat(),
167
+ "timestamp": timestamp,
155
168
  "parameter_count": len(tool_input) if isinstance(tool_input, dict) else 0,
156
169
  "is_file_operation": tool_name
157
170
  in ["Write", "Edit", "MultiEdit", "Read", "LS", "Glob"],
158
171
  "is_execution": tool_name in ["Bash", "NotebookEdit"],
159
172
  "is_delegation": tool_name == "Task",
160
173
  "security_risk": assess_security_risk(tool_name, tool_input),
174
+ "correlation_id": tool_call_id, # Add correlation_id for pre/post correlation
161
175
  }
162
176
 
177
+ # Store tool_call_id using CorrelationManager for cross-process retrieval
178
+ if session_id:
179
+ from .correlation_manager import CorrelationManager
180
+
181
+ CorrelationManager.store(session_id, tool_call_id, tool_name)
182
+ if DEBUG:
183
+ print(
184
+ f" - Generated tool_call_id: {tool_call_id[:8]}... for session {session_id[:8]}...",
185
+ file=sys.stderr,
186
+ )
187
+
163
188
  # Add delegation-specific data if this is a Task tool
164
189
  if tool_name == "Task" and isinstance(tool_input, dict):
165
190
  self._handle_task_delegation(tool_input, pre_tool_data, session_id)
@@ -226,8 +251,11 @@ class EventHandlers:
226
251
  f" - Request data keys: {list(request_data.keys())}",
227
252
  file=sys.stderr,
228
253
  )
254
+ delegation_requests = getattr(
255
+ self.hook_handler, "delegation_requests", {}
256
+ )
229
257
  print(
230
- f" - delegation_requests size: {len(self.hook_handler.delegation_requests)}",
258
+ f" - delegation_requests size: {len(delegation_requests)}",
231
259
  file=sys.stderr,
232
260
  )
233
261
 
@@ -239,9 +267,13 @@ class EventHandlers:
239
267
  )
240
268
 
241
269
  # Trigger memory pre-delegation hook
242
- self.hook_handler.memory_hook_manager.trigger_pre_delegation_hook(
243
- agent_type, tool_input, session_id
244
- )
270
+ try:
271
+ mhm = getattr(self.hook_handler, "memory_hook_manager", None)
272
+ if mhm and hasattr(mhm, "trigger_pre_delegation_hook"):
273
+ mhm.trigger_pre_delegation_hook(agent_type, tool_input, session_id)
274
+ except Exception:
275
+ # Memory hooks are optional
276
+ pass
245
277
 
246
278
  # Emit a subagent_start event for better tracking
247
279
  subagent_start_data = {
@@ -375,6 +407,7 @@ class EventHandlers:
375
407
  """
376
408
  tool_name = event.get("tool_name", "")
377
409
  exit_code = event.get("exit_code", 0)
410
+ session_id = event.get("session_id", "")
378
411
 
379
412
  # Extract result data
380
413
  result_data = extract_tool_results(event)
@@ -386,6 +419,16 @@ class EventHandlers:
386
419
  working_dir = event.get("cwd", "")
387
420
  git_branch = self._get_git_branch(working_dir) if working_dir else "Unknown"
388
421
 
422
+ # Retrieve tool_call_id using CorrelationManager for cross-process correlation
423
+ from .correlation_manager import CorrelationManager
424
+
425
+ tool_call_id = CorrelationManager.retrieve(session_id) if session_id else None
426
+ if DEBUG and tool_call_id:
427
+ print(
428
+ f" - Retrieved tool_call_id: {tool_call_id[:8]}... for session {session_id[:8]}...",
429
+ file=sys.stderr,
430
+ )
431
+
389
432
  post_tool_data = {
390
433
  "tool_name": tool_name,
391
434
  "exit_code": exit_code,
@@ -399,7 +442,7 @@ class EventHandlers:
399
442
  ),
400
443
  "duration_ms": duration,
401
444
  "result_summary": result_data,
402
- "session_id": event.get("session_id", ""),
445
+ "session_id": session_id,
403
446
  "working_directory": working_dir,
404
447
  "git_branch": git_branch,
405
448
  "timestamp": datetime.now(timezone.utc).isoformat(),
@@ -412,20 +455,42 @@ class EventHandlers:
412
455
  ),
413
456
  }
414
457
 
458
+ # Include full output for file operations (Read, Edit, Write)
459
+ # so frontend can display file content
460
+ if tool_name in ("Read", "Edit", "Write", "Grep", "Glob") and "output" in event:
461
+ post_tool_data["output"] = event["output"]
462
+
463
+ # Add correlation_id if available for correlation with pre_tool
464
+ if tool_call_id:
465
+ post_tool_data["correlation_id"] = tool_call_id
466
+
415
467
  # Handle Task delegation completion for memory hooks and response tracking
416
468
  if tool_name == "Task":
417
469
  session_id = event.get("session_id", "")
418
470
  agent_type = self.hook_handler._get_delegation_agent_type(session_id)
419
471
 
420
472
  # Trigger memory post-delegation hook
421
- self.hook_handler.memory_hook_manager.trigger_post_delegation_hook(
422
- agent_type, event, session_id
423
- )
473
+ try:
474
+ mhm = getattr(self.hook_handler, "memory_hook_manager", None)
475
+ if mhm and hasattr(mhm, "trigger_post_delegation_hook"):
476
+ mhm.trigger_post_delegation_hook(agent_type, event, session_id)
477
+ except Exception:
478
+ # Memory hooks are optional
479
+ pass
424
480
 
425
481
  # Track agent response if response tracking is enabled
426
- self.hook_handler.response_tracking_manager.track_agent_response(
427
- session_id, agent_type, event, self.hook_handler.delegation_requests
428
- )
482
+ try:
483
+ rtm = getattr(self.hook_handler, "response_tracking_manager", None)
484
+ if rtm and hasattr(rtm, "track_agent_response"):
485
+ delegation_requests = getattr(
486
+ self.hook_handler, "delegation_requests", {}
487
+ )
488
+ rtm.track_agent_response(
489
+ session_id, agent_type, event, delegation_requests
490
+ )
491
+ except Exception:
492
+ # Response tracking is optional
493
+ pass
429
494
 
430
495
  self.hook_handler._emit_socketio_event("", "post_tool", post_tool_data)
431
496
 
@@ -486,9 +551,14 @@ class EventHandlers:
486
551
  self._log_stop_event_debug(event, session_id, metadata)
487
552
 
488
553
  # Track response if enabled
489
- self.hook_handler.response_tracking_manager.track_stop_response(
490
- event, session_id, metadata, self.hook_handler.pending_prompts
491
- )
554
+ try:
555
+ rtm = getattr(self.hook_handler, "response_tracking_manager", None)
556
+ if rtm and hasattr(rtm, "track_stop_response"):
557
+ pending_prompts = getattr(self.hook_handler, "pending_prompts", {})
558
+ rtm.track_stop_response(event, session_id, metadata, pending_prompts)
559
+ except Exception:
560
+ # Response tracking is optional
561
+ pass
492
562
 
493
563
  # Emit stop event to Socket.IO
494
564
  self._emit_stop_event(event, session_id, metadata)
@@ -511,15 +581,27 @@ class EventHandlers:
511
581
  self, event: dict, session_id: str, metadata: dict
512
582
  ) -> None:
513
583
  """Log debug information for stop events."""
584
+ try:
585
+ rtm = getattr(self.hook_handler, "response_tracking_manager", None)
586
+ tracking_enabled = (
587
+ getattr(rtm, "response_tracking_enabled", False) if rtm else False
588
+ )
589
+ tracker_exists = (
590
+ getattr(rtm, "response_tracker", None) is not None if rtm else False
591
+ )
592
+
593
+ print(
594
+ f" - response_tracking_enabled: {tracking_enabled}",
595
+ file=sys.stderr,
596
+ )
597
+ print(
598
+ f" - response_tracker exists: {tracker_exists}",
599
+ file=sys.stderr,
600
+ )
601
+ except Exception:
602
+ # If debug logging fails, just skip it
603
+ pass
514
604
 
515
- print(
516
- f" - response_tracking_enabled: {self.hook_handler.response_tracking_manager.response_tracking_enabled}",
517
- file=sys.stderr,
518
- )
519
- print(
520
- f" - response_tracker exists: {self.hook_handler.response_tracking_manager.response_tracker is not None}",
521
- file=sys.stderr,
522
- )
523
605
  print(
524
606
  f" - session_id: {session_id[:8] if session_id else 'None'}...",
525
607
  file=sys.stderr,
@@ -567,15 +649,22 @@ class EventHandlers:
567
649
  git_branch: str,
568
650
  ):
569
651
  """Handle response tracking for subagent stop events with fuzzy matching."""
570
- if not (
571
- self.hook_handler.response_tracking_manager.response_tracking_enabled
572
- and self.hook_handler.response_tracking_manager.response_tracker
573
- ):
652
+ try:
653
+ rtm = getattr(self.hook_handler, "response_tracking_manager", None)
654
+ if not (
655
+ rtm
656
+ and getattr(rtm, "response_tracking_enabled", False)
657
+ and getattr(rtm, "response_tracker", None)
658
+ ):
659
+ return
660
+ except Exception:
661
+ # Response tracking is optional
574
662
  return
575
663
 
576
664
  try:
577
665
  # Get the original request data (with fuzzy matching fallback)
578
- request_info = self.hook_handler.delegation_requests.get(session_id)
666
+ delegation_requests = getattr(self.hook_handler, "delegation_requests", {})
667
+ request_info = delegation_requests.get(session_id)
579
668
 
580
669
  # If exact match fails, try partial matching
581
670
  if not request_info and session_id:
@@ -585,7 +674,7 @@ class EventHandlers:
585
674
  file=sys.stderr,
586
675
  )
587
676
  # Try to find a session that matches the first 8-16 characters
588
- for stored_sid in list(self.hook_handler.delegation_requests.keys()):
677
+ for stored_sid in list(delegation_requests.keys()):
589
678
  if (
590
679
  stored_sid.startswith(session_id[:8])
591
680
  or session_id.startswith(stored_sid[:8])
@@ -600,17 +689,13 @@ class EventHandlers:
600
689
  f" - ✅ Fuzzy match found: {stored_sid[:16]}...",
601
690
  file=sys.stderr,
602
691
  )
603
- request_info = self.hook_handler.delegation_requests.get(
604
- stored_sid
605
- )
692
+ request_info = delegation_requests.get(stored_sid)
606
693
  # Update the key to use the current session_id for consistency
607
694
  if request_info:
608
- self.hook_handler.delegation_requests[session_id] = (
609
- request_info
610
- )
695
+ delegation_requests[session_id] = request_info
611
696
  # Optionally remove the old key to avoid duplicates
612
697
  if stored_sid != session_id:
613
- del self.hook_handler.delegation_requests[stored_sid]
698
+ del delegation_requests[stored_sid]
614
699
  break
615
700
 
616
701
  if request_info:
@@ -658,23 +743,31 @@ class EventHandlers:
658
743
  )
659
744
 
660
745
  # Track the response
661
- file_path = self.hook_handler.response_tracking_manager.response_tracker.track_response(
662
- agent_name=agent_type,
663
- request=full_request,
664
- response=response_text,
665
- session_id=session_id,
666
- metadata=metadata,
746
+ rtm = getattr(self.hook_handler, "response_tracking_manager", None)
747
+ response_tracker = (
748
+ getattr(rtm, "response_tracker", None) if rtm else None
667
749
  )
668
-
669
- if file_path and DEBUG:
670
- print(
671
- f"✅ Tracked {agent_type} agent response on SubagentStop: {file_path.name}",
672
- file=sys.stderr,
750
+ if response_tracker and hasattr(response_tracker, "track_response"):
751
+ file_path = response_tracker.track_response(
752
+ agent_name=agent_type,
753
+ request=full_request,
754
+ response=response_text,
755
+ session_id=session_id,
756
+ metadata=metadata,
673
757
  )
674
758
 
759
+ if file_path and DEBUG:
760
+ print(
761
+ f"✅ Tracked {agent_type} agent response on SubagentStop: {file_path.name}",
762
+ file=sys.stderr,
763
+ )
764
+
675
765
  # Clean up the request data
676
- if session_id in self.hook_handler.delegation_requests:
677
- del self.hook_handler.delegation_requests[session_id]
766
+ delegation_requests = getattr(
767
+ self.hook_handler, "delegation_requests", {}
768
+ )
769
+ if session_id in delegation_requests:
770
+ del delegation_requests[session_id]
678
771
 
679
772
  elif DEBUG:
680
773
  print(
@@ -698,9 +791,14 @@ class EventHandlers:
698
791
  - Essential for comprehensive monitoring of Claude interactions
699
792
  """
700
793
  # Track the response for logging
701
- self.hook_handler.response_tracking_manager.track_assistant_response(
702
- event, self.hook_handler.pending_prompts
703
- )
794
+ try:
795
+ rtm = getattr(self.hook_handler, "response_tracking_manager", None)
796
+ if rtm and hasattr(rtm, "track_assistant_response"):
797
+ pending_prompts = getattr(self.hook_handler, "pending_prompts", {})
798
+ rtm.track_assistant_response(event, pending_prompts)
799
+ except Exception:
800
+ # Response tracking is optional
801
+ pass
704
802
 
705
803
  # Get working directory and git branch
706
804
  working_dir = event.get("cwd", "")
@@ -730,16 +828,21 @@ class EventHandlers:
730
828
  }
731
829
 
732
830
  # Check if this is a response to a tracked prompt
733
- if session_id in self.hook_handler.pending_prompts:
734
- prompt_data = self.hook_handler.pending_prompts[session_id]
735
- assistant_response_data["original_prompt"] = prompt_data.get("prompt", "")[
736
- :200
737
- ]
738
- assistant_response_data["prompt_timestamp"] = prompt_data.get(
739
- "timestamp", ""
740
- )
741
- assistant_response_data["is_tracked_response"] = True
742
- else:
831
+ try:
832
+ pending_prompts = getattr(self.hook_handler, "pending_prompts", {})
833
+ if session_id in pending_prompts:
834
+ prompt_data = pending_prompts[session_id]
835
+ assistant_response_data["original_prompt"] = prompt_data.get(
836
+ "prompt", ""
837
+ )[:200]
838
+ assistant_response_data["prompt_timestamp"] = prompt_data.get(
839
+ "timestamp", ""
840
+ )
841
+ assistant_response_data["is_tracked_response"] = True
842
+ else:
843
+ assistant_response_data["is_tracked_response"] = False
844
+ except Exception:
845
+ # If prompt lookup fails, just mark as not tracked
743
846
  assistant_response_data["is_tracked_response"] = False
744
847
 
745
848
  # Debug logging
@@ -753,3 +856,33 @@ class EventHandlers:
753
856
  self.hook_handler._emit_socketio_event(
754
857
  "", "assistant_response", assistant_response_data
755
858
  )
859
+
860
+ def handle_session_start_fast(self, event):
861
+ """Handle session start events for tracking conversation sessions.
862
+
863
+ WHY track session starts:
864
+ - Provides visibility into new conversation sessions
865
+ - Enables tracking of session lifecycle and duration
866
+ - Useful for monitoring concurrent sessions and resource usage
867
+ """
868
+ session_id = event.get("session_id", "")
869
+ working_dir = event.get("cwd", "")
870
+ git_branch = self._get_git_branch(working_dir) if working_dir else "Unknown"
871
+
872
+ session_start_data = {
873
+ "session_id": session_id,
874
+ "working_directory": working_dir,
875
+ "git_branch": git_branch,
876
+ "timestamp": datetime.now(timezone.utc).isoformat(),
877
+ "hook_event_name": "SessionStart",
878
+ }
879
+
880
+ # Debug logging
881
+ if DEBUG:
882
+ print(
883
+ f"Hook handler: Processing SessionStart - session: '{session_id}'",
884
+ file=sys.stderr,
885
+ )
886
+
887
+ # Emit normalized event
888
+ self.hook_handler._emit_socketio_event("", "session_start", session_start_data)