UNPKG

@owloops/claude-powerline

Version:

Beautiful vim-style powerline statusline for Claude Code with real-time usage tracking, git integration, and custom themes

118 lines (97 loc) 3.07 kB
import { execSync } from "node:child_process"; const VALID_TTY_PATTERN = /^[a-zA-Z0-9/]+$/; function findParentTty(): string | null { if (process.platform === "win32") return null; let pid = process.pid.toString(); for (let i = 0; i < 10; i++) { try { const info = execSync(`ps -o ppid=,tty= -p ${pid}`, { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"], }).trim(); const parts = info.split(/\s+/); const ppid = parts[0]; const tty = parts[1]; if (tty && tty !== "?" && tty !== "??" && VALID_TTY_PATTERN.test(tty)) { return tty; } if (!ppid || ppid === "1" || ppid === "0") break; pid = ppid; } catch { break; } } return null; } function getWindowsTerminalWidth(): number | null { try { const output = execSync("mode con", { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"], windowsHide: true, }); const match = output.match(/Columns:\s*(\d+)/i); if (match?.[1]) { const parsed = parseInt(match[1], 10); if (!isNaN(parsed) && parsed > 0) return parsed; } } catch {} return null; } function getUnixTerminalWidth(): number | null { const tty = findParentTty(); if (tty) { try { const size = execSync(`stty size < /dev/${tty}`, { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"], shell: "/bin/sh", }).trim(); const width = size.split(" ")[1]; if (width) { const parsed = parseInt(width, 10); if (!isNaN(parsed) && parsed > 0) return parsed; } } catch {} } try { const width = execSync("tput cols 2>/dev/null", { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"], }).trim(); const parsed = parseInt(width, 10); if (!isNaN(parsed) && parsed > 0) return parsed; } catch {} return null; } /** * @info Reserves characters for Claude Code's right-side UI messages * (e.g., "Current: 2.1.78 · latest: 2.1.78", "Thinking off") */ const RESERVED_CHARS = 45; export function getTerminalWidth(): number | null { const applyReserve = (w: number) => Math.max(1, w - RESERVED_CHARS); const envColumns = process.env.COLUMNS; if (envColumns) { const parsed = parseInt(envColumns, 10); if (!isNaN(parsed) && parsed > 0) return applyReserve(parsed); } if (process.stdout.columns && process.stdout.columns > 0) { return applyReserve(process.stdout.columns); } if (process.platform === "win32") { const width = getWindowsTerminalWidth(); if (width) return applyReserve(width); } const width = getUnixTerminalWidth(); return width ? applyReserve(width) : null; } export function getRawTerminalWidth(): number | null { // Skip COLUMNS env and process.stdout.columns — Claude Code sets those // to an already-reserved panel width. We need the actual terminal width // so the grid engine can apply its own widthReserve. if (process.platform === "win32") { return getWindowsTerminalWidth(); } return getUnixTerminalWidth(); }