diff --git a/custom_statusline.js b/custom_statusline.js new file mode 100644 index 0000000..e6c5291 --- /dev/null +++ b/custom_statusline.js @@ -0,0 +1,93 @@ +#!/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 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 (_) {} + + // --- 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'; + + // --- 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_WIDTH = 10; + const filled = Math.round((pct / 100) * BAR_WIDTH); + const bar = + `${barColor}[` + + '='.repeat(filled) + + `${DIM}` + ' '.repeat(BAR_WIDTH - filled) + + `${barColor}] ${pct}%${R}`; + + // --- Assemble --- + const segments = [`${CYAN}${displayDir}${R}`]; + if (gitBranch !== null) segments.push(`${GREEN}${gitBranch}${R}`); + segments.push(`${MAGENTA}${model}${R}`); + segments.push(bar); + + process.stdout.write(segments.join(SEP) + '\n'); +});