claude-mpm 5.4.96__py3-none-any.whl → 5.6.17__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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/{CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md → CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md} +14 -6
- claude_mpm/agents/PM_INSTRUCTIONS.md +44 -10
- claude_mpm/agents/WORKFLOW.md +2 -0
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- claude_mpm/cli/commands/autotodos.py +45 -5
- claude_mpm/cli/commands/commander.py +216 -0
- claude_mpm/cli/commands/hook_errors.py +60 -60
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +5 -3
- claude_mpm/cli/executor.py +32 -17
- claude_mpm/cli/parsers/base_parser.py +17 -0
- claude_mpm/cli/parsers/commander_parser.py +116 -0
- claude_mpm/cli/parsers/run_parser.py +10 -0
- claude_mpm/cli/parsers/skill_source_parser.py +4 -0
- claude_mpm/cli/parsers/skills_parser.py +5 -0
- claude_mpm/cli/startup.py +124 -3
- claude_mpm/cli/startup_display.py +2 -1
- claude_mpm/cli/utils.py +7 -3
- claude_mpm/commander/__init__.py +78 -0
- claude_mpm/commander/adapters/__init__.py +60 -0
- claude_mpm/commander/adapters/auggie.py +260 -0
- claude_mpm/commander/adapters/base.py +288 -0
- claude_mpm/commander/adapters/claude_code.py +392 -0
- claude_mpm/commander/adapters/codex.py +237 -0
- claude_mpm/commander/adapters/communication.py +366 -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/__init__.py +16 -0
- claude_mpm/commander/api/app.py +121 -0
- claude_mpm/commander/api/errors.py +133 -0
- claude_mpm/commander/api/routes/__init__.py +8 -0
- claude_mpm/commander/api/routes/events.py +184 -0
- claude_mpm/commander/api/routes/inbox.py +171 -0
- claude_mpm/commander/api/routes/messages.py +148 -0
- claude_mpm/commander/api/routes/projects.py +271 -0
- claude_mpm/commander/api/routes/sessions.py +226 -0
- claude_mpm/commander/api/routes/work.py +296 -0
- claude_mpm/commander/api/schemas.py +186 -0
- claude_mpm/commander/chat/__init__.py +7 -0
- claude_mpm/commander/chat/cli.py +111 -0
- claude_mpm/commander/chat/commands.py +96 -0
- claude_mpm/commander/chat/repl.py +310 -0
- claude_mpm/commander/config.py +49 -0
- claude_mpm/commander/config_loader.py +115 -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 +594 -0
- claude_mpm/commander/env_loader.py +59 -0
- claude_mpm/commander/events/__init__.py +26 -0
- claude_mpm/commander/events/manager.py +332 -0
- claude_mpm/commander/frameworks/__init__.py +12 -0
- claude_mpm/commander/frameworks/base.py +143 -0
- claude_mpm/commander/frameworks/claude_code.py +58 -0
- claude_mpm/commander/frameworks/mpm.py +62 -0
- claude_mpm/commander/inbox/__init__.py +16 -0
- claude_mpm/commander/inbox/dedup.py +128 -0
- claude_mpm/commander/inbox/inbox.py +224 -0
- claude_mpm/commander/inbox/models.py +70 -0
- claude_mpm/commander/instance_manager.py +337 -0
- claude_mpm/commander/llm/__init__.py +6 -0
- claude_mpm/commander/llm/openrouter_client.py +167 -0
- claude_mpm/commander/llm/summarizer.py +70 -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/models/__init__.py +18 -0
- claude_mpm/commander/models/events.py +121 -0
- claude_mpm/commander/models/project.py +162 -0
- claude_mpm/commander/models/work.py +214 -0
- claude_mpm/commander/parsing/__init__.py +20 -0
- claude_mpm/commander/parsing/extractor.py +132 -0
- claude_mpm/commander/parsing/output_parser.py +270 -0
- claude_mpm/commander/parsing/patterns.py +100 -0
- claude_mpm/commander/persistence/__init__.py +11 -0
- claude_mpm/commander/persistence/event_store.py +274 -0
- claude_mpm/commander/persistence/state_store.py +309 -0
- claude_mpm/commander/persistence/work_store.py +164 -0
- claude_mpm/commander/polling/__init__.py +13 -0
- claude_mpm/commander/polling/event_detector.py +104 -0
- claude_mpm/commander/polling/output_buffer.py +49 -0
- claude_mpm/commander/polling/output_poller.py +153 -0
- claude_mpm/commander/project_session.py +268 -0
- claude_mpm/commander/proxy/__init__.py +12 -0
- claude_mpm/commander/proxy/formatter.py +89 -0
- claude_mpm/commander/proxy/output_handler.py +191 -0
- claude_mpm/commander/proxy/relay.py +155 -0
- claude_mpm/commander/registry.py +410 -0
- claude_mpm/commander/runtime/__init__.py +10 -0
- claude_mpm/commander/runtime/executor.py +191 -0
- claude_mpm/commander/runtime/monitor.py +346 -0
- claude_mpm/commander/session/__init__.py +6 -0
- claude_mpm/commander/session/context.py +81 -0
- claude_mpm/commander/session/manager.py +59 -0
- claude_mpm/commander/tmux_orchestrator.py +361 -0
- claude_mpm/commander/web/__init__.py +1 -0
- claude_mpm/commander/work/__init__.py +30 -0
- claude_mpm/commander/work/executor.py +207 -0
- claude_mpm/commander/work/queue.py +405 -0
- claude_mpm/commander/workflow/__init__.py +27 -0
- claude_mpm/commander/workflow/event_handler.py +241 -0
- claude_mpm/commander/workflow/notifier.py +146 -0
- claude_mpm/commands/mpm-config.md +8 -0
- claude_mpm/commands/mpm-doctor.md +8 -0
- claude_mpm/commands/mpm-help.md +8 -0
- claude_mpm/commands/mpm-init.md +8 -0
- claude_mpm/commands/mpm-monitor.md +8 -0
- claude_mpm/commands/mpm-organize.md +8 -0
- claude_mpm/commands/mpm-postmortem.md +8 -0
- claude_mpm/commands/mpm-session-resume.md +8 -0
- claude_mpm/commands/mpm-status.md +8 -0
- claude_mpm/commands/mpm-ticket-view.md +8 -0
- claude_mpm/commands/mpm-version.md +8 -0
- claude_mpm/commands/mpm.md +8 -0
- claude_mpm/config/agent_presets.py +8 -7
- claude_mpm/config/skill_sources.py +16 -0
- claude_mpm/core/claude_runner.py +143 -0
- claude_mpm/core/config.py +32 -19
- claude_mpm/core/logger.py +26 -9
- claude_mpm/core/logging_utils.py +35 -11
- claude_mpm/core/output_style_manager.py +49 -12
- claude_mpm/core/unified_config.py +10 -6
- claude_mpm/core/unified_paths.py +68 -80
- claude_mpm/experimental/cli_enhancements.py +2 -1
- 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__/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-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 +112 -99
- claude_mpm/hooks/claude_hooks/hook_handler.py +81 -88
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +116 -8
- claude_mpm/hooks/claude_hooks/memory_integration.py +51 -31
- claude_mpm/hooks/claude_hooks/response_tracking.py +39 -58
- 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-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 +36 -103
- 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 +43 -16
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/agents/agent_recommendation_service.py +8 -8
- claude_mpm/services/agents/agent_selection_service.py +2 -2
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
- claude_mpm/services/event_log.py +8 -0
- claude_mpm/services/pm_skills_deployer.py +84 -6
- claude_mpm/services/skills/git_skill_source_manager.py +130 -10
- claude_mpm/services/skills/selective_skill_deployer.py +28 -0
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills_deployer.py +31 -5
- claude_mpm/skills/__init__.py +2 -1
- claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
- claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
- claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
- claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
- claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
- claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
- claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
- claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
- claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
- claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
- claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/registry.py +295 -90
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/METADATA +22 -6
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/RECORD +213 -83
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/top_level.txt +0 -0
|
@@ -7,34 +7,62 @@ 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)
|
|
14
|
-
# but respects production install silence
|
|
23
|
+
# but respects production install silence AND startup suppression
|
|
15
24
|
try:
|
|
16
25
|
from claude_mpm.core.unified_paths import DeploymentContext, PathContext
|
|
17
26
|
|
|
18
27
|
context = PathContext.detect_deployment_context()
|
|
19
28
|
|
|
29
|
+
# CRITICAL: Check if root logger is already suppressed (CRITICAL+1 from startup.py)
|
|
30
|
+
# If so, don't call basicConfig as it will reset the level to INFO
|
|
31
|
+
root_logger = logging.getLogger()
|
|
32
|
+
is_suppressed = root_logger.level > logging.CRITICAL # CRITICAL+1 = 51
|
|
33
|
+
|
|
20
34
|
# Only configure verbose logging for development/editable installs
|
|
21
|
-
#
|
|
22
|
-
if context in (
|
|
35
|
+
# AND if logging isn't already suppressed by startup.py
|
|
36
|
+
if not is_suppressed and context in (
|
|
37
|
+
DeploymentContext.DEVELOPMENT,
|
|
38
|
+
DeploymentContext.EDITABLE_INSTALL,
|
|
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"
|
|
23
44
|
logging.basicConfig(
|
|
24
45
|
level=logging.INFO,
|
|
25
46
|
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
26
47
|
force=True, # Python 3.8+ - reconfigures root logger
|
|
27
|
-
|
|
48
|
+
filename=str(log_file),
|
|
28
49
|
)
|
|
29
50
|
except ImportError:
|
|
30
|
-
# Fallback: if unified_paths not available,
|
|
31
|
-
|
|
32
|
-
logging.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
51
|
+
# Fallback: if unified_paths not available, check suppression before configuring
|
|
52
|
+
root_logger = logging.getLogger()
|
|
53
|
+
is_suppressed = root_logger.level > logging.CRITICAL
|
|
54
|
+
|
|
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"
|
|
60
|
+
logging.basicConfig(
|
|
61
|
+
level=logging.INFO,
|
|
62
|
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
63
|
+
force=True,
|
|
64
|
+
filename=str(log_file),
|
|
65
|
+
)
|
|
38
66
|
from datetime import datetime, timezone
|
|
39
67
|
from typing import Optional
|
|
40
68
|
|
|
@@ -60,7 +88,7 @@ try:
|
|
|
60
88
|
except Exception as e:
|
|
61
89
|
# Catch all exceptions to prevent any import errors from breaking the handler
|
|
62
90
|
if DEBUG:
|
|
63
|
-
|
|
91
|
+
_log(f"Memory hooks not available: {e}")
|
|
64
92
|
MEMORY_HOOKS_AVAILABLE = False
|
|
65
93
|
|
|
66
94
|
|
|
@@ -94,10 +122,7 @@ class MemoryHookManager:
|
|
|
94
122
|
# Only initialize if memory system is enabled
|
|
95
123
|
if not config.get("memory.enabled", True):
|
|
96
124
|
if DEBUG:
|
|
97
|
-
|
|
98
|
-
"Memory system disabled - skipping hook initialization",
|
|
99
|
-
file=sys.stderr,
|
|
100
|
-
)
|
|
125
|
+
_log("Memory system disabled - skipping hook initialization")
|
|
101
126
|
return
|
|
102
127
|
|
|
103
128
|
# Initialize pre-delegation hook for memory injection
|
|
@@ -115,14 +140,11 @@ class MemoryHookManager:
|
|
|
115
140
|
hooks_info.append("pre-delegation")
|
|
116
141
|
if self.post_delegation_hook:
|
|
117
142
|
hooks_info.append("post-delegation")
|
|
118
|
-
|
|
119
|
-
f"✅ Memory hooks initialized: {', '.join(hooks_info)}",
|
|
120
|
-
file=sys.stderr,
|
|
121
|
-
)
|
|
143
|
+
_log(f"✅ Memory hooks initialized: {', '.join(hooks_info)}")
|
|
122
144
|
|
|
123
145
|
except Exception as e:
|
|
124
146
|
if DEBUG:
|
|
125
|
-
|
|
147
|
+
_log(f"❌ Failed to initialize memory hooks: {e}")
|
|
126
148
|
# Don't fail the entire handler - memory system is optional
|
|
127
149
|
|
|
128
150
|
def trigger_pre_delegation_hook(
|
|
@@ -171,14 +193,13 @@ class MemoryHookManager:
|
|
|
171
193
|
|
|
172
194
|
if DEBUG:
|
|
173
195
|
memory_size = len(memory_section.encode("utf-8"))
|
|
174
|
-
|
|
175
|
-
f"✅ Injected {memory_size} bytes of memory for agent '{agent_type}'"
|
|
176
|
-
file=sys.stderr,
|
|
196
|
+
_log(
|
|
197
|
+
f"✅ Injected {memory_size} bytes of memory for agent '{agent_type}'"
|
|
177
198
|
)
|
|
178
199
|
|
|
179
200
|
except Exception as e:
|
|
180
201
|
if DEBUG:
|
|
181
|
-
|
|
202
|
+
_log(f"❌ Memory pre-delegation hook failed: {e}")
|
|
182
203
|
# Don't fail the delegation - memory is optional
|
|
183
204
|
|
|
184
205
|
def trigger_post_delegation_hook(
|
|
@@ -238,12 +259,11 @@ class MemoryHookManager:
|
|
|
238
259
|
if result.success and result.metadata:
|
|
239
260
|
learnings_extracted = result.metadata.get("learnings_extracted", 0)
|
|
240
261
|
if learnings_extracted > 0 and DEBUG:
|
|
241
|
-
|
|
242
|
-
f"✅ Extracted {learnings_extracted} learnings for agent '{agent_type}'"
|
|
243
|
-
file=sys.stderr,
|
|
262
|
+
_log(
|
|
263
|
+
f"✅ Extracted {learnings_extracted} learnings for agent '{agent_type}'"
|
|
244
264
|
)
|
|
245
265
|
|
|
246
266
|
except Exception as e:
|
|
247
267
|
if DEBUG:
|
|
248
|
-
|
|
268
|
+
_log(f"❌ Memory post-delegation hook failed: {e}")
|
|
249
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
395
|
+
_log(f"❌ Failed to track assistant response: {e}")
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -20,6 +20,15 @@ import os
|
|
|
20
20
|
import sys
|
|
21
21
|
from datetime import datetime, timezone
|
|
22
22
|
|
|
23
|
+
# Try to import _log from hook_handler, fall back to no-op
|
|
24
|
+
try:
|
|
25
|
+
from claude_mpm.hooks.claude_hooks.hook_handler import _log
|
|
26
|
+
except ImportError:
|
|
27
|
+
|
|
28
|
+
def _log(msg: str) -> None:
|
|
29
|
+
pass # Silent fallback
|
|
30
|
+
|
|
31
|
+
|
|
23
32
|
# Debug mode is enabled by default for better visibility into hook processing
|
|
24
33
|
DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "true").lower() != "false"
|
|
25
34
|
|
|
@@ -94,13 +103,10 @@ class ConnectionManagerService:
|
|
|
94
103
|
try:
|
|
95
104
|
self.connection_pool = get_connection_pool()
|
|
96
105
|
if DEBUG:
|
|
97
|
-
|
|
106
|
+
_log("✅ Modern SocketIO connection pool initialized")
|
|
98
107
|
except Exception as e:
|
|
99
108
|
if DEBUG:
|
|
100
|
-
|
|
101
|
-
f"⚠️ Failed to initialize SocketIO connection pool: {e}",
|
|
102
|
-
file=sys.stderr,
|
|
103
|
-
)
|
|
109
|
+
_log(f"⚠️ Failed to initialize SocketIO connection pool: {e}")
|
|
104
110
|
self.connection_pool = None
|
|
105
111
|
|
|
106
112
|
def emit_event(self, namespace: str, event: str, data: dict):
|
|
@@ -149,10 +155,7 @@ class ConnectionManagerService:
|
|
|
149
155
|
|
|
150
156
|
# Debug log when we detect invalid hook_type for troubleshooting
|
|
151
157
|
if DEBUG:
|
|
152
|
-
|
|
153
|
-
f"⚠️ Invalid hook_type detected, using fallback: {hook_type}",
|
|
154
|
-
file=sys.stderr,
|
|
155
|
-
)
|
|
158
|
+
_log(f"⚠️ Invalid hook_type detected, using fallback: {hook_type}")
|
|
156
159
|
|
|
157
160
|
event_type = hook_type
|
|
158
161
|
else:
|
|
@@ -177,16 +180,12 @@ class ConnectionManagerService:
|
|
|
177
180
|
if DEBUG and event in ["subagent_stop", "pre_tool"]:
|
|
178
181
|
if event == "subagent_stop":
|
|
179
182
|
agent_type = data.get("agent_type", "unknown")
|
|
180
|
-
|
|
181
|
-
f"Hook handler: Publishing SubagentStop for agent '{agent_type}'",
|
|
182
|
-
file=sys.stderr,
|
|
183
|
-
)
|
|
183
|
+
_log(f"Hook handler: Publishing SubagentStop for agent '{agent_type}'")
|
|
184
184
|
elif event == "pre_tool" and data.get("tool_name") == "Task":
|
|
185
185
|
delegation = data.get("delegation_details", {})
|
|
186
186
|
agent_type = delegation.get("agent_type", "unknown")
|
|
187
|
-
|
|
188
|
-
f"Hook handler: Publishing Task delegation to agent '{agent_type}'"
|
|
189
|
-
file=sys.stderr,
|
|
187
|
+
_log(
|
|
188
|
+
f"Hook handler: Publishing Task delegation to agent '{agent_type}'"
|
|
190
189
|
)
|
|
191
190
|
|
|
192
191
|
# Emit through direct Socket.IO connection pool (primary path)
|
|
@@ -196,11 +195,11 @@ class ConnectionManagerService:
|
|
|
196
195
|
# Emit to Socket.IO server directly
|
|
197
196
|
self.connection_pool.emit("mpm_event", claude_event_data)
|
|
198
197
|
if DEBUG:
|
|
199
|
-
|
|
198
|
+
_log(f"✅ Emitted via connection pool: {event}")
|
|
200
199
|
return # Success - no need for fallback
|
|
201
200
|
except Exception as e:
|
|
202
201
|
if DEBUG:
|
|
203
|
-
|
|
202
|
+
_log(f"⚠️ Failed to emit via connection pool: {e}")
|
|
204
203
|
|
|
205
204
|
# HTTP fallback for cross-process communication (when direct calls fail)
|
|
206
205
|
# This replaces EventBus for reliability without the complexity
|
|
@@ -221,22 +220,18 @@ class ConnectionManagerService:
|
|
|
221
220
|
|
|
222
221
|
if response.status_code in [200, 204]:
|
|
223
222
|
if DEBUG:
|
|
224
|
-
|
|
223
|
+
_log("✅ HTTP fallback successful")
|
|
225
224
|
elif DEBUG:
|
|
226
|
-
|
|
227
|
-
f"⚠️ HTTP fallback failed: {response.status_code}",
|
|
228
|
-
file=sys.stderr,
|
|
229
|
-
)
|
|
225
|
+
_log(f"⚠️ HTTP fallback failed: {response.status_code}")
|
|
230
226
|
|
|
231
227
|
except Exception as e:
|
|
232
228
|
if DEBUG:
|
|
233
|
-
|
|
229
|
+
_log(f"⚠️ HTTP fallback error: {e}")
|
|
234
230
|
|
|
235
231
|
# Warn if no emission method is available
|
|
236
232
|
if not self.connection_pool and DEBUG:
|
|
237
|
-
|
|
238
|
-
f"⚠️ No event emission method available for: {claude_event_data.get('event', 'unknown')}"
|
|
239
|
-
file=sys.stderr,
|
|
233
|
+
_log(
|
|
234
|
+
f"⚠️ No event emission method available for: {claude_event_data.get('event', 'unknown')}"
|
|
240
235
|
)
|
|
241
236
|
|
|
242
237
|
def cleanup(self):
|
|
@@ -245,5 +240,5 @@ class ConnectionManagerService:
|
|
|
245
240
|
if self.connection_pool:
|
|
246
241
|
try:
|
|
247
242
|
self.connection_pool.cleanup()
|
|
248
|
-
except Exception:
|
|
243
|
+
except Exception: # nosec B110
|
|
249
244
|
pass # Ignore cleanup errors during destruction
|