Last active
April 3, 2026 11:18
-
-
Save Misaka-0x447f/d4bbeeda56b9bc80a73e0cde5f20d96f to your computer and use it in GitHub Desktop.
Claude Code statusline config (2026-03-28)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Wrapper to invoke TypeScript statusline script | |
| exec pnpx tsx "$(dirname "$0")/statusline.ts" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env npx tsx | |
| // upstream=https://gist.github.com/Misaka-0x447f/d4bbeeda56b9bc80a73e0cde5f20d96f | |
| interface StatuslineInput { | |
| cwd?: string; | |
| workspace?: { current_dir?: string }; | |
| model?: { display_name?: string }; | |
| cost?: { total_cost_usd?: number }; | |
| exceeds_200k_tokens?: boolean; | |
| rate_limits?: { | |
| five_hour?: { used_percentage?: number; resets_at?: number }; | |
| seven_day?: { used_percentage?: number; resets_at?: number }; | |
| }; | |
| } | |
| async function main(): Promise<void> { | |
| let raw = ''; | |
| for await (const chunk of process.stdin) { | |
| raw += chunk; | |
| } | |
| const data: StatuslineInput = JSON.parse(raw); | |
| // Quota coloring based on pace (consumption rate vs time-proportional expectation). | |
| // | |
| // Inputs: | |
| // remaining = 100 - used_percentage (actual remaining quota %) | |
| // expected = (time left / total window) * 100 (ideal remaining % if usage were uniform) | |
| // | |
| // Rules (first match wins, all require expected to be available): | |
| // 1. remaining <= expected/3 + 3 → red — consumed far more than expected | |
| // 2. remaining <= expected*2/3 + 5 → orange — consuming significantly faster than expected | |
| // 3. remaining < expected - 10 → orange — consuming >10% faster than expected pace | |
| // 4. remaining < expected → yellow — consuming faster than expected, within 10% | |
| // 5. remaining >= expected → green — on pace or under-consuming | |
| // | |
| // When time info (resets_at) is unavailable, no coloring is applied. | |
| const C_GRAY = '\x1b[38;2;187;187;187m'; // #bbbbbb | |
| const C_GREEN = '\x1b[38;2;155;233;197m'; // #9be9c5 | |
| const C_YELLOW = '\x1b[38;2;237;217;140m'; // #edd98c | |
| const C_ORANGE = '\x1b[38;2;255;155;85m'; // #ff9b55 | |
| const C_RED = '\x1b[91m'; // bright red | |
| const C_RESET = '\x1b[0m'; | |
| const cwd = (() => { | |
| const dir = data.workspace?.current_dir ?? data.cwd ?? ''; | |
| const home = process.env.HOME ?? ''; | |
| return home && dir.startsWith(home) ? '~' + dir.slice(home.length) : dir; | |
| })(); | |
| const model = data.model?.id ?? ''; | |
| const bigCtx = data.exceeds_200k_tokens ? ` ${C_YELLOW}1M mode${C_RESET}` : ''; | |
| const cost = data.cost?.total_cost_usd ?? 0; | |
| const time = new Intl.DateTimeFormat('en-GB', { | |
| hour: '2-digit', | |
| minute: '2-digit', | |
| second: '2-digit', | |
| hour12: false, | |
| }).format(new Date()); | |
| const colorize = (remaining: number, expected: number | null, text: string): string => { | |
| let color = C_GREEN; | |
| if (expected != null && remaining <= expected / 3 + 3) color = C_RED; | |
| else if (expected != null && remaining <= expected * 2 / 3 + 5) color = C_ORANGE; | |
| else if (expected != null && remaining < expected - 10) color = C_ORANGE; | |
| else if (expected != null && remaining < expected) color = C_YELLOW; | |
| return `${color}${text}${C_RESET}`; | |
| }; | |
| const fmtPct = (v: number) => Math.round(v).toFixed(0); | |
| const fmtDuration = (sec: number, extended = false): string => { | |
| sec = Math.max(0, Math.floor(sec)); | |
| const units: [number, string][] = [[86400, 'd'], [3600, 'h'], [60, 'm'], [1, 's']]; | |
| for (let i = 0; i < units.length; i++) { | |
| const [div, suf] = units[i]; | |
| if (sec >= div || i === units.length - 1) { | |
| const major = Math.floor(sec / div); | |
| if (extended && i + 1 < units.length) { | |
| const [div2, suf2] = units[i + 1]; | |
| const minor = Math.floor((sec % div) / div2); | |
| return minor > 0 ? `${major}${suf}${minor}${suf2}` : `${major}${suf}`; | |
| } | |
| return `${major}${suf}`; | |
| } | |
| } | |
| return `${sec}s`; | |
| }; | |
| const fmtRemain = (resetAt: number): string => { | |
| return fmtDuration((resetAt * 1000 - Date.now()) / 1000); | |
| }; | |
| // Calculate expected remaining % from time left in the window | |
| const calcExpected = (resetAt: number | undefined, windowSec: number): number | null => { | |
| if (!resetAt) return null; | |
| const remainSec = Math.max(0, (resetAt * 1000 - Date.now()) / 1000); | |
| return (remainSec / windowSec) * 100; | |
| }; | |
| const FIVE_HOUR_SEC = 5 * 3600; | |
| const SEVEN_DAY_SEC = 7 * 86400; | |
| const fiveH = data.rate_limits?.five_hour; | |
| const sevenD = data.rate_limits?.seven_day; | |
| let quotaParts: string[] = []; | |
| if (fiveH?.used_percentage != null) { | |
| const remaining = 100 - fiveH.used_percentage; | |
| const expected = calcExpected(fiveH.resets_at, FIVE_HOUR_SEC); | |
| const label = fiveH.resets_at ? fmtRemain(fiveH.resets_at) : '5h'; | |
| const pctText = `${fmtPct(remaining)}%`; | |
| // First 3 minutes of the 5h window: gray (data not yet meaningful) | |
| const remainSec = fiveH.resets_at ? Math.max(0, (fiveH.resets_at * 1000 - Date.now()) / 1000) : 0; | |
| const isEarly = fiveH.resets_at && remainSec > FIVE_HOUR_SEC - 180; | |
| const colored = isEarly ? `${C_GRAY}${pctText}${C_RESET}` | |
| : expected != null ? colorize(remaining, expected, pctText) : pctText; | |
| const delta5h = (!isEarly && expected != null && remaining < expected) | |
| ? ` Δ-${fmtDuration(remainSec - remaining * FIVE_HOUR_SEC / 100)}` | |
| : ''; | |
| quotaParts.push(`[${label}]${colored}${delta5h}`); | |
| } | |
| // Same coloring as 5h but green maps to no color (plain text) | |
| const colorizeNoGreen = (remaining: number, expected: number | null, text: string): string => { | |
| let color: string | null = null; | |
| if (expected != null && remaining <= expected / 3 + 3) color = C_RED; | |
| else if (expected != null && remaining <= expected * 2 / 3 + 5) color = C_ORANGE; | |
| else if (expected != null && remaining < expected - 10) color = C_ORANGE; | |
| else if (expected != null && remaining < expected) color = C_YELLOW; | |
| return color ? `${color}${text}${C_RESET}` : text; | |
| }; | |
| if (sevenD?.used_percentage != null) { | |
| const remaining = 100 - sevenD.used_percentage; | |
| const expected = calcExpected(sevenD.resets_at, SEVEN_DAY_SEC); | |
| const label = sevenD.resets_at ? fmtRemain(sevenD.resets_at) : '7d'; | |
| const pctText = `${fmtPct(remaining)}%`; | |
| const remainSec7d = sevenD.resets_at ? Math.max(0, (sevenD.resets_at * 1000 - Date.now()) / 1000) : 0; | |
| const deltaSec7d = remainSec7d - remaining * SEVEN_DAY_SEC / 100; | |
| const delta7d = (expected != null && remaining < expected) | |
| ? ` Δ-${fmtDuration(deltaSec7d, deltaSec7d >= 86400)}` | |
| : ''; | |
| quotaParts.push(`[${label}]${expected != null ? colorizeNoGreen(remaining, expected, pctText) : pctText}${delta7d}`); | |
| } | |
| const quotaStr = quotaParts.length ? ` ' ${quotaParts.join(' ')}` : ''; | |
| process.stdout.write( | |
| `${cwd} ' ${model}${bigCtx} ' $${cost.toFixed(4)}${quotaStr} ' ${time}`, | |
| ); | |
| } | |
| main().catch((err) => { | |
| process.stdout.write(`error: ${err.message}`); | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment