claude-mpm 5.6.4__py3-none-any.whl → 5.6.5__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 (43) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  3. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-314.pyc +0 -0
  4. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  5. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-314.pyc +0 -0
  6. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  7. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  8. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-314.pyc +0 -0
  9. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  10. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-314.pyc +0 -0
  11. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-314.pyc +0 -0
  12. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  13. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-314.pyc +0 -0
  14. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  15. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-314.pyc +0 -0
  16. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  17. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-314.pyc +0 -0
  18. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +29 -30
  19. claude_mpm/hooks/claude_hooks/memory_integration.py +30 -21
  20. claude_mpm/hooks/claude_hooks/response_tracking.py +39 -58
  21. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  22. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-314.pyc +0 -0
  23. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  24. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-314.pyc +0 -0
  25. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  26. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-314.pyc +0 -0
  27. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  28. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-314.pyc +0 -0
  29. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  30. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-314.pyc +0 -0
  31. claude_mpm/hooks/claude_hooks/services/connection_manager.py +23 -28
  32. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +22 -26
  33. claude_mpm/hooks/claude_hooks/services/state_manager.py +23 -36
  34. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +47 -73
  35. claude_mpm/hooks/session_resume_hook.py +22 -18
  36. claude_mpm/hooks/templates/pre_tool_use_template.py +10 -2
  37. {claude_mpm-5.6.4.dist-info → claude_mpm-5.6.5.dist-info}/METADATA +1 -1
  38. {claude_mpm-5.6.4.dist-info → claude_mpm-5.6.5.dist-info}/RECORD +43 -17
  39. {claude_mpm-5.6.4.dist-info → claude_mpm-5.6.5.dist-info}/WHEEL +0 -0
  40. {claude_mpm-5.6.4.dist-info → claude_mpm-5.6.5.dist-info}/entry_points.txt +0 -0
  41. {claude_mpm-5.6.4.dist-info → claude_mpm-5.6.5.dist-info}/licenses/LICENSE +0 -0
  42. {claude_mpm-5.6.4.dist-info → claude_mpm-5.6.5.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  43. {claude_mpm-5.6.4.dist-info → claude_mpm-5.6.5.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION CHANGED
@@ -1 +1 @@
1
- 5.6.4
1
+ 5.6.5
@@ -22,7 +22,7 @@ USAGE:
22
22
  threshold_crossed = auto_pause.on_usage_update(metadata["usage"])
23
23
  if threshold_crossed:
24
24
  warning = auto_pause.emit_threshold_warning(threshold_crossed)
25
- print(f"\n⚠️ {warning}", file=sys.stderr)
25
+ _log(f"\n⚠️ {warning}")
26
26
 
27
27
  # Record actions during pause mode
28
28
  if auto_pause.is_pause_active():
@@ -34,7 +34,6 @@ USAGE:
34
34
  """
35
35
 
36
36
  import os
37
- import sys
38
37
  from datetime import datetime, timezone
39
38
  from pathlib import Path
40
39
  from typing import Any, Dict, Optional
@@ -45,6 +44,15 @@ from claude_mpm.services.infrastructure.context_usage_tracker import (
45
44
  ContextUsageTracker,
46
45
  )
47
46
 
47
+ # Try to import _log from hook_handler, fall back to no-op
48
+ try:
49
+ from claude_mpm.hooks.claude_hooks.hook_handler import _log
50
+ except ImportError:
51
+
52
+ def _log(msg: str) -> None:
53
+ pass # Silent fallback
54
+
55
+
48
56
  logger = get_logger(__name__)
49
57
 
50
58
  # Debug mode
@@ -100,11 +108,10 @@ class AutoPauseHandler:
100
108
  self._previous_threshold = current_state.threshold_reached
101
109
 
102
110
  if DEBUG:
103
- print(
111
+ _log(
104
112
  f"AutoPauseHandler initialized: "
105
113
  f"{current_state.percentage_used:.1f}% context used, "
106
- f"threshold: {current_state.threshold_reached}",
107
- file=sys.stderr,
114
+ f"threshold: {current_state.threshold_reached}"
108
115
  )
109
116
  except Exception as e:
110
117
  logger.error(f"Failed to initialize AutoPauseHandler: {e}")
@@ -169,10 +176,9 @@ class AutoPauseHandler:
169
176
  self._previous_threshold = current_threshold
170
177
 
171
178
  if DEBUG:
172
- print(
179
+ _log(
173
180
  f"Context threshold crossed: {current_threshold} "
174
- f"({state.percentage_used:.1f}%)",
175
- file=sys.stderr,
181
+ f"({state.percentage_used:.1f}%)"
176
182
  )
177
183
 
178
184
  # Trigger auto-pause if threshold reached
@@ -184,7 +190,7 @@ class AutoPauseHandler:
184
190
  except Exception as e:
185
191
  logger.error(f"Failed to update usage: {e}")
186
192
  if DEBUG:
187
- print(f"❌ Usage update failed: {e}", file=sys.stderr)
193
+ _log(f"❌ Usage update failed: {e}")
188
194
  # Don't propagate error - auto-pause is optional
189
195
  return None
190
196
 
@@ -220,12 +226,12 @@ class AutoPauseHandler:
220
226
  )
221
227
 
222
228
  if DEBUG:
223
- print(f"Recorded tool call during pause: {tool_name}", file=sys.stderr)
229
+ _log(f"Recorded tool call during pause: {tool_name}")
224
230
 
225
231
  except Exception as e:
226
232
  logger.error(f"Failed to record tool call: {e}")
227
233
  if DEBUG:
228
- print(f"❌ Failed to record tool call: {e}", file=sys.stderr)
234
+ _log(f"❌ Failed to record tool call: {e}")
229
235
 
230
236
  def on_assistant_response(self, response_summary: str) -> None:
231
237
  """Record an assistant response if auto-pause is active.
@@ -257,15 +263,14 @@ class AutoPauseHandler:
257
263
  )
258
264
 
259
265
  if DEBUG:
260
- print(
261
- f"Recorded assistant response during pause (length: {len(summary)})",
262
- file=sys.stderr,
266
+ _log(
267
+ f"Recorded assistant response during pause (length: {len(summary)})"
263
268
  )
264
269
 
265
270
  except Exception as e:
266
271
  logger.error(f"Failed to record assistant response: {e}")
267
272
  if DEBUG:
268
- print(f"❌ Failed to record assistant response: {e}", file=sys.stderr)
273
+ _log(f"❌ Failed to record assistant response: {e}")
269
274
 
270
275
  def on_user_message(self, message_summary: str) -> None:
271
276
  """Record a user message if auto-pause is active.
@@ -297,15 +302,12 @@ class AutoPauseHandler:
297
302
  )
298
303
 
299
304
  if DEBUG:
300
- print(
301
- f"Recorded user message during pause (length: {len(summary)})",
302
- file=sys.stderr,
303
- )
305
+ _log(f"Recorded user message during pause (length: {len(summary)})")
304
306
 
305
307
  except Exception as e:
306
308
  logger.error(f"Failed to record user message: {e}")
307
309
  if DEBUG:
308
- print(f"❌ Failed to record user message: {e}", file=sys.stderr)
310
+ _log(f"❌ Failed to record user message: {e}")
309
311
 
310
312
  def on_session_end(self) -> Optional[Path]:
311
313
  """Called when session ends. Finalizes any active pause.
@@ -318,7 +320,7 @@ class AutoPauseHandler:
318
320
  """
319
321
  if not self.is_pause_active():
320
322
  if DEBUG:
321
- print("No active pause to finalize", file=sys.stderr)
323
+ _log("No active pause to finalize")
322
324
  return None
323
325
 
324
326
  try:
@@ -326,14 +328,14 @@ class AutoPauseHandler:
326
328
  session_path = self.pause_manager.finalize_pause(create_full_snapshot=True)
327
329
 
328
330
  if session_path and DEBUG:
329
- print(f"✅ Session finalized: {session_path.name}", file=sys.stderr)
331
+ _log(f"✅ Session finalized: {session_path.name}")
330
332
 
331
333
  return session_path
332
334
 
333
335
  except Exception as e:
334
336
  logger.error(f"Failed to finalize pause session: {e}")
335
337
  if DEBUG:
336
- print(f"❌ Failed to finalize pause: {e}", file=sys.stderr)
338
+ _log(f"❌ Failed to finalize pause: {e}")
337
339
  raise
338
340
 
339
341
  def is_pause_active(self) -> bool:
@@ -417,9 +419,7 @@ class AutoPauseHandler:
417
419
  # Check if pause is already active
418
420
  if self.is_pause_active():
419
421
  if DEBUG:
420
- print(
421
- "Auto-pause already active, skipping trigger", file=sys.stderr
422
- )
422
+ _log("Auto-pause already active, skipping trigger")
423
423
  return
424
424
 
425
425
  # Start incremental pause
@@ -429,16 +429,15 @@ class AutoPauseHandler:
429
429
  )
430
430
 
431
431
  if DEBUG:
432
- print(
432
+ _log(
433
433
  f"✅ Auto-pause triggered: {session_id} "
434
- f"({state.percentage_used:.1f}% context used)",
435
- file=sys.stderr,
434
+ f"({state.percentage_used:.1f}% context used)"
436
435
  )
437
436
 
438
437
  except Exception as e:
439
438
  logger.error(f"Failed to trigger auto-pause: {e}")
440
439
  if DEBUG:
441
- print(f"❌ Failed to trigger auto-pause: {e}", file=sys.stderr)
440
+ _log(f"❌ Failed to trigger auto-pause: {e}")
442
441
  # Don't propagate - auto-pause is optional
443
442
 
444
443
  def _summarize_dict(
@@ -7,7 +7,16 @@ including pre and post delegation hooks.
7
7
 
8
8
  import logging
9
9
  import os
10
- import sys
10
+ from pathlib import Path
11
+
12
+ # Try to import _log from hook_handler, fall back to no-op
13
+ try:
14
+ from claude_mpm.hooks.claude_hooks.hook_handler import _log
15
+ except ImportError:
16
+
17
+ def _log(msg: str) -> None:
18
+ pass # Silent fallback
19
+
11
20
 
12
21
  # Install-type-aware logging configuration BEFORE kuzu-memory imports
13
22
  # This overrides kuzu-memory's WARNING-level basicConfig (fixes 1M-445)
@@ -28,11 +37,15 @@ try:
28
37
  DeploymentContext.DEVELOPMENT,
29
38
  DeploymentContext.EDITABLE_INSTALL,
30
39
  ):
40
+ # Write logs to file instead of stderr to avoid hook errors
41
+ log_dir = Path.home() / ".claude-mpm"
42
+ log_dir.mkdir(parents=True, exist_ok=True)
43
+ log_file = log_dir / "hooks.log"
31
44
  logging.basicConfig(
32
45
  level=logging.INFO,
33
46
  format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
34
47
  force=True, # Python 3.8+ - reconfigures root logger
35
- stream=sys.stderr,
48
+ filename=str(log_file),
36
49
  )
37
50
  except ImportError:
38
51
  # Fallback: if unified_paths not available, check suppression before configuring
@@ -40,11 +53,15 @@ except ImportError:
40
53
  is_suppressed = root_logger.level > logging.CRITICAL
41
54
 
42
55
  if not is_suppressed:
56
+ # Write logs to file instead of stderr to avoid hook errors
57
+ log_dir = Path.home() / ".claude-mpm"
58
+ log_dir.mkdir(parents=True, exist_ok=True)
59
+ log_file = log_dir / "hooks.log"
43
60
  logging.basicConfig(
44
61
  level=logging.INFO,
45
62
  format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
46
63
  force=True,
47
- stream=sys.stderr,
64
+ filename=str(log_file),
48
65
  )
49
66
  from datetime import datetime, timezone
50
67
  from typing import Optional
@@ -71,7 +88,7 @@ try:
71
88
  except Exception as e:
72
89
  # Catch all exceptions to prevent any import errors from breaking the handler
73
90
  if DEBUG:
74
- print(f"Memory hooks not available: {e}", file=sys.stderr)
91
+ _log(f"Memory hooks not available: {e}")
75
92
  MEMORY_HOOKS_AVAILABLE = False
76
93
 
77
94
 
@@ -105,10 +122,7 @@ class MemoryHookManager:
105
122
  # Only initialize if memory system is enabled
106
123
  if not config.get("memory.enabled", True):
107
124
  if DEBUG:
108
- print(
109
- "Memory system disabled - skipping hook initialization",
110
- file=sys.stderr,
111
- )
125
+ _log("Memory system disabled - skipping hook initialization")
112
126
  return
113
127
 
114
128
  # Initialize pre-delegation hook for memory injection
@@ -126,14 +140,11 @@ class MemoryHookManager:
126
140
  hooks_info.append("pre-delegation")
127
141
  if self.post_delegation_hook:
128
142
  hooks_info.append("post-delegation")
129
- print(
130
- f"✅ Memory hooks initialized: {', '.join(hooks_info)}",
131
- file=sys.stderr,
132
- )
143
+ _log(f"✅ Memory hooks initialized: {', '.join(hooks_info)}")
133
144
 
134
145
  except Exception as e:
135
146
  if DEBUG:
136
- print(f"❌ Failed to initialize memory hooks: {e}", file=sys.stderr)
147
+ _log(f"❌ Failed to initialize memory hooks: {e}")
137
148
  # Don't fail the entire handler - memory system is optional
138
149
 
139
150
  def trigger_pre_delegation_hook(
@@ -182,14 +193,13 @@ class MemoryHookManager:
182
193
 
183
194
  if DEBUG:
184
195
  memory_size = len(memory_section.encode("utf-8"))
185
- print(
186
- f"✅ Injected {memory_size} bytes of memory for agent '{agent_type}'",
187
- file=sys.stderr,
196
+ _log(
197
+ f"✅ Injected {memory_size} bytes of memory for agent '{agent_type}'"
188
198
  )
189
199
 
190
200
  except Exception as e:
191
201
  if DEBUG:
192
- print(f"❌ Memory pre-delegation hook failed: {e}", file=sys.stderr)
202
+ _log(f"❌ Memory pre-delegation hook failed: {e}")
193
203
  # Don't fail the delegation - memory is optional
194
204
 
195
205
  def trigger_post_delegation_hook(
@@ -249,12 +259,11 @@ class MemoryHookManager:
249
259
  if result.success and result.metadata:
250
260
  learnings_extracted = result.metadata.get("learnings_extracted", 0)
251
261
  if learnings_extracted > 0 and DEBUG:
252
- print(
253
- f"✅ Extracted {learnings_extracted} learnings for agent '{agent_type}'",
254
- file=sys.stderr,
262
+ _log(
263
+ f"✅ Extracted {learnings_extracted} learnings for agent '{agent_type}'"
255
264
  )
256
265
 
257
266
  except Exception as e:
258
267
  if DEBUG:
259
- print(f"❌ Memory post-delegation hook failed: {e}", file=sys.stderr)
268
+ _log(f"❌ Memory post-delegation hook failed: {e}")
260
269
  # Don't fail the delegation result - memory is optional
@@ -8,11 +8,19 @@ with their original requests.
8
8
  import json
9
9
  import os
10
10
  import re
11
- import sys
12
11
  from datetime import datetime, timezone
13
12
  from pathlib import Path
14
13
  from typing import Any, Optional
15
14
 
15
+ # Try to import _log from hook_handler, fall back to no-op
16
+ try:
17
+ from claude_mpm.hooks.claude_hooks.hook_handler import _log
18
+ except ImportError:
19
+
20
+ def _log(msg: str) -> None:
21
+ pass # Silent fallback
22
+
23
+
16
24
  # Debug mode
17
25
  DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "true").lower() != "false"
18
26
 
@@ -80,10 +88,7 @@ class ResponseTrackingManager:
80
88
 
81
89
  if not (response_tracking_enabled or response_logging_enabled):
82
90
  if DEBUG:
83
- print(
84
- "Response tracking disabled - skipping initialization",
85
- file=sys.stderr,
86
- )
91
+ _log("Response tracking disabled - skipping initialization")
87
92
  return
88
93
 
89
94
  # Initialize response tracker with config
@@ -101,15 +106,11 @@ class ResponseTrackingManager:
101
106
  if self.track_all_interactions
102
107
  else "Task delegations only"
103
108
  )
104
- print(
105
- f"✅ Response tracking initialized (mode: {mode})", file=sys.stderr
106
- )
109
+ _log(f"✅ Response tracking initialized (mode: {mode})")
107
110
 
108
111
  except Exception as e:
109
112
  if DEBUG:
110
- print(
111
- f"❌ Failed to initialize response tracking: {e}", file=sys.stderr
112
- )
113
+ _log(f"❌ Failed to initialize response tracking: {e}")
113
114
  # Don't fail the entire handler - response tracking is optional
114
115
 
115
116
  def track_agent_response(
@@ -133,9 +134,8 @@ class ResponseTrackingManager:
133
134
  request_info = delegation_requests.get(session_id) # nosec B113 - False positive: dict.get(), not requests library
134
135
  if not request_info:
135
136
  if DEBUG:
136
- print(
137
- f"No request data found for session {session_id}, skipping response tracking",
138
- file=sys.stderr,
137
+ _log(
138
+ f"No request data found for session {session_id}, skipping response tracking"
139
139
  )
140
140
  return
141
141
 
@@ -163,15 +163,11 @@ class ResponseTrackingManager:
163
163
  if json_match:
164
164
  structured_response = json.loads(json_match.group(1))
165
165
  if DEBUG:
166
- print(
167
- f"Extracted structured response from {agent_type} agent",
168
- file=sys.stderr,
169
- )
166
+ _log(f"Extracted structured response from {agent_type} agent")
170
167
  except (json.JSONDecodeError, AttributeError) as e:
171
168
  if DEBUG:
172
- print(
173
- f"No structured JSON response found in {agent_type} agent output: {e}",
174
- file=sys.stderr,
169
+ _log(
170
+ f"No structured JSON response found in {agent_type} agent output: {e}"
175
171
  )
176
172
 
177
173
  # Get the original request (prompt + description)
@@ -220,9 +216,8 @@ class ResponseTrackingManager:
220
216
  if structured_response.get("MEMORIES"):
221
217
  if DEBUG:
222
218
  memories_count = len(structured_response["MEMORIES"])
223
- print(
224
- f"Agent {agent_type} returned MEMORIES field with {memories_count} items",
225
- file=sys.stderr,
219
+ _log(
220
+ f"Agent {agent_type} returned MEMORIES field with {memories_count} items"
226
221
  )
227
222
 
228
223
  # Check if task was completed for logging purposes
@@ -232,9 +227,7 @@ class ResponseTrackingManager:
232
227
  # Log files modified for debugging
233
228
  if DEBUG and structured_response.get("files_modified"):
234
229
  files = [f["file"] for f in structured_response["files_modified"]]
235
- print(
236
- f"Agent {agent_type} modified files: {files}", file=sys.stderr
237
- )
230
+ _log(f"Agent {agent_type} modified files: {files}")
238
231
 
239
232
  # Track the response
240
233
  file_path = self.response_tracker.track_response(
@@ -246,14 +239,12 @@ class ResponseTrackingManager:
246
239
  )
247
240
 
248
241
  if file_path and DEBUG:
249
- print(
250
- f"✅ Tracked response for {agent_type} agent in session {session_id}: {file_path.name}",
251
- file=sys.stderr,
242
+ _log(
243
+ f"✅ Tracked response for {agent_type} agent in session {session_id}: {file_path.name}"
252
244
  )
253
245
  elif DEBUG and not file_path:
254
- print(
255
- f"Response tracking returned None for {agent_type} agent (might be excluded or disabled)",
256
- file=sys.stderr,
246
+ _log(
247
+ f"Response tracking returned None for {agent_type} agent (might be excluded or disabled)"
257
248
  )
258
249
 
259
250
  # Clean up the request data after successful tracking
@@ -261,7 +252,7 @@ class ResponseTrackingManager:
261
252
 
262
253
  except Exception as e:
263
254
  if DEBUG:
264
- print(f"❌ Failed to track agent response: {e}", file=sys.stderr)
255
+ _log(f"❌ Failed to track agent response: {e}")
265
256
  # Don't fail the hook processing - response tracking is optional
266
257
 
267
258
  def track_stop_response(
@@ -286,11 +277,10 @@ class ResponseTrackingManager:
286
277
  prompt_data = pending_prompts.get(session_id)
287
278
 
288
279
  if DEBUG:
289
- print(
290
- f" - output present: {bool(output)} (length: {len(str(output)) if output else 0})",
291
- file=sys.stderr,
280
+ _log(
281
+ f" - output present: {bool(output)} (length: {len(str(output)) if output else 0})"
292
282
  )
293
- print(f" - prompt_data present: {bool(prompt_data)}", file=sys.stderr)
283
+ _log(f" - prompt_data present: {bool(prompt_data)}")
294
284
 
295
285
  if output and prompt_data:
296
286
  # Add prompt timestamp to metadata
@@ -300,10 +290,7 @@ class ResponseTrackingManager:
300
290
  if "stop_reason" in event:
301
291
  metadata["stop_reason"] = event["stop_reason"]
302
292
  if DEBUG:
303
- print(
304
- f" - Captured stop_reason: {event['stop_reason']}",
305
- file=sys.stderr,
306
- )
293
+ _log(f" - Captured stop_reason: {event['stop_reason']}")
307
294
 
308
295
  # Capture Claude API usage data if available
309
296
  # NOTE: Usage data is already captured in metadata by handle_stop_fast()
@@ -324,10 +311,7 @@ class ResponseTrackingManager:
324
311
  total_tokens = usage_data.get(
325
312
  "input_tokens", 0
326
313
  ) + usage_data.get("output_tokens", 0)
327
- print(
328
- f" - Captured usage: {total_tokens} total tokens",
329
- file=sys.stderr,
330
- )
314
+ _log(f" - Captured usage: {total_tokens} total tokens")
331
315
 
332
316
  # Track the main Claude response
333
317
  file_path = self.response_tracker.track_response(
@@ -339,14 +323,14 @@ class ResponseTrackingManager:
339
323
  )
340
324
 
341
325
  if file_path and DEBUG:
342
- print(f" - Response tracked to: {file_path}", file=sys.stderr)
326
+ _log(f" - Response tracked to: {file_path}")
343
327
 
344
328
  # Clean up pending prompt
345
329
  del pending_prompts[session_id]
346
330
 
347
331
  except Exception as e:
348
332
  if DEBUG:
349
- print(f"Error tracking stop response: {e}", file=sys.stderr)
333
+ _log(f"Error tracking stop response: {e}")
350
334
 
351
335
  def track_assistant_response(self, event: dict, pending_prompts: dict):
352
336
  """Handle assistant response events for comprehensive response tracking."""
@@ -361,9 +345,8 @@ class ResponseTrackingManager:
361
345
  prompt_data = pending_prompts.get(session_id)
362
346
  if not prompt_data:
363
347
  if DEBUG:
364
- print(
365
- f"No stored prompt for session {session_id[:8]}..., skipping response tracking",
366
- file=sys.stderr,
348
+ _log(
349
+ f"No stored prompt for session {session_id[:8]}..., skipping response tracking"
367
350
  )
368
351
  return
369
352
 
@@ -377,9 +360,8 @@ class ResponseTrackingManager:
377
360
 
378
361
  if not response_content:
379
362
  if DEBUG:
380
- print(
381
- f"No response content in event for session {session_id[:8]}...",
382
- file=sys.stderr,
363
+ _log(
364
+ f"No response content in event for session {session_id[:8]}..."
383
365
  )
384
366
  return
385
367
 
@@ -401,9 +383,8 @@ class ResponseTrackingManager:
401
383
  )
402
384
 
403
385
  if file_path and DEBUG:
404
- print(
405
- f"✅ Tracked Claude response for session {session_id[:8]}...: {file_path.name}",
406
- file=sys.stderr,
386
+ _log(
387
+ f"✅ Tracked Claude response for session {session_id[:8]}...: {file_path.name}"
407
388
  )
408
389
 
409
390
  # Clean up the stored prompt
@@ -411,4 +392,4 @@ class ResponseTrackingManager:
411
392
 
412
393
  except Exception as e:
413
394
  if DEBUG:
414
- print(f"❌ Failed to track assistant response: {e}", file=sys.stderr)
395
+ _log(f"❌ Failed to track assistant response: {e}")