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);

posted @ 2026-08-21 09:43  so易杰  阅读(15)  评论(0)    收藏  举报