claude-mpm 5.6.4__py3-none-any.whl → 5.6.16__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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/PM_INSTRUCTIONS.md +8 -3
- claude_mpm/cli/commands/commander.py +173 -3
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +5 -3
- claude_mpm/cli/parsers/commander_parser.py +41 -8
- claude_mpm/cli/parsers/skill_source_parser.py +4 -0
- claude_mpm/cli/parsers/skills_parser.py +5 -0
- claude_mpm/cli/startup.py +10 -1
- claude_mpm/cli/startup_display.py +2 -1
- claude_mpm/commander/__init__.py +6 -0
- claude_mpm/commander/adapters/__init__.py +32 -3
- claude_mpm/commander/adapters/auggie.py +260 -0
- claude_mpm/commander/adapters/base.py +98 -1
- claude_mpm/commander/adapters/claude_code.py +32 -1
- claude_mpm/commander/adapters/codex.py +237 -0
- claude_mpm/commander/adapters/example_usage.py +310 -0
- claude_mpm/commander/adapters/mpm.py +389 -0
- claude_mpm/commander/adapters/registry.py +204 -0
- claude_mpm/commander/api/app.py +32 -16
- claude_mpm/commander/api/errors.py +21 -0
- claude_mpm/commander/api/routes/messages.py +11 -11
- claude_mpm/commander/api/routes/projects.py +20 -20
- claude_mpm/commander/api/routes/sessions.py +37 -26
- claude_mpm/commander/api/routes/work.py +86 -50
- claude_mpm/commander/api/schemas.py +4 -0
- claude_mpm/commander/chat/cli.py +4 -0
- claude_mpm/commander/core/__init__.py +10 -0
- claude_mpm/commander/core/block_manager.py +325 -0
- claude_mpm/commander/core/response_manager.py +323 -0
- claude_mpm/commander/daemon.py +206 -10
- claude_mpm/commander/env_loader.py +59 -0
- claude_mpm/commander/memory/__init__.py +45 -0
- claude_mpm/commander/memory/compression.py +347 -0
- claude_mpm/commander/memory/embeddings.py +230 -0
- claude_mpm/commander/memory/entities.py +310 -0
- claude_mpm/commander/memory/example_usage.py +290 -0
- claude_mpm/commander/memory/integration.py +325 -0
- claude_mpm/commander/memory/search.py +381 -0
- claude_mpm/commander/memory/store.py +657 -0
- claude_mpm/commander/registry.py +10 -4
- claude_mpm/commander/runtime/monitor.py +32 -2
- claude_mpm/commander/work/executor.py +38 -20
- claude_mpm/commander/workflow/event_handler.py +25 -3
- claude_mpm/config/skill_sources.py +16 -0
- claude_mpm/core/claude_runner.py +143 -0
- claude_mpm/core/config.py +27 -19
- claude_mpm/core/output_style_manager.py +34 -7
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +29 -30
- claude_mpm/hooks/claude_hooks/event_handlers.py +22 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +0 -0
- claude_mpm/hooks/claude_hooks/installer.py +41 -0
- claude_mpm/hooks/claude_hooks/memory_integration.py +30 -21
- claude_mpm/hooks/claude_hooks/response_tracking.py +39 -58
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +23 -28
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +22 -26
- claude_mpm/hooks/claude_hooks/services/state_manager.py +23 -36
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +47 -73
- claude_mpm/hooks/session_resume_hook.py +22 -18
- claude_mpm/hooks/templates/pre_tool_use_template.py +10 -2
- claude_mpm/scripts/claude-hook-handler.sh +5 -5
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/agents/agent_selection_service.py +2 -2
- claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
- claude_mpm/services/skills/git_skill_source_manager.py +79 -8
- claude_mpm/services/skills/selective_skill_deployer.py +28 -0
- claude_mpm/services/skills/skill_discovery_service.py +17 -1
- claude_mpm/services/skills_deployer.py +31 -5
- claude_mpm/skills/__init__.py +2 -1
- claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
- claude_mpm/skills/registry.py +295 -90
- {claude_mpm-5.6.4.dist-info → claude_mpm-5.6.16.dist-info}/METADATA +5 -3
- {claude_mpm-5.6.4.dist-info → claude_mpm-5.6.16.dist-info}/RECORD +116 -58
- {claude_mpm-5.6.4.dist-info → claude_mpm-5.6.16.dist-info}/WHEEL +0 -0
- {claude_mpm-5.6.4.dist-info → claude_mpm-5.6.16.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.6.4.dist-info → claude_mpm-5.6.16.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.6.4.dist-info → claude_mpm-5.6.16.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.6.4.dist-info → claude_mpm-5.6.16.dist-info}/top_level.txt +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
@@ -126,6 +126,15 @@ class EventHandlers:
|
|
|
126
126
|
# Response tracking is optional - silently continue if it fails
|
|
127
127
|
pass
|
|
128
128
|
|
|
129
|
+
# Record user message for auto-pause if active
|
|
130
|
+
auto_pause = getattr(self.hook_handler, "auto_pause_handler", None)
|
|
131
|
+
if auto_pause and auto_pause.is_pause_active():
|
|
132
|
+
try:
|
|
133
|
+
auto_pause.on_user_message(prompt)
|
|
134
|
+
except Exception as e:
|
|
135
|
+
if DEBUG:
|
|
136
|
+
_log(f"Auto-pause user message recording error: {e}")
|
|
137
|
+
|
|
129
138
|
# Emit normalized event (namespace no longer needed with normalized events)
|
|
130
139
|
self.hook_handler._emit_socketio_event("", "user_prompt", prompt_data)
|
|
131
140
|
|
|
@@ -603,6 +612,19 @@ class EventHandlers:
|
|
|
603
612
|
if DEBUG:
|
|
604
613
|
_log(f"Auto-pause error in handle_stop_fast: {e}")
|
|
605
614
|
|
|
615
|
+
# Finalize pause session if active
|
|
616
|
+
try:
|
|
617
|
+
if auto_pause.is_pause_active():
|
|
618
|
+
session_file = auto_pause.on_session_end()
|
|
619
|
+
if session_file:
|
|
620
|
+
if DEBUG:
|
|
621
|
+
_log(
|
|
622
|
+
f"✅ Auto-pause session finalized: {session_file.name}"
|
|
623
|
+
)
|
|
624
|
+
except Exception as e:
|
|
625
|
+
if DEBUG:
|
|
626
|
+
_log(f"❌ Failed to finalize auto-pause session: {e}")
|
|
627
|
+
|
|
606
628
|
# Track response if enabled
|
|
607
629
|
try:
|
|
608
630
|
rtm = getattr(self.hook_handler, "response_tracking_manager", None)
|
|
File without changes
|
|
@@ -537,6 +537,44 @@ main "$@"
|
|
|
537
537
|
except Exception as e:
|
|
538
538
|
self.logger.warning(f"Could not clean up old settings file: {e}")
|
|
539
539
|
|
|
540
|
+
def _fix_status_line(self, settings: Dict) -> None:
|
|
541
|
+
"""Fix statusLine command to handle both output style schema formats.
|
|
542
|
+
|
|
543
|
+
The statusLine command receives input in different formats:
|
|
544
|
+
- Newer format: {"activeOutputStyle": "Claude MPM", ...}
|
|
545
|
+
- Older format: {"output_style": {"name": "Claude MPM"}, ...}
|
|
546
|
+
|
|
547
|
+
This method ensures the jq expression checks both locations.
|
|
548
|
+
|
|
549
|
+
Args:
|
|
550
|
+
settings: The settings dictionary to update
|
|
551
|
+
"""
|
|
552
|
+
if "statusLine" not in settings:
|
|
553
|
+
return
|
|
554
|
+
|
|
555
|
+
status_line = settings.get("statusLine", {})
|
|
556
|
+
if "command" not in status_line:
|
|
557
|
+
return
|
|
558
|
+
|
|
559
|
+
command = status_line["command"]
|
|
560
|
+
|
|
561
|
+
# Pattern to match: '.output_style.name // "default"'
|
|
562
|
+
# We need to update it to: '.output_style.name // .activeOutputStyle // "default"'
|
|
563
|
+
old_pattern = r'\.output_style\.name\s*//\s*"default"'
|
|
564
|
+
new_pattern = '.output_style.name // .activeOutputStyle // "default"'
|
|
565
|
+
|
|
566
|
+
# Check if the command needs updating
|
|
567
|
+
if re.search(old_pattern, command) and ".activeOutputStyle" not in command:
|
|
568
|
+
updated_command = re.sub(old_pattern, new_pattern, command)
|
|
569
|
+
settings["statusLine"]["command"] = updated_command
|
|
570
|
+
self.logger.info(
|
|
571
|
+
"Fixed statusLine command to handle both output style schemas"
|
|
572
|
+
)
|
|
573
|
+
else:
|
|
574
|
+
self.logger.debug(
|
|
575
|
+
"StatusLine command already supports both schemas or not present"
|
|
576
|
+
)
|
|
577
|
+
|
|
540
578
|
def _update_claude_settings(self, hook_script_path: Path) -> None:
|
|
541
579
|
"""Update Claude settings to use the installed hook."""
|
|
542
580
|
self.logger.info("Updating Claude settings...")
|
|
@@ -598,6 +636,9 @@ main "$@"
|
|
|
598
636
|
}
|
|
599
637
|
]
|
|
600
638
|
|
|
639
|
+
# Fix statusLine command to handle both output style schemas
|
|
640
|
+
self._fix_status_line(settings)
|
|
641
|
+
|
|
601
642
|
# Write settings to settings.json
|
|
602
643
|
with self.settings_file.open("w") as f:
|
|
603
644
|
json.dump(settings, f, indent=2)
|
|
@@ -7,7 +7,16 @@ including pre and post delegation hooks.
|
|
|
7
7
|
|
|
8
8
|
import logging
|
|
9
9
|
import os
|
|
10
|
-
import
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
268
|
+
_log(f"❌ Memory post-delegation hook failed: {e}")
|
|
260
269
|
# Don't fail the delegation result - memory is optional
|