claude实用
Claude Code CLI状态栏 /statusline
https://code.claude.com/docs/en/statusline#context-window-usage
https://hannahstulberg.substack.com/p/claude-code-for-everything-your-status-line-is-empty
点击查看代码
#!/usr/bin/env node
/**
* Claude Code statusLine.
* Layout: 📁 path | ★ Model | Context: ▰▰▱▱ NN% | 💰 Cost:$N.NN | 🌿 branch(+N) ● effort · /effort
* Left segments are pipe-separated; the effort indicator is right-aligned to $COLUMNS.
*/
const fs = require("fs");
const path = require("path");
const { execFileSync } = require("child_process");
let s = {};
try {
s = JSON.parse(fs.readFileSync(0, "utf8")) || {};
} catch {
s = {};
}
// --- ANSI helpers ---------------------------------------------------------
const C = (code, text) => `\x1b[${code}m${text}\x1b[0m`;
const SEP = C("38;5;240", " | ");
const DIM = "38;5;244";
const FG = "38;5;253";
/** Display width, ignoring ANSI and counting emoji as 2 cells. */
function width(str) {
const plain = str.replace(/\x1b\[[0-9;]*m/g, "");
let w = 0;
for (const ch of plain) {
const cp = ch.codePointAt(0);
const wide =
(cp >= 0x1f300 && cp <= 0x1faff) || // emoji & pictographs
(cp >= 0x2600 && cp <= 0x27bf) || // misc symbols / dingbats
(cp >= 0x1100 && cp <= 0x115f) || // Hangul jamo
(cp >= 0x2e80 && cp <= 0xa4cf) || // CJK
(cp >= 0xff00 && cp <= 0xff60); // fullwidth forms
w += wide ? 2 : 1;
}
return w;
}
const left = [];
// --- 📁 Working directory -------------------------------------------------
const cwd = s.workspace?.current_dir || s.cwd || process.cwd();
const home = process.env.USERPROFILE || process.env.HOME || "";
let label;
if (home && cwd.toLowerCase().startsWith(home.toLowerCase())) {
const rest = cwd.slice(home.length).replace(/^[\\/]/, "").replace(/\\/g, "/");
label = rest ? `~/${rest}` : "~";
} else {
label = cwd.replace(/\\/g, "/");
}
const segs = label.split("/").filter(Boolean);
if (segs.length > 3) label = `…/${segs.slice(-2).join("/")}`;
left.push(`${C(DIM, "📁")} ${C(FG, label)}`);
// --- ★ Model --------------------------------------------------------------
const model = (s.model?.display_name || "").replace(/\s*\(.*\)\s*$/, "").trim();
if (model) left.push(`${C("38;5;215", "★")} ${C("1;38;5;215", model)}`);
// --- Context window usage bar --------------------------------------------
const cw = s.context_window;
if (cw && typeof cw.used_percentage === "number") {
const used = Math.max(0, Math.min(100, cw.used_percentage));
const CELLS = 14;
const filled = Math.min(CELLS, Math.round((used / 100) * CELLS));
const color = used >= 80 ? "38;5;203" : used >= 60 ? "38;5;179" : "38;5;114";
const bar =
C(color, "▰".repeat(filled)) + C("38;5;238", "▱".repeat(CELLS - filled));
left.push(`${C(DIM, "Context:")} ${bar} ${C(FG, `${Math.round(used)}%`)}`);
}
// --- 💰 Session cost ------------------------------------------------------
const cost = s.cost?.total_cost_usd;
if (typeof cost === "number" && Number.isFinite(cost)) {
left.push(`💰 ${C(DIM, "Cost:")}${C(FG, `$${cost.toFixed(2)}`)}`);
}
// --- 🌿 Git branch + dirty count -----------------------------------------
function git(args) {
try {
return execFileSync("git", ["-C", cwd, ...args], {
encoding: "utf8",
timeout: 1000,
stdio: ["ignore", "pipe", "ignore"],
windowsHide: true,
}).trim();
} catch {
return "";
}
}
let branch = s.worktree?.branch || "";
if (!branch) {
branch = git(["rev-parse", "--abbrev-ref", "HEAD"]);
if (branch === "HEAD") {
const sha = git(["rev-parse", "--short", "HEAD"]);
branch = sha ? `detached@${sha}` : "";
}
}
if (branch) {
const status = git(["status", "--porcelain"]);
const dirty = status ? status.split("\n").filter(Boolean).length : 0;
let seg = `🌿 ${C("38;5;114", branch)}`;
if (dirty > 0) seg += C("38;5;139", `(+${dirty})`);
left.push(seg);
}
// --- ● Reasoning effort (right-aligned) ----------------------------------
const EFFORT_COLOR = {
low: "38;5;75",
medium: "38;5;80",
high: "38;5;114",
xhigh: "38;5;179",
max: "38;5;203",
};
const effort = s.effort?.level;
let right = "";
if (effort) {
right =
`${C(EFFORT_COLOR[effort] || DIM, "●")} ${C(FG, effort)}` +
C("38;5;240", " · /effort");
}
// --- Compose --------------------------------------------------------------
let line = left.join(SEP);
const cols = Number(process.env.COLUMNS) || 0;
if (right) {
const gap = cols - width(line) - width(right);
line += gap > 1 ? " ".repeat(gap) + right : `${SEP}${right}`;
}
process.stdout.write(line);
浙公网安备 33010602011771号