-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherror_tracker.py
More file actions
93 lines (77 loc) · 2.62 KB
/
error_tracker.py
File metadata and controls
93 lines (77 loc) · 2.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#!/usr/bin/env python3
# @bigd-hook-meta
# name: error_tracker
# fires_on: PostToolUse
# always_fire: true
# cost_score: 1
"""PostToolUse hook: track consecutive Bash errors → inject lesson reminder after 2 in a row."""
import hashlib
import json
import sys
import time
from pathlib import Path
STATE_FILE = Path("/tmp/claude_error_tracker.json")
THRESHOLD = 2
def fingerprint(command: str, output: str) -> str:
"""Stable hash: command binary + first error keyword found."""
cmd_bin = command.strip().split()[0] if command.strip() else ""
error_sig = ""
for line in output.splitlines():
lo = line.lower()
if any(k in lo for k in ("exit code", "error:", "failed", "refused", "permission denied")):
error_sig = line.strip()[:120]
break
return hashlib.md5(f"{cmd_bin}|{error_sig}".encode()).hexdigest()[:10]
def main():
try:
data = json.load(sys.stdin)
except (json.JSONDecodeError, EOFError):
sys.stdout.write("{}\n")
return
if data.get("tool_name") != "Bash":
sys.stdout.write("{}\n")
return
command = data.get("tool_input", {}).get("command", "")
resp = data.get("tool_response", {})
output = ""
if isinstance(resp, dict):
output = str(resp.get("output", "")) + str(resp.get("stderr", ""))
elif isinstance(resp, str):
output = resp
is_error = any(k in output for k in (
"Error:", "exit code", "Exit code", "FAILED", "failed:", "Connection refused",
"Permission denied", "No such file"
))
if not is_error:
STATE_FILE.unlink(missing_ok=True)
sys.stdout.write("{}\n")
return
state = {}
if STATE_FILE.exists():
try:
state = json.loads(STATE_FILE.read_text())
except Exception:
state = {}
fp = fingerprint(command, output)
if state.get("fp") == fp:
state["count"] = state.get("count", 1) + 1
else:
state = {"fp": fp, "count": 1, "cmd": command[:200], "ts": time.time()}
STATE_FILE.write_text(json.dumps(state))
if state["count"] >= THRESHOLD:
STATE_FILE.unlink(missing_ok=True)
msg = (
f"SAME ERROR {state['count']}x IN A ROW on: `{command[:80]}`. "
"STOP retrying minor variations. Diagnose root cause. "
"After fixing, save a lesson to memory."
)
sys.stdout.write(json.dumps({
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": msg
}
}) + "\n")
return
sys.stdout.write("{}\n")
if __name__ == "__main__":
main()