English | 简体中文
Claude Code 自定义 statusline:状态栏显示 GLM 智谱套餐用量 + 会话实时指标(工时/轮次/速率/缓存命中/吞吐,全部本地统计)。
Rust 单二进制,文件级 TTL 缓存,采集-渲染分离。
[glm-4.6] my-project 🌿 main ● 📝 +10-3
🧠 ▓▓▓▓▓░░░░░ 40% ⏱ 12m 💬 42 🎯 87% 🚀 423t/s | 🔄 2 RPM · 19.6K TPM
🔋 13% (⏰ 05:19 · ⌛ 2h7m) | 📅 3% (⏰ 6/16 20:17 · ⌛ 2d17h) | 🔧 112/4000 (⌛ 7d17h)
组内空格紧凑,组间用 CCSL_SEP(默认 |,可设 ❯ 走 powerline 风)分隔:
| 行 | 段 | 语义 |
|---|---|---|
| 行1 | [model] project 🌿 git 📝+N-N |
身份 + git 未提交改动 |
| 行2 | 🧠 ⏱Xm 💬N 🎯hit% 🚀t/s | 🔄 RPM/TPM |
会话状态 + 缓存/吞吐 + 速率 |
| 行3 | 🔋 📅 🔧(组内 | 分隔) |
配额池 |
| 元素 | 颜色 | 规则 |
|---|---|---|
| 进度条 / 百分比 / 计数 | 绿 / 黄 / 红 | 按用量:<80% 绿、80–94% 黄、≥95% 红 |
🎯 缓存命中率 |
绿 / 黄 / 红(反向) | 高=绿好(≥80%)、中=黄(≥50%)、低=红(<50%)——与用量配色方向相反 |
⌛ 剩余时长 |
青(充足)/ 黄(接近刷新) | urgent 阈值:5h 窗口剩 <1h、周/月窗口剩 <1天 转黄警示;窗口已到刷新点显示 now(非倒计时归零) |
⏰ 重置时刻 |
dim 灰 | 弱化次要信息 |
| 其余(💬/🚀/🔄/emoji/model/project) | 无色 | 无明确好坏阈值,不上色避免噪音 |
⚠ stale / ⚠ cfg(行尾追加) |
无色 | 数据冻结(fetch 失败用旧缓存兜底)/ 配置加载失败——提示当前值非实时 |
statusline 数据源分两路:
🔋/📅/🔧:直连智谱 monitor(open.bigmodel.cn),需智谱开放平台 API Key🧠/⏱/💬/🎯/🚀/🔄:全部来自 CC stdin + 本地 transcript,零网络
配额段走单次 HTTP + 文件级缓存;会话段每次实时遍历 transcript,完全不依赖网络。即使智谱 monitor 临时不可用,会话指标仍正常显示。
会话指标全部在一次 transcript 遍历里产出(去重按 message.id,过滤 sidechain/重试产生的重复行):
| 段 | 来源 | 字段/算法 | 周期 |
|---|---|---|---|
[model] |
CC stdin | model.display_name(回退 id) |
— |
project |
CC stdin | workspace.project_dir basename |
— |
🧠 进度条 |
CC stdin | context_window.used_percentage |
当前上下文窗口 |
⏱ 工作时长 |
transcript | 累加各 assistant turn「触发→完成」时长(排除用户离开/思考的空转) | 当前会话(/new 归零) |
💬 轮次 |
transcript | 去重后 assistant 行数 | 当前会话 |
🎯 缓存命中 |
transcript | Σcache_read / Σ(input+cache_read+cache_create) |
当前会话累计 |
🚀 t/s |
transcript | 最近 60s Σoutput / Σ每条 assistant 生成时长(末ts-首ts) |
最近 60s |
🔄 RPM |
transcript | 最近 60s 去重 assistant 数 | 最近 60s |
🔄 TPM |
transcript | 最近 60s Σ(input+output) |
最近 60s |
🔋 |
智谱 quota/limit |
TOKENS_LIMIT unit==3 的 percentage |
5h Token |
📅 |
智谱 quota/limit |
TOKENS_LIMIT unit==6 的 percentage |
周限量 |
🔧 |
智谱 quota/limit |
TIME_LIMIT unit==5 的 currentValue / usage(可被 CCSL_MCP_LIMIT 覆盖) |
MCP 工具调用,月级 |
🌿 git |
project_dir 跑 git |
branch + dirty(●) + ahead(↑N)/behind(↓N) | 实时 |
📝 未提交改动 |
project_dir 跑 git |
git diff HEAD --numstat 累加 |
实时(commit 清零) |
口径说明:
⏱是模型工作时长(累加各 turn「触发→完成」,排除用户空转;非会话墙钟);🚀 t/s是 per-request 口径:窗口内Σoutput / Σ每条消息首→末 ts 跨度(排除消息间思考间隔,贴合「生成速度」语义;span 全 0 时不显示);🎯是会话累计(非最近窗口,长期效果更稳定)。/new开新 transcript 文件,会话段全部归零。
nextResetTime是毫秒时间戳,按北京时间(UTC+8)显示重置时刻;剩余时长⌛是时间差,与时区无关。reset_at已到(窗口刚翻转、待下次采集更新)时⌛显示now而非倒计时。
CC 调用 statusline(事件驱动 + 300ms 防抖;可加 refreshInterval 定时刷新)
↓ stdin(read_to_string,CC 关写端即返回)
main.rs → 解析 CcInput(model/project/🧠/transcript)
↓ 读缓存一次(fresh 判断 + 过期兜底复用同一次读,不二次读盘)
├─ 新鲜(< TTL)→ 用缓存
└─ 过期 → 单次采集(无重试,失败用过期缓存兜底):
└─ 智谱 /monitor/usage/quota/limit → 🔋/📅/🔧
原子写缓存(.tmp + rename)
↓
render.rs → session_stats 一次遍历 transcript 算 ⏱/💬/🎯/🚀/🔄
+ 三行拼接 + git collect(status v2 + numstat,2 进程)→ flush stdout
- 采集-渲染分离:渲染端零网络(智谱走缓存),git 段实时(2 进程),会话指标本地 transcript(零网络)
- 三级降级:新鲜缓存 → 单次采集 → 过期缓存兜底(行尾标
⚠ stale)→ 空快照(只渲染本地段 + 行1) - 会话指标完全不依赖网络:transcript 是本地文件,智谱挂了 ⏱/💬/🎯/🚀/🔄 照常显示
- stdout 显式 flush:statusline 是管道(非 tty),print! 后必须 flush 否则缓冲滞留
前缀 CCSL_。两种放置方式(shell export 优先于 env 文件):
- 方式 A:
~/.env(推荐,被 shell source 进环境) - 方式 B:独立文件
~/.claude/cc-statusline.env(程序自动加载,建议chmod 600)
| 变量 | 必填 | 说明 |
|---|---|---|
CCSL_GLM_TOKEN |
是 | 智谱开放平台 API Key |
CCSL_GLM_BASE_URL |
否 | 默认 https://open.bigmodel.cn/api |
CCSL_CACHE_TTL |
否 | 缓存秒数,默认 120 |
CCSL_CACHE_DIR |
否 | 缓存目录,默认 ~/.claude/cc-statusline |
CCSL_MCP_LIMIT |
否 | 覆盖 🔧 MCP 工具调用上限(智谱 API 不返回上限,或需自定义上限时用) |
CCSL_SEP |
否 | 段分隔符,默认 |(powerline 可设 ❯) |
CCSL_DEBUG |
否 | 1 开调试日志 |
CCSL_GLM_TOKEN缺则只渲染本地段(会话指标 + 身份行),配额段关闭。
cargo build --release
# 二进制:target/release/cc-statusline(~2.2M)curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal
source ~/.cargo/envgit clone https://github.com/Err0rCM/cc-statusline.git
cd cc-statuslinecargo build --release在 ~/.env 或 ~/.claude/cc-statusline.env 加入:
CCSL_GLM_TOKEN=<智谱APIKey>(只需智谱 Key;会话指标走本地 transcript)
mkdir -p ~/.claude/bin
cp target/release/cc-statusline ~/.claude/bin/~/.claude/settings.json 加 statusLine 字段(可选 refreshInterval 让空闲时也定时刷新):
{
"statusLine": {
"type": "command",
"command": "~/.claude/bin/cc-statusline",
"refreshInterval": 30
}
}echo '{"model":{"id":"glm","display_name":"glm"},"workspace":{"project_dir":"/tmp/t"},"context_window":{"used_percentage":40}}' | ~/.claude/bin/cc-statusline应输出完整状态栏。重启 CC,首次会弹工作区信任,接受即可。
| 变量 | 位置 |
|---|---|
CCSL_GLM_TOKEN |
open.bigmodel.cn 控制台 → API Keys |
- 缓存文件:
~/.claude/cc-statusline/stats.json(原子写:.tmp+rename,防并发读到半截 JSON) - 渲染时读缓存一次:新鲜(< TTL,默认 120s)直接用;过期才同步采集,单次请求不重试(失败即用过期缓存兜底,避免 statusline 长时间阻塞)
- 采集失败 → 过期缓存兜底 → 连缓存也没有则只渲染本地段,状态栏不空白
- 会话指标(⏱/💬/🎯/🚀/🔄)不经此缓存:每次实时遍历 transcript,反映当前会话
- git 段(🌿/📝)也不经缓存:每次实时跑
git status+git diff(2 进程)
双层刷新配合:CC 的
refreshInterval(调 statusline 的频率)应 ≥ 项目的CCSL_CACHE_TTL(智谱数据新鲜度),否则频繁刷新只读到同一份缓存。会话指标不受 TTL 影响(每次遍历 transcript 实时算)。
CCSL_DEBUG=1 claude
# 日志:~/.claude/cc-statusline/debug.log| 症状 | 可能原因 | 解法 |
|---|---|---|
| 配额段(🔋/📅/🔧)不显示 | CCSL_GLM_TOKEN 缺 / 智谱 401 |
确认是智谱开放平台 key(非对话用的 sk-) |
配额段不更新、⌛ 卡 now 且行尾 ⚠ stale |
fetch 超时(DNS 慢 / 网络断 / token 失效) | 代码已设 RES_OPTIONS=timeout:2 attempts:2 缓解 DNS 死等;查 debug.log 看 fetch: failed 原因 |
| 会话段(⏱/💬/🎯/🚀/🔄)不显示 | transcript_path 未传 / 文件读不出 | 通常 CC 总会传;查 debug.log 的 stdin 记录 |
🚀 t/s 时有时无 |
窗口内无 assistant 或所有消息首末 ts 相同(span=0,除零保护) | 正常:单行或同秒请求算不出速率 |
| 每次都卡(不命中缓存) | 缓存写入失败 / TTL 过短 | 查 debug.log;确认 ~/.claude/cc-statusline/ 可写 |
| 配色不显示 | 终端不支持 ANSI / NO_COLOR 设置 |
多数终端支持;检查环境 |
| 状态栏完全不显示 | stdout 缓冲未 flush / 进程被 CC 超时杀 | 已内置 flush;查 debug.log 有无输出记录 |
MIT — 见 LICENSE。