Skip to content

Commit 75eed8e

Browse files
committed
fixing vercel blog y add statusline components
1 parent eb19e71 commit 75eed8e

File tree

11 files changed

+628
-23
lines changed

11 files changed

+628
-23
lines changed

.claude/scripts/context-monitor.py

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Claude Code Context Monitor
4+
Real-time context usage monitoring with visual indicators and session analytics
5+
"""
6+
7+
import json
8+
import sys
9+
import os
10+
import re
11+
12+
def parse_context_from_transcript(transcript_path):
13+
"""Parse context usage from transcript file."""
14+
if not transcript_path or not os.path.exists(transcript_path):
15+
return None
16+
17+
try:
18+
with open(transcript_path, 'r') as f:
19+
lines = f.readlines()
20+
21+
# Check last 15 lines for context information
22+
recent_lines = lines[-15:] if len(lines) > 15 else lines
23+
24+
for line in reversed(recent_lines):
25+
try:
26+
data = json.loads(line.strip())
27+
28+
# Method 1: Parse usage tokens from assistant messages
29+
if data.get('type') == 'assistant':
30+
message = data.get('message', {})
31+
usage = message.get('usage', {})
32+
33+
if usage:
34+
input_tokens = usage.get('input_tokens', 0)
35+
cache_read = usage.get('cache_read_input_tokens', 0)
36+
cache_creation = usage.get('cache_creation_input_tokens', 0)
37+
38+
# Estimate context usage (assume 200k context for Claude Sonnet)
39+
total_tokens = input_tokens + cache_read + cache_creation
40+
if total_tokens > 0:
41+
percent_used = min(100, (total_tokens / 200000) * 100)
42+
return {
43+
'percent': percent_used,
44+
'tokens': total_tokens,
45+
'method': 'usage'
46+
}
47+
48+
# Method 2: Parse system context warnings
49+
elif data.get('type') == 'system_message':
50+
content = data.get('content', '')
51+
52+
# "Context left until auto-compact: X%"
53+
match = re.search(r'Context left until auto-compact: (\d+)%', content)
54+
if match:
55+
percent_left = int(match.group(1))
56+
return {
57+
'percent': 100 - percent_left,
58+
'warning': 'auto-compact',
59+
'method': 'system'
60+
}
61+
62+
# "Context low (X% remaining)"
63+
match = re.search(r'Context low \((\d+)% remaining\)', content)
64+
if match:
65+
percent_left = int(match.group(1))
66+
return {
67+
'percent': 100 - percent_left,
68+
'warning': 'low',
69+
'method': 'system'
70+
}
71+
72+
except (json.JSONDecodeError, KeyError, ValueError):
73+
continue
74+
75+
return None
76+
77+
except (FileNotFoundError, PermissionError):
78+
return None
79+
80+
def get_context_display(context_info):
81+
"""Generate context display with visual indicators."""
82+
if not context_info:
83+
return "🔵 ???"
84+
85+
percent = context_info.get('percent', 0)
86+
warning = context_info.get('warning')
87+
88+
# Color and icon based on usage level
89+
if percent >= 95:
90+
icon, color = "🚨", "\033[31;1m" # Blinking red
91+
alert = "CRIT"
92+
elif percent >= 90:
93+
icon, color = "🔴", "\033[31m" # Red
94+
alert = "HIGH"
95+
elif percent >= 75:
96+
icon, color = "🟠", "\033[91m" # Light red
97+
alert = ""
98+
elif percent >= 50:
99+
icon, color = "🟡", "\033[33m" # Yellow
100+
alert = ""
101+
else:
102+
icon, color = "🟢", "\033[32m" # Green
103+
alert = ""
104+
105+
# Create progress bar
106+
segments = 8
107+
filled = int((percent / 100) * segments)
108+
bar = "█" * filled + "▁" * (segments - filled)
109+
110+
# Special warnings
111+
if warning == 'auto-compact':
112+
alert = "AUTO-COMPACT!"
113+
elif warning == 'low':
114+
alert = "LOW!"
115+
116+
reset = "\033[0m"
117+
alert_str = f" {alert}" if alert else ""
118+
119+
return f"{icon}{color}{bar}{reset} {percent:.0f}%{alert_str}"
120+
121+
def get_directory_display(workspace_data):
122+
"""Get directory display name."""
123+
current_dir = workspace_data.get('current_dir', '')
124+
project_dir = workspace_data.get('project_dir', '')
125+
126+
if current_dir and project_dir:
127+
if current_dir.startswith(project_dir):
128+
rel_path = current_dir[len(project_dir):].lstrip('/')
129+
return rel_path or os.path.basename(project_dir)
130+
else:
131+
return os.path.basename(current_dir)
132+
elif project_dir:
133+
return os.path.basename(project_dir)
134+
elif current_dir:
135+
return os.path.basename(current_dir)
136+
else:
137+
return "unknown"
138+
139+
def get_session_metrics(cost_data):
140+
"""Get session metrics display."""
141+
if not cost_data:
142+
return ""
143+
144+
metrics = []
145+
146+
# Cost
147+
cost_usd = cost_data.get('total_cost_usd', 0)
148+
if cost_usd > 0:
149+
if cost_usd >= 0.10:
150+
cost_color = "\033[31m" # Red for expensive
151+
elif cost_usd >= 0.05:
152+
cost_color = "\033[33m" # Yellow for moderate
153+
else:
154+
cost_color = "\033[32m" # Green for cheap
155+
156+
cost_str = f"{cost_usd*100:.0f}¢" if cost_usd < 0.01 else f"${cost_usd:.3f}"
157+
metrics.append(f"{cost_color}💰 {cost_str}\033[0m")
158+
159+
# Duration
160+
duration_ms = cost_data.get('total_duration_ms', 0)
161+
if duration_ms > 0:
162+
minutes = duration_ms / 60000
163+
if minutes >= 30:
164+
duration_color = "\033[33m" # Yellow for long sessions
165+
else:
166+
duration_color = "\033[32m" # Green
167+
168+
if minutes < 1:
169+
duration_str = f"{duration_ms//1000}s"
170+
else:
171+
duration_str = f"{minutes:.0f}m"
172+
173+
metrics.append(f"{duration_color}{duration_str}\033[0m")
174+
175+
# Lines changed
176+
lines_added = cost_data.get('total_lines_added', 0)
177+
lines_removed = cost_data.get('total_lines_removed', 0)
178+
if lines_added > 0 or lines_removed > 0:
179+
net_lines = lines_added - lines_removed
180+
181+
if net_lines > 0:
182+
lines_color = "\033[32m" # Green for additions
183+
elif net_lines < 0:
184+
lines_color = "\033[31m" # Red for deletions
185+
else:
186+
lines_color = "\033[33m" # Yellow for neutral
187+
188+
sign = "+" if net_lines >= 0 else ""
189+
metrics.append(f"{lines_color}📝 {sign}{net_lines}\033[0m")
190+
191+
return f" \033[90m|\033[0m {' '.join(metrics)}" if metrics else ""
192+
193+
def main():
194+
try:
195+
# Read JSON input from Claude Code
196+
data = json.load(sys.stdin)
197+
198+
# Extract information
199+
model_name = data.get('model', {}).get('display_name', 'Claude')
200+
workspace = data.get('workspace', {})
201+
transcript_path = data.get('transcript_path', '')
202+
cost_data = data.get('cost', {})
203+
204+
# Parse context usage
205+
context_info = parse_context_from_transcript(transcript_path)
206+
207+
# Build status components
208+
context_display = get_context_display(context_info)
209+
directory = get_directory_display(workspace)
210+
session_metrics = get_session_metrics(cost_data)
211+
212+
# Model display with context-aware coloring
213+
if context_info:
214+
percent = context_info.get('percent', 0)
215+
if percent >= 90:
216+
model_color = "\033[31m" # Red
217+
elif percent >= 75:
218+
model_color = "\033[33m" # Yellow
219+
else:
220+
model_color = "\033[32m" # Green
221+
222+
model_display = f"{model_color}[{model_name}]\033[0m"
223+
else:
224+
model_display = f"\033[94m[{model_name}]\033[0m"
225+
226+
# Combine all components
227+
status_line = f"{model_display} \033[93m📁 {directory}\033[0m 🧠 {context_display}{session_metrics}"
228+
229+
print(status_line)
230+
231+
except Exception as e:
232+
# Fallback display on any error
233+
print(f"\033[94m[Claude]\033[0m \033[93m📁 {os.path.basename(os.getcwd())}\033[0m 🧠 \033[31m[Error: {str(e)[:20]}]\033[0m")
234+
235+
if __name__ == "__main__":
236+
main()

.claude/settings.local.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,5 +119,9 @@
119119
]
120120
}
121121
]
122+
},
123+
"statusLine": {
124+
"type": "command",
125+
"command": "python3 .claude/scripts/context-monitor.py"
122126
}
123127
}

cli-tool/components/commands/nextjs-vercel/vercel-edge-function.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
allowed-tools: Read, Write, Edit
33
argument-hint: [function-name] [--auth] [--geo] [--transform] [--proxy]
44
description: Generate optimized Vercel Edge Functions with geolocation, authentication, and data transformation
5-
model: claude-3-5-sonnet-20241022
5+
model: sonnet
66
---
77

88
## Vercel Edge Function Generator
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"description": "Real-time Claude Code context usage monitor with visual progress bars, color-coded alerts, session analytics (cost, duration, lines changed), and auto-compact warnings. Tracks conversation context consumption and provides visual feedback to prevent session interruptions.",
3+
"statusLine": {
4+
"type": "command",
5+
"command": "python3 .claude/scripts/context-monitor.py"
6+
}
7+
}

0 commit comments

Comments
 (0)