#!/usr/bin/env node // Claude Code Statusline // Shows: | | | [===== ] 60% // Git branch segment is omitted entirely when not in a git repository. 'use strict'; const { execSync } = require('child_process'); const fs = require('fs'); const path = require('path'); const os = require('os'); const R = '\x1b[0m'; const DIM = '\x1b[90m'; // separators const CYAN = '\x1b[36m'; // directory const GREEN = '\x1b[32m'; // git branch const MAGENTA = '\x1b[35m'; // model const BAR_OK = '\x1b[32m'; // usage < 70% const BAR_WARN = '\x1b[33m'; // usage 70–89% const BAR_CRIT = '\x1b[31m'; // usage >= 90% const SEP = `${DIM} | ${R}`; let input = ''; process.stdin.on('data', chunk => input += chunk); process.stdin.on('end', () => { let data = {}; try { if (input.trim()) data = JSON.parse(input); } catch (_) {} try { fs.writeFileSync(path.join(os.tmpdir(), 'statusline_data.json'), JSON.stringify(data, null, 2)); } catch (_) {} // --- Directory --- const cwd = (data.workspace && data.workspace.current_dir) || data.cwd || process.env.PWD || process.cwd(); const home = os.homedir().replace(/\\/g, '/'); const cwdNorm = cwd.replace(/\\/g, '/'); const displayDir = cwdNorm.startsWith(home) ? '~' + cwdNorm.slice(home.length) : cwdNorm; // --- Git branch --- let gitBranch = null; try { const branch = execSync('git rev-parse --abbrev-ref HEAD', { cwd, stdio: ['ignore', 'pipe', 'ignore'], timeout: 2000, env: { ...process.env, GIT_OPTIONAL_LOCKS: '0' }, }).toString().trim(); if (branch && branch !== 'HEAD') { gitBranch = branch; } else { try { gitBranch = execSync('git rev-parse --short HEAD', { cwd, stdio: ['ignore', 'pipe', 'ignore'], timeout: 2000, env: { ...process.env, GIT_OPTIONAL_LOCKS: '0' }, }).toString().trim() || 'HEAD'; } catch (_) { gitBranch = 'HEAD'; } } } catch (_) { gitBranch = null; } // --- Model --- const model = (data.model && data.model.display_name) || (data.model && data.model.id) || 'Claude'; // --- Bar helper --- const BAR_WIDTH = 8; function makeBar(pct, color) { const filled = Math.round((pct / 100) * BAR_WIDTH); return `${color}` + '█'.repeat(filled) + `${DIM}` + '░'.repeat(BAR_WIDTH - filled) + `${color} ${pct}%${R}`; } // --- Context window usage --- const pct = Math.round( (data.context_window && data.context_window.used_percentage) || 0 ); const barColor = pct >= 90 ? BAR_CRIT : pct >= 70 ? BAR_WARN : BAR_OK; const bar = makeBar(pct, barColor); // --- 5h rate limit + cost --- const fiveHour = data.rate_limits && data.rate_limits.five_hour; const totalCost = data.cost && data.cost.total_cost_usd; let usageSegment = null; if (fiveHour || totalCost) { const parts = []; if (fiveHour) { const fivePct = Math.round(fiveHour.used_percentage); const fiveColor = fivePct >= 90 ? BAR_CRIT : fivePct >= 70 ? BAR_WARN : BAR_OK; const resetDate = new Date(fiveHour.resets_at * 1000); const hh = String(resetDate.getHours()).padStart(2, '0'); const mm = String(resetDate.getMinutes()).padStart(2, '0'); parts.push(`${hh}:${mm} ${makeBar(fivePct, fiveColor)}`); } if (totalCost) { parts.push(`${DIM}$${totalCost.toFixed(2)}${R}`); } usageSegment = parts.join(' '); } // --- Assemble --- const segments = [`${CYAN}${displayDir}${R}`]; if (gitBranch !== null) segments.push(`${GREEN}${gitBranch}${R}`); segments.push(`${MAGENTA}${model}${R}`); segments.push(bar); if (usageSegment !== null) segments.push(usageSegment); process.stdout.write(segments.join(SEP) + '\n'); });