Files
custom-statusline/custom_statusline.js
T
mikkeli ba54cbf84e Compact unicode bars and reset time for rate limit segment
Replaces ASCII [====] bars with █░ unicode blocks at width 8 (no
brackets) for both context and rate limit segments. Replaces static
"5h" label with actual reset time formatted as HH:MM.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 11:09:36 +09:00

121 lines
3.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
// Claude Code Statusline
// Shows: <directory> | <git branch> | <model> | [===== ] 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 7089%
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');
});