|
# Claude Code custom status line
|
|
# https://code.claude.com/docs/en/statusline
|
|
#
|
|
# Format: {progress bar} {context %} | {tokens used/max} | {cost} | {duration} | {model}
|
|
# Output: ████▌██████████ 26.0% | 52.1k/200.0k | $1.93 | 3m 33s | Opus 4.6
|
|
#
|
|
# progressBar = green/dim unicode block bar showing context usage visually (persistent across resumes)
|
|
# usedPctStr = context window usage as percentage (persistent across resumes)
|
|
# tokenStr = current context usage / max context window size (persistent across resumes)
|
|
# totalCost = session cost in USD (resets on resume)
|
|
# duration = total wall-clock time since session started (resets on resume)
|
|
# modelName = active model display name (persistent across resumes)
|
|
|
|
# --- Parse JSON from stdin ---
|
|
|
|
$json = [Console]::In.ReadToEnd() | ConvertFrom-Json
|
|
|
|
# --- Extract values ---
|
|
|
|
$modelName = $json.model.display_name
|
|
$usedPct = if ($null -ne $json.context_window.used_percentage) { $json.context_window.used_percentage } else { 0 }
|
|
$totalCost = if ($null -ne $json.cost.total_cost_usd) { $json.cost.total_cost_usd } else { 0 }
|
|
$maxTokens = if ($null -ne $json.context_window.context_window_size) { $json.context_window.context_window_size } else { 200000 }
|
|
|
|
# Use exact current_usage fields for token count (input tokens only, matching used_percentage formula)
|
|
# Falls back to deriving from used_percentage when current_usage is null (before first API call)
|
|
$cu = $json.context_window.current_usage
|
|
if ($null -ne $cu) {
|
|
$usedTokens = $cu.input_tokens + $cu.cache_creation_input_tokens + $cu.cache_read_input_tokens
|
|
$usedPct = $usedTokens / $maxTokens * 100
|
|
} else {
|
|
$usedTokens = [math]::Round($maxTokens * $usedPct / 100)
|
|
}
|
|
|
|
# --- Format duration ---
|
|
|
|
$durationMs = if ($null -ne $json.cost.total_duration_ms) { $json.cost.total_duration_ms } else { 0 }
|
|
$elapsed = [TimeSpan]::FromMilliseconds($durationMs)
|
|
if ($elapsed.TotalHours -ge 1) {
|
|
$duration = "{0}h {1}m" -f [math]::Floor($elapsed.TotalHours), $elapsed.Minutes
|
|
} elseif ($elapsed.TotalMinutes -ge 1) {
|
|
$duration = "{0}m {1}s" -f [math]::Floor($elapsed.TotalMinutes), $elapsed.Seconds
|
|
} else {
|
|
$duration = "{0}s" -f [math]::Floor($elapsed.TotalSeconds)
|
|
}
|
|
|
|
# --- Format token counts ---
|
|
|
|
function Format-Tokens($n) {
|
|
if ($n -ge 1000000) { return "{0:F1}M" -f ($n / 1000000) }
|
|
if ($n -ge 1000) { return "{0:F1}k" -f ($n / 1000) }
|
|
return "$n"
|
|
}
|
|
|
|
# --- Build progress bar ---
|
|
|
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
|
|
|
$esc = [char]27
|
|
$green = "$esc[32m"
|
|
$dim = "$esc[90m"
|
|
$reset = "$esc[0m"
|
|
$fullBlock = [char]0x2588
|
|
$halfBlock = [char]0x258C
|
|
|
|
$barWidth = 15
|
|
$exactFill = $barWidth * $usedPct / 100
|
|
$filledWidth = [math]::Floor($exactFill)
|
|
$hasHalf = ($exactFill - $filledWidth) -ge 0.5
|
|
$emptyWidth = $barWidth - $filledWidth - ([int]$hasHalf)
|
|
|
|
$filled = ([string]$fullBlock) * $filledWidth
|
|
$half = if ($hasHalf) { [string]$halfBlock } else { "" }
|
|
$empty = ([string]$fullBlock) * $emptyWidth
|
|
|
|
# --- Output ---
|
|
|
|
$progressBar = "$green$filled$half$dim$empty$reset"
|
|
$usedPctStr = "{0:F1}%" -f $usedPct
|
|
$tokenStr = "$(Format-Tokens $usedTokens)/$(Format-Tokens $maxTokens)"
|
|
$costStr = "`$$("{0:F2}" -f $totalCost)"
|
|
|
|
Write-Host "$progressBar $usedPctStr | $tokenStr | $costStr | $duration | $modelName"
|