From 50cb82074e24088389c8faecb45192dbfb289dd8 Mon Sep 17 00:00:00 2001 From: Julian Lechner Date: Wed, 16 Sep 2026 19:18:24 +0200 Subject: [PATCH] feat(statusline): show compact colored context and token metrics --- scripts/test-platform-packages.ps1 | 2 +- scripts/test-platform-packages.sh | 3 +- shared/statusline/statusline.ps1 | 33 +++++++++++++++------ shared/statusline/statusline.sh | 46 ++++++++++++++++++++---------- 4 files changed, 57 insertions(+), 27 deletions(-) diff --git a/scripts/test-platform-packages.ps1 b/scripts/test-platform-packages.ps1 index 67e9beb..2a1982f 100644 --- a/scripts/test-platform-packages.ps1 +++ b/scripts/test-platform-packages.ps1 @@ -11,7 +11,7 @@ $buildSummaryOutput = & (Join-Path $root 'scripts/build.ps1') -Summary if (@($buildSummaryOutput | Where-Object { $_ -eq 'Build: PASS | 4 packages' }).Count -ne 1) { throw "build.ps1 -Summary must still print the PASS line: $($buildSummaryOutput -join '; ')" } $statusOutput = ($statusInput | & (Join-Path $root 'shared/statusline/statusline.ps1')) -join "`n" $plainStatusOutput = [regex]::Replace($statusOutput, [char]27 + '\[[0-9;]*m', '') -$expectedStatusOutput = "Test Model $([char]0x00B7) high`nTestRepo on $branch $([char]0x00B7) 9% ctx (16.7k tok)" +$expectedStatusOutput = "Test Model $([char]0x00B7) Effort high $([char]0x00B7) TestRepo @ $branch`nCtx 200k $([char]0x00B7) Used 9% $([char]0x00B7) Tokens 16.7k" if ($buildSummaryOutput.Count -ne 1) { throw 'Build summary must contain only one success line.' } if ($plainStatusOutput -ne $expectedStatusOutput) { throw 'PowerShell status line output is incorrect.' } $sourceAgentCount = @(Get-ChildItem (Join-Path $root 'shared/agents') -Directory).Count diff --git a/scripts/test-platform-packages.sh b/scripts/test-platform-packages.sh index f070ce5..ca42974 100755 --- a/scripts/test-platform-packages.sh +++ b/scripts/test-platform-packages.sh @@ -20,7 +20,7 @@ fi [ "$build_summary_output" = 'Build: PASS | 4 packages' ] status_output=$(printf '{"model":{"display_name":"Test Model"},"effort":{"level":"high"},"workspace":{"current_dir":"%s","repo":{"name":"TestRepo"}},"context_window":{"context_window_size":200000,"used_percentage":8.5,"total_input_tokens":15500,"total_output_tokens":1200}}' "$root" | bash "$root/shared/statusline/statusline.sh") plain_status_output=$(printf '%s' "$status_output" | sed -E $'s/\x1b\\[[0-9;]*m//g') -expected_status_output=$'Test Model \xc2\xb7 high\nTestRepo on '"$branch"$' \xc2\xb7 9% ctx (16.7k tok)' +expected_status_output=$'Test Model \xc2\xb7 Effort high \xc2\xb7 TestRepo @ '"$branch"$'\nCtx 200k \xc2\xb7 Used 9% \xc2\xb7 Tokens 16.7k' [ "$plain_status_output" = "$expected_status_output" ] source_agent_count=$(find "$root/shared/agents" -mindepth 1 -maxdepth 1 -type d | wc -l) source_skill_count=$(find "$root/shared/skills" -name SKILL.md | wc -l) @@ -113,4 +113,3 @@ for entry_point in install update; do done printf '%s\n' "$doctor_summary_output" | grep '^WARN ' || true if [ "$summary" = true ]; then printf 'Tests: PASS | platform packages\n'; else printf 'PASS four platform packages and six Bash selections\n'; fi - diff --git a/shared/statusline/statusline.ps1 b/shared/statusline/statusline.ps1 index b31b9d7..0b37888 100644 --- a/shared/statusline/statusline.ps1 +++ b/shared/statusline/statusline.ps1 @@ -1,28 +1,43 @@ [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 $invariantCulture = [System.Globalization.CultureInfo]::InvariantCulture +function Format-TokenCount { + param($Value) + if ($null -eq $Value) { return '-' } + $count = [double]$Value + if ($count -ge 1000000) { return ($count / 1000000).ToString('0.#', $invariantCulture) + 'M' } + if ($count -ge 1000) { return ($count / 1000).ToString('0.#', $invariantCulture) + 'k' } + return $count.ToString('0', $invariantCulture) +} $data = ($input | Out-String) | ConvertFrom-Json $model = if ($data.model.display_name) { $data.model.display_name } else { '-' } $effort = if ($data.effort.level) { $data.effort.level } else { '-' } $directory = if ($data.workspace.current_dir) { $data.workspace.current_dir } else { $data.cwd } $repo = if ($data.workspace.repo.name) { $data.workspace.repo.name } elseif ($directory) { Split-Path $directory -Leaf } else { '-' } +if (-not $data.workspace.repo.name -and $directory -and (Get-Command git -ErrorAction SilentlyContinue)) { + $repoRoot = & git -C $directory rev-parse --show-toplevel 2>$null | Select-Object -First 1 + if ($repoRoot) { $repo = Split-Path $repoRoot -Leaf } +} $branch = if ($directory -and (Get-Command git -ErrorAction SilentlyContinue)) { (& git -C $directory branch --show-current 2>$null | Select-Object -First 1) } else { $null } if (-not $branch) { $branch = '-' } -$usedPercentage = if ($null -ne $data.context_window.used_percentage) { [double]$data.context_window.used_percentage } else { $null } +$usedPercentage = if ($null -ne $data.context_window.used_percentage) { [math]::Round([double]$data.context_window.used_percentage, [MidpointRounding]::AwayFromZero) } else { $null } $usedContext = if ($null -ne $usedPercentage) { "$([math]::Round($usedPercentage, [MidpointRounding]::AwayFromZero).ToString($invariantCulture))%" } else { '-' } $usedTokens = [long]$data.context_window.total_input_tokens + [long]$data.context_window.total_output_tokens -$usedTokensDisplay = if ($usedTokens -ge 1000) { ($usedTokens / 1000).ToString('0.0', $invariantCulture) + 'k' } else { $usedTokens.ToString($invariantCulture) } +$usedTokensDisplay = Format-TokenCount $usedTokens +$contextWindow = Format-TokenCount $data.context_window.context_window_size $esc = [char]27 $reset = "$esc[0m" $dim = "$esc[90m" -$cyan = "$esc[36m" -$magenta = "$esc[35m" -$blue = "$esc[34m" -$green = "$esc[32m" +$cyan = "$esc[96m" +$magenta = "$esc[95m" +$blue = "$esc[94m" +$green = "$esc[92m" $contextColor = if ($null -eq $usedPercentage) { $dim } elseif ($usedPercentage -ge 85) { "$esc[31m" } elseif ($usedPercentage -ge 60) { "$esc[33m" } else { $green } $middot = [char]0x00B7 $sep = "$dim$middot$reset" -$line1 = "$cyan$model$reset $sep $magenta$effort$reset" -$line2 = "$blue$repo$reset$dim on$reset $green$branch$reset $sep $contextColor$usedContext ctx$reset $dim($usedTokensDisplay tok)$reset" -Write-Output "$line1`n$line2" +$line1 = "$cyan$model$reset $sep Effort $magenta$effort$reset $sep $blue$repo$reset @ $green$branch$reset" +$line2 = "Ctx $cyan$contextWindow$reset $sep Used $contextColor$usedContext$reset $sep Tokens $magenta$usedTokensDisplay$reset" +$outputText = "$line1`n$line2" +if ($env:NO_COLOR) { $outputText = [regex]::Replace($outputText, [char]27 + '\[[0-9;]*m', '') } +Write-Output $outputText diff --git a/shared/statusline/statusline.sh b/shared/statusline/statusline.sh index 32e2478..43b3fdd 100755 --- a/shared/statusline/statusline.sh +++ b/shared/statusline/statusline.sh @@ -4,19 +4,24 @@ set -euo pipefail command -v jq >/dev/null 2>&1 || exit 0 input= while IFS= read -r line || [ -n "$line" ]; do input+="$line"; done -IFS=$'\t' read -r model effort repo directory used_percentage used_tokens < <( +IFS=$'\t' read -r model effort repo directory used_percentage used_tokens context_window < <( printf '%s' "$input" | jq -r '[ (.model.display_name // "-"), (.effort.level // "-"), (.workspace.repo.name // "-"), - (.workspace.current_dir // .cwd // "."), + (.workspace.current_dir // .cwd // "-"), (if .context_window.used_percentage == null then "-" else (.context_window.used_percentage | round) end), - ((.context_window.total_input_tokens // 0) + (.context_window.total_output_tokens // 0)) + ((.context_window.total_input_tokens // 0) + (.context_window.total_output_tokens // 0)), + (.context_window.context_window_size // "-") ] | @tsv' ) used_percentage=${used_percentage%$'\r'} used_tokens=${used_tokens%$'\r'} -[ "$repo" != - ] || repo=$(basename -- "$directory") +context_window=${context_window%$'\r'} +if [ "$repo" = - ]; then + repo_root=$(git -C "$directory" rev-parse --show-toplevel 2>/dev/null || true) + repo=$(basename -- "${repo_root:-$directory}") +fi [ -n "$repo" ] || repo=- branch=$(git -C "$directory" branch --show-current 2>/dev/null || true) [ -n "$branch" ] || branch=- @@ -26,19 +31,27 @@ if [ "$used_percentage" != - ]; then else used_context=- fi -if [ "$used_tokens" -ge 1000 ]; then - used_tokens_display=$(awk -v t="$used_tokens" 'BEGIN { printf "%.1fk", t / 1000 }') -else - used_tokens_display=$used_tokens -fi +format_token_count() { + LC_ALL=C awk -v t="$1" 'BEGIN { + if (t == "-") { printf "-"; exit } + suffix = "" + if (t >= 1000000) { t /= 1000000; suffix = "M" } + else if (t >= 1000) { t /= 1000; suffix = "k" } + value = sprintf("%.1f", t) + sub(/\.0$/, "", value) + printf "%s%s", value, suffix + }' +} +used_tokens_display=$(format_token_count "$used_tokens") +context_window_display=$(format_token_count "$context_window") esc=$'\033' reset="$esc[0m" dim="$esc[90m" -cyan="$esc[36m" -magenta="$esc[35m" -blue="$esc[34m" -green="$esc[32m" +cyan="$esc[96m" +magenta="$esc[95m" +blue="$esc[94m" +green="$esc[92m" if [ "$used_percentage" = - ]; then context_color=$dim elif [ "$used_percentage" -ge 85 ]; then @@ -48,7 +61,10 @@ elif [ "$used_percentage" -ge 60 ]; then else context_color=$green fi +if [ -n "${NO_COLOR:-}" ]; then + reset= dim= cyan= magenta= blue= green= context_color= +fi sep="${dim}ยท${reset}" -printf "${cyan}%s${reset} ${sep} ${magenta}%s${reset}\n${blue}%s${reset}${dim} on${reset} ${green}%s${reset} ${sep} ${context_color}%s ctx${reset} ${dim}(%s tok)${reset}\n" \ - "$model" "$effort" "$repo" "$branch" "$used_context" "$used_tokens_display" +printf "${cyan}%s${reset} ${sep} Effort ${magenta}%s${reset} ${sep} ${blue}%s${reset} @ ${green}%s${reset}\nCtx ${cyan}%s${reset} ${sep} Used ${context_color}%s${reset} ${sep} Tokens ${magenta}%s${reset}\n" \ + "$model" "$effort" "$repo" "$branch" "$context_window_display" "$used_context" "$used_tokens_display"