feat: Add live context window tracking with visual progress bar
- Extract token usage from message_delta events in backend - Calculate context usage percentage (input + cache tokens / 200k) - Add context_update, compacting_started/finished, compact_boundary events - Display progress bar that fills up as context is consumed - Color-coded warnings (green→yellow→red) based on usage - Show compacting status indicator when auto-compact runs - Display system messages for compact start/finish with usage stats 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -23,7 +23,8 @@ export function StatusBar({ sessionStats, isProcessing, connected, permissionMod
|
||||
cacheCreationTokens = 0,
|
||||
numTurns = 0,
|
||||
contextWindow = 200000,
|
||||
contextLeftPercent = null, // From Claude's "Context left until auto-compact: X%" message
|
||||
contextLeftPercent = null, // Live context tracking from message_delta events
|
||||
tokensUsed = 0,
|
||||
isCompacting = false,
|
||||
} = sessionStats || {};
|
||||
|
||||
@@ -31,9 +32,27 @@ export function StatusBar({ sessionStats, isProcessing, connected, permissionMod
|
||||
const currentMode = PERMISSION_MODES.find(m => m.value === permissionMode) || PERMISSION_MODES[0];
|
||||
const ModeIcon = currentMode.icon;
|
||||
|
||||
// Context remaining: Use Claude's reported value if available, otherwise don't show
|
||||
// Claude only reports this when context is getting low (< ~15%)
|
||||
// Context used percentage (0-100) - bar fills up as context is consumed
|
||||
const contextRemaining = contextLeftPercent;
|
||||
const contextUsedPercent = contextRemaining !== null ? (100 - contextRemaining) : 0;
|
||||
|
||||
// Determine color based on usage (higher usage = more warning)
|
||||
const getContextColor = (usedPercent) => {
|
||||
if (usedPercent === null) return 'bg-dark-600';
|
||||
if (usedPercent >= 95) return 'bg-red-500';
|
||||
if (usedPercent >= 85) return 'bg-red-400';
|
||||
if (usedPercent >= 70) return 'bg-yellow-400';
|
||||
if (usedPercent >= 50) return 'bg-yellow-300';
|
||||
return 'bg-green-400';
|
||||
};
|
||||
|
||||
const getContextTextColor = (usedPercent) => {
|
||||
if (usedPercent === null) return 'text-dark-500';
|
||||
if (usedPercent >= 95) return 'text-red-400 font-medium animate-pulse';
|
||||
if (usedPercent >= 85) return 'text-red-400';
|
||||
if (usedPercent >= 70) return 'text-yellow-400';
|
||||
return 'text-green-400';
|
||||
};
|
||||
|
||||
// Format cost
|
||||
const formatCost = (cost) => {
|
||||
@@ -135,19 +154,33 @@ export function StatusBar({ sessionStats, isProcessing, connected, permissionMod
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Right side: Token usage */}
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Context status - only shown when Claude reports it (context getting low) */}
|
||||
{/* Right side: Context usage with progress bar */}
|
||||
<div className="flex items-center gap-3">
|
||||
{/* Context progress bar - always visible when we have data */}
|
||||
{contextRemaining !== null && (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-dark-500">Context:</span>
|
||||
<span className={`${
|
||||
contextRemaining <= 5 ? 'text-red-400 font-medium animate-pulse' :
|
||||
contextRemaining <= 15 ? 'text-red-400' :
|
||||
contextRemaining <= 30 ? 'text-yellow-400' : 'text-green-400'
|
||||
}`}>
|
||||
{contextRemaining}% left
|
||||
</span>
|
||||
<Database className="w-3 h-3 text-dark-500" />
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Progress bar container - fills up as context is used */}
|
||||
<div className="w-24 h-2 bg-dark-700 rounded-full overflow-hidden" title={`${tokensUsed.toLocaleString()} / ${contextWindow.toLocaleString()} tokens used`}>
|
||||
<div
|
||||
className={`h-full transition-all duration-300 ${getContextColor(contextUsedPercent)}`}
|
||||
style={{ width: `${contextUsedPercent}%` }}
|
||||
/>
|
||||
</div>
|
||||
{/* Percentage text - shows how full the context is */}
|
||||
<span className={`min-w-[45px] text-right ${getContextTextColor(contextUsedPercent)}`}>
|
||||
{contextUsedPercent}%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Show "waiting" state if no context data yet */}
|
||||
{contextRemaining === null && connected && (
|
||||
<div className="flex items-center gap-2 text-dark-500">
|
||||
<Database className="w-3 h-3" />
|
||||
<span>Context: --</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user