claude-code-cache-fix 3.0.4 → 3.0.5
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.
- package/package.json +1 -1
- package/tools/quota-statusline.sh +40 -79
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-cache-fix",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.5",
|
|
4
4
|
"description": "Cache optimization proxy and interceptor for Claude Code. Fixes prompt cache bugs, stabilizes prefix, reduces quota burn.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": "./preload.mjs",
|
|
@@ -1,68 +1,43 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# Status line: show quota % and burn rate from
|
|
3
|
-
#
|
|
4
|
-
# No prev file needed — each reading is self-contained
|
|
2
|
+
# Status line: show quota % and burn rate from quota-status.json
|
|
3
|
+
# Written by cache-fix proxy's cache-telemetry extension on every API call.
|
|
5
4
|
|
|
6
5
|
input=$(cat)
|
|
7
6
|
|
|
8
|
-
JSONL="$HOME/.claude/claude-meter.jsonl"
|
|
9
7
|
QS="$HOME/.claude/quota-status.json"
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
elif [ -f "$QS" ]; then
|
|
16
|
-
# Translate quota-status.json into the same shape the Python expects
|
|
17
|
-
last=$(python3 -c "
|
|
18
|
-
import json, pathlib
|
|
19
|
-
qs = json.load(open(pathlib.Path.home() / '.claude' / 'quota-status.json'))
|
|
20
|
-
fh = qs.get('five_hour', {})
|
|
21
|
-
sd = qs.get('seven_day', {})
|
|
22
|
-
print(json.dumps({
|
|
23
|
-
'q5h': fh.get('utilization', 0),
|
|
24
|
-
'q7d': sd.get('utilization', 0),
|
|
25
|
-
'q5h_reset': fh.get('resets_at', 0),
|
|
26
|
-
'q7d_reset': sd.get('resets_at', 0),
|
|
27
|
-
'qoverage': qs.get('overage_status', ''),
|
|
28
|
-
'ts': qs.get('timestamp', ''),
|
|
29
|
-
}))
|
|
30
|
-
" 2>/dev/null)
|
|
31
|
-
else
|
|
32
|
-
exit 0
|
|
33
|
-
fi
|
|
34
|
-
|
|
35
|
-
if [ -z "$last" ]; then exit 0; fi
|
|
9
|
+
if [ -f "$QS" ]; then
|
|
10
|
+
result=$(python3 -c "
|
|
11
|
+
import sys, json, os
|
|
12
|
+
from datetime import datetime, timezone, timedelta
|
|
36
13
|
|
|
37
|
-
|
|
38
|
-
import sys, json
|
|
39
|
-
from datetime import datetime, timezone
|
|
14
|
+
qs = json.load(open(os.path.expanduser('~/.claude/quota-status.json')))
|
|
40
15
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
16
|
+
q5h = qs.get('five_hour', {}).get('pct', 0)
|
|
17
|
+
q7d = qs.get('seven_day', {}).get('pct', 0)
|
|
18
|
+
q5h_reset = qs.get('five_hour', {}).get('resets_at', 0)
|
|
19
|
+
q7d_reset = qs.get('seven_day', {}).get('resets_at', 0)
|
|
20
|
+
status = qs.get('status', '')
|
|
21
|
+
overage = qs.get('overage_status', '')
|
|
22
|
+
ts = qs.get('timestamp', '')
|
|
48
23
|
|
|
49
|
-
now = datetime.fromisoformat(ts.replace('Z', '+00:00'))
|
|
24
|
+
now = datetime.fromisoformat(ts.replace('Z', '+00:00')) if ts else datetime.now(timezone.utc)
|
|
50
25
|
|
|
51
|
-
# Q5h
|
|
26
|
+
# Q5h burn rate
|
|
52
27
|
rate5 = ''
|
|
53
|
-
if q5h_reset > 0:
|
|
54
|
-
window_start = datetime.fromtimestamp(q5h_reset, tz=timezone.utc) -
|
|
28
|
+
if q5h_reset > 0 and q5h > 0:
|
|
29
|
+
window_start = datetime.fromtimestamp(q5h_reset, tz=timezone.utc) - timedelta(hours=5)
|
|
55
30
|
elapsed_min = (now - window_start).total_seconds() / 60
|
|
56
|
-
if elapsed_min > 1
|
|
31
|
+
if elapsed_min > 1:
|
|
57
32
|
rate5 = '{:+.1f}'.format(q5h / elapsed_min)
|
|
58
33
|
|
|
59
|
-
# Q7d
|
|
34
|
+
# Q7d burn rate
|
|
60
35
|
rate7 = ''
|
|
61
|
-
if q7d_reset > 0:
|
|
62
|
-
window_start_7d = datetime.fromtimestamp(q7d_reset, tz=timezone.utc) -
|
|
63
|
-
|
|
64
|
-
if
|
|
65
|
-
rate7 = '{:+.1f}'.format(q7d /
|
|
36
|
+
if q7d_reset > 0 and q7d > 0:
|
|
37
|
+
window_start_7d = datetime.fromtimestamp(q7d_reset, tz=timezone.utc) - timedelta(days=7)
|
|
38
|
+
elapsed_hr = (now - window_start_7d).total_seconds() / 3600
|
|
39
|
+
if elapsed_hr > 0.1:
|
|
40
|
+
rate7 = '{:+.1f}'.format(q7d / elapsed_hr)
|
|
66
41
|
|
|
67
42
|
label = 'Q5h: {}%'.format(q5h)
|
|
68
43
|
if rate5:
|
|
@@ -73,37 +48,23 @@ if rate7:
|
|
|
73
48
|
if overage == 'active':
|
|
74
49
|
label += ' | OVERAGE'
|
|
75
50
|
|
|
76
|
-
#
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
prefix = cache_cr + cache_rd
|
|
91
|
-
if prefix > 0:
|
|
92
|
-
if prefix >= 1_000_000:
|
|
93
|
-
label += ' \033[31m\u26A0 idle >5m = {:.1f}M rebuild\033[0m'.format(prefix / 1_000_000)
|
|
94
|
-
else:
|
|
95
|
-
label += ' \033[31m\u26A0 idle >5m = {:.0f}K rebuild\033[0m'.format(prefix / 1_000)
|
|
96
|
-
else:
|
|
97
|
-
label += ' | TTL:' + ttl
|
|
98
|
-
if hit and hit != 'N/A':
|
|
99
|
-
label += ' ' + hit + '%'
|
|
100
|
-
peak = qs.get('peak_hour', False)
|
|
101
|
-
if peak:
|
|
102
|
-
label += ' | \033[33mPEAK\033[0m' # yellow
|
|
103
|
-
except:
|
|
104
|
-
pass
|
|
51
|
+
# TTL and cache stats
|
|
52
|
+
ttl = qs.get('cache', {}).get('ttl_tier', '')
|
|
53
|
+
hit = qs.get('cache', {}).get('hit_rate', '')
|
|
54
|
+
if ttl:
|
|
55
|
+
if ttl == '5m':
|
|
56
|
+
label += ' | \033[31mTTL:5m\033[0m'
|
|
57
|
+
else:
|
|
58
|
+
label += ' | TTL:' + ttl
|
|
59
|
+
if hit and hit != 'N/A':
|
|
60
|
+
label += ' ' + hit + '%'
|
|
61
|
+
|
|
62
|
+
peak = qs.get('peak_hour', False)
|
|
63
|
+
if peak:
|
|
64
|
+
label += ' | \033[33mPEAK\033[0m'
|
|
105
65
|
|
|
106
66
|
print(label)
|
|
107
67
|
" 2>/dev/null)
|
|
108
68
|
|
|
109
69
|
[ -n "$result" ] && echo "$result"
|
|
70
|
+
fi
|