@cxmyu/ccglance 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -3
- package/README.zh-CN.md +7 -3
- package/dist/cli.js +9 -1
- package/dist/defaults/index.js +2 -2
- package/dist/segments/index.js +53 -13
- package/docs/assets/preview-macos.png +0 -0
- package/docs/assets/preview-windows.png +0 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
**A fast, zero-dependency, multi-line status line for [Claude Code](https://docs.anthropic.com/en/docs/claude-code)**
|
|
6
6
|
|
|
7
|
-
model · effort · context · cache · git · session — all at a glance
|
|
7
|
+
model · effort · context · prompt cache · limits · git · session — all at a glance
|
|
8
8
|
|
|
9
9
|
[](https://nodejs.org/)
|
|
10
10
|
[](./LICENSE)
|
|
11
11
|
|
|
12
12
|
[English](./README.md) · [简体中文](./README.zh-CN.md) · [GitHub](https://github.com/CxMYu/CcGlanceLine)
|
|
13
13
|
|
|
14
|
-
**Windows 11 · Segoe UI Emoji**
|
|
14
|
+
**Windows 11 · Segoe UI Emoji · Claude Code 2.1.258 sample**
|
|
15
15
|
|
|
16
16
|

|
|
17
17
|
|
|
18
|
-
**macOS · Apple Color Emoji**
|
|
18
|
+
**macOS · Apple Color Emoji · Claude Code 2.1.258 sample**
|
|
19
19
|
|
|
20
20
|

|
|
21
21
|
|
|
@@ -23,6 +23,12 @@ model · effort · context · cache · git · session — all at a glance
|
|
|
23
23
|
|
|
24
24
|
> **stdin-first · zero runtime dependencies · fixed emoji style** — renders the JSON Claude Code pipes to its status-line command; only the `status` segment reads a bounded transcript tail. Written in TypeScript, shipped as compiled JavaScript; runs on Node.js ≥ 22 or Bun.
|
|
25
25
|
|
|
26
|
+
Current Claude Code cache and usage-limit fields are covered, including the
|
|
27
|
+
latest request's prompt-cache hit ratio and token traffic, warm/cold state, and
|
|
28
|
+
the Hour, Week, and account Limit usage windows.
|
|
29
|
+
Older Claude Code versions keep working through optional fields and the legacy
|
|
30
|
+
cache calculation.
|
|
31
|
+
|
|
26
32
|
**Docs:** [Overview](./docs/overview.md) · [Segments & icons](./docs/segments.md) · [Development](./docs/development.md)
|
|
27
33
|
|
|
28
34
|
## Terminal Font
|
package/README.zh-CN.md
CHANGED
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
**面向 [Claude Code](https://docs.anthropic.com/en/docs/claude-code) 的快速、零依赖多行状态栏**
|
|
6
6
|
|
|
7
|
-
模型 · effort · 上下文 ·
|
|
7
|
+
模型 · effort · 上下文 · prompt cache · 限额 · git · 会话 —— 一眼尽览
|
|
8
8
|
|
|
9
9
|
[](https://nodejs.org/)
|
|
10
10
|
[](./LICENSE)
|
|
11
11
|
|
|
12
12
|
[English](./README.md) · [简体中文](./README.zh-CN.md) · [GitHub](https://github.com/CxMYu/CcGlanceLine)
|
|
13
13
|
|
|
14
|
-
**Windows 11 · Segoe UI Emoji
|
|
14
|
+
**Windows 11 · Segoe UI Emoji · Claude Code 2.1.258 示例**
|
|
15
15
|
|
|
16
16
|

|
|
17
17
|
|
|
18
|
-
**macOS · Apple Color Emoji
|
|
18
|
+
**macOS · Apple Color Emoji · Claude Code 2.1.258 示例**
|
|
19
19
|
|
|
20
20
|

|
|
21
21
|
|
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
|
|
24
24
|
> **stdin 优先 · 运行时零依赖 · 固定 emoji 风格** —— 渲染 Claude Code 经 stdin 传入的 JSON;仅 `status` 段读取 transcript 尾部固定字节。TypeScript 编写,以编译后的 JavaScript 发布,可在 Node.js ≥ 22 或 Bun 上运行。
|
|
25
25
|
|
|
26
|
+
已覆盖新版 Claude Code 的缓存和限额字段,包括最近一次请求的 prompt cache 命中率与
|
|
27
|
+
token 流量、缓存冷热状态,以及 Hour、Week 和账户 Limit 三类用量窗口。旧版 Claude Code 缺少这些可选字段时,
|
|
28
|
+
仍会自动沿用原有缓存计算逻辑。
|
|
29
|
+
|
|
26
30
|
**文档:** [概览](./docs/overview.zh-CN.md) · [字段与图标](./docs/segments.zh-CN.md) · [开发](./docs/development.zh-CN.md)
|
|
27
31
|
|
|
28
32
|
## 终端字体
|
package/dist/cli.js
CHANGED
|
@@ -13,16 +13,24 @@ const PREVIEW_SAMPLE = {
|
|
|
13
13
|
used_percentage: 23.5, remaining_percentage: 76.5,
|
|
14
14
|
current_usage: { output_tokens: 1200, cache_read_input_tokens: 172000, cache_creation_input_tokens: 15000 },
|
|
15
15
|
},
|
|
16
|
+
prompt_cache: {
|
|
17
|
+
warm: true, caching_observed: true, ttl: '1h',
|
|
18
|
+
expires_at: Math.floor(Date.now() / 1000) + 45 * 60,
|
|
19
|
+
requests: 14, misses: 2, expected_rebuilds: 1, hit_ratio: 0.91,
|
|
20
|
+
cache_write_tokens: 352000, miss_recache_tokens: 310200,
|
|
21
|
+
recache_tokens_if_cold: 45000,
|
|
22
|
+
},
|
|
16
23
|
output_style: { name: 'default' },
|
|
17
24
|
rate_limits: {
|
|
18
25
|
five_hour: { used_percentage: 23.5, resets_at: Math.floor(Date.now() / 1000) + 2 * 3600 },
|
|
19
26
|
seven_day: { used_percentage: 41.2, resets_at: Math.floor(Date.now() / 1000) + 3 * 86400 },
|
|
27
|
+
spend_limit: { used_percentage: 62.8, resets_at: Math.floor(Date.now() / 1000) + 30 * 86400 },
|
|
20
28
|
},
|
|
21
29
|
workspace: { current_dir: process.cwd() },
|
|
22
30
|
worktree: { name: 'main', branch: 'main' },
|
|
23
31
|
session_name: 'ccglance',
|
|
24
32
|
cost: { total_cost_usd: 0.1234, total_duration_ms: 192000, total_lines_added: 156, total_lines_removed: 23 },
|
|
25
|
-
version: '2.1.
|
|
33
|
+
version: '2.1.258',
|
|
26
34
|
};
|
|
27
35
|
const argv = process.argv.slice(2);
|
|
28
36
|
// 用法 + 「安装后要做什么」指引。终端直接运行或 --help 时打印;此路径绝不读 stdin。
|
package/dist/defaults/index.js
CHANGED
|
@@ -26,11 +26,11 @@ exports.DEFAULT_SPEC = {
|
|
|
26
26
|
cache: { enabled: true },
|
|
27
27
|
rate_limits: {
|
|
28
28
|
enabled: true,
|
|
29
|
-
show: '
|
|
29
|
+
show: 'all',
|
|
30
30
|
warnPct: 70,
|
|
31
31
|
dangerPct: 90,
|
|
32
32
|
showReset: true,
|
|
33
|
-
labels: { five_hour: 'Hour', seven_day: 'Week' },
|
|
33
|
+
labels: { five_hour: 'Hour', seven_day: 'Week', spend_limit: 'Limit' },
|
|
34
34
|
},
|
|
35
35
|
style: { enabled: true },
|
|
36
36
|
dir: { enabled: true, fullPath: false },
|
package/dist/segments/index.js
CHANGED
|
@@ -31,8 +31,22 @@ function positive(v) {
|
|
|
31
31
|
function statusIcon(ctx, key, fallback) {
|
|
32
32
|
return opt(ctx, 'status').statusIcons?.[key] || fallback;
|
|
33
33
|
}
|
|
34
|
-
function fmtRatePct(v) {
|
|
35
|
-
|
|
34
|
+
function fmtRatePct(v, allowOver100 = false) {
|
|
35
|
+
const rounded = Math.max(0, Math.round(v));
|
|
36
|
+
return (allowOver100 ? rounded : Math.min(100, rounded)) + '%';
|
|
37
|
+
}
|
|
38
|
+
// Prompt-cache TTLs are short; minute precision stays compact and avoids a noisy seconds countdown.
|
|
39
|
+
function fmtCacheRemaining(epochSec, nowMs) {
|
|
40
|
+
const expiry = num(epochSec);
|
|
41
|
+
if (expiry == null)
|
|
42
|
+
return null;
|
|
43
|
+
const ms = expiry * 1000 - nowMs;
|
|
44
|
+
if (ms <= 0)
|
|
45
|
+
return null;
|
|
46
|
+
const minutes = Math.max(1, Math.ceil(ms / 60000));
|
|
47
|
+
const hours = Math.floor(minutes / 60);
|
|
48
|
+
const rest = minutes % 60;
|
|
49
|
+
return hours ? `${hours}h${rest ? `${rest}m` : ''}` : `${minutes}m`;
|
|
36
50
|
}
|
|
37
51
|
// 会话状态:读 transcript 尾部推断;默认仅显示图标,工具态附带工具名。
|
|
38
52
|
const status = (ctx) => {
|
|
@@ -93,12 +107,34 @@ const cache = (ctx) => {
|
|
|
93
107
|
const cw = ctx.data.context_window;
|
|
94
108
|
if (!cw)
|
|
95
109
|
return null;
|
|
96
|
-
const cu = cw.current_usage
|
|
97
|
-
const
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
const
|
|
101
|
-
|
|
110
|
+
const cu = cw.current_usage;
|
|
111
|
+
const read = nonNegative(cu?.cache_read_input_tokens) ?? 0;
|
|
112
|
+
const write = nonNegative(cu?.cache_creation_input_tokens) ?? 0;
|
|
113
|
+
const fresh = nonNegative(cu?.input_tokens);
|
|
114
|
+
const latestTotal = fresh != null
|
|
115
|
+
? fresh + read + write
|
|
116
|
+
: nonNegative(cw.total_input_tokens);
|
|
117
|
+
const latestHitPct = cu && latestTotal != null
|
|
118
|
+
? latestTotal > 0 ? Math.max(0, Math.min(100, read / latestTotal * 100)) : 0
|
|
119
|
+
: null;
|
|
120
|
+
const pc = ctx.data.prompt_cache;
|
|
121
|
+
const ratio = pc?.caching_observed === true ? num(pc.hit_ratio) : null;
|
|
122
|
+
const sessionHitPct = ratio != null ? Math.max(0, Math.min(1, ratio)) * 100 : null;
|
|
123
|
+
const parts = latestHitPct != null
|
|
124
|
+
? [(0, format_1.fmtPct)(latestHitPct), `↓${(0, format_1.fmtTokens)(read)}`, `↑${(0, format_1.fmtTokens)(write)}`]
|
|
125
|
+
: sessionHitPct != null
|
|
126
|
+
? [`Avg ${(0, format_1.fmtPct)(sessionHitPct)}`]
|
|
127
|
+
: ['0%', '↓0', '↑0'];
|
|
128
|
+
if (pc?.caching_observed === true && pc.warm === true) {
|
|
129
|
+
const remaining = fmtCacheRemaining(pc.expires_at, ctx.nowMs);
|
|
130
|
+
const ttl = typeof pc.ttl === 'string' ? pc.ttl.trim() : '';
|
|
131
|
+
parts.push(`🔥${remaining || ttl}`);
|
|
132
|
+
}
|
|
133
|
+
else if (pc?.caching_observed === true && pc.warm === false) {
|
|
134
|
+
const recache = positive(pc.recache_tokens_if_cold);
|
|
135
|
+
parts.push(`🧊${recache != null ? `↻${(0, format_1.fmtTokens)(recache)}` : ''}`);
|
|
136
|
+
}
|
|
137
|
+
return iconSeg(ctx, 'cache', colors_1.C.cache, 'cache', parts.join(colors_1.DOT));
|
|
102
138
|
};
|
|
103
139
|
const rateLimits = (ctx) => {
|
|
104
140
|
const rl = ctx.data.rate_limits;
|
|
@@ -110,6 +146,7 @@ const rateLimits = (ctx) => {
|
|
|
110
146
|
const labels = {
|
|
111
147
|
five_hour: o.labels?.five_hour || 'Hour',
|
|
112
148
|
seven_day: o.labels?.seven_day || 'Week',
|
|
149
|
+
spend_limit: o.labels?.spend_limit || 'Limit',
|
|
113
150
|
};
|
|
114
151
|
const normal = optTextColor(ctx, 'rate_limits', colors_1.C.rate);
|
|
115
152
|
const bold = optBold(ctx, 'rate_limits');
|
|
@@ -123,18 +160,18 @@ const rateLimits = (ctx) => {
|
|
|
123
160
|
: pct >= 10 ? '🌒' : '🌑';
|
|
124
161
|
return (0, colors_1.paint)(color, glyph, bold);
|
|
125
162
|
};
|
|
126
|
-
const pushWindow = (label, win) => {
|
|
127
|
-
|
|
163
|
+
const pushWindow = (label, win, allowOver100 = false) => {
|
|
164
|
+
const pct = nonNegative(win?.used_percentage);
|
|
165
|
+
if (pct == null)
|
|
128
166
|
return;
|
|
129
|
-
const pct = win.used_percentage;
|
|
130
167
|
const warn = o.warnPct != null ? o.warnPct : 70;
|
|
131
168
|
const danger = o.dangerPct != null ? o.dangerPct : 90;
|
|
132
169
|
const winColor = pctColor(pct, warn, danger, normal);
|
|
133
|
-
const reset = showReset ? (0, format_1.fmtResetIn)(win
|
|
170
|
+
const reset = showReset ? (0, format_1.fmtResetIn)(win?.resets_at, ctx.nowMs) : null;
|
|
134
171
|
const detail = [
|
|
135
172
|
(0, colors_1.paint)(normal, label, bold),
|
|
136
173
|
meter(pct, winColor),
|
|
137
|
-
(0, colors_1.paint)(winColor, fmtRatePct(pct), bold),
|
|
174
|
+
(0, colors_1.paint)(winColor, fmtRatePct(pct, allowOver100), bold),
|
|
138
175
|
];
|
|
139
176
|
if (reset)
|
|
140
177
|
detail.push((0, colors_1.paint)(colors_1.C.rateReset, '⏳', bold), (0, colors_1.paint)(colors_1.C.rateReset, reset, bold));
|
|
@@ -147,6 +184,9 @@ const rateLimits = (ctx) => {
|
|
|
147
184
|
if (wants(['all', 'both', 'seven_day'])) {
|
|
148
185
|
pushWindow(labels.seven_day, rl.seven_day);
|
|
149
186
|
}
|
|
187
|
+
if (wants(['all', 'spend_limit'])) {
|
|
188
|
+
pushWindow(labels.spend_limit, rl.spend_limit, true);
|
|
189
|
+
}
|
|
150
190
|
if (!parts.length)
|
|
151
191
|
return null;
|
|
152
192
|
const col = pctColor(maxUsed, o.warnPct != null ? o.warnPct : 70, o.dangerPct != null ? o.dangerPct : 90, normal);
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cxmyu/ccglance",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "A fast, zero-dependency
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "A fast, zero-dependency Claude Code status line for model, effort, context, prompt cache, usage limits, git and session.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ccglance": "dist/cli.js"
|
|
7
7
|
},
|