@cxmyu/ccglance 1.1.1 → 1.2.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 +17 -0
- package/README.zh-CN.md +14 -0
- package/dist/cli.js +3 -2
- package/dist/defaults/index.js +4 -2
- package/dist/render/colors.js +2 -1
- package/dist/render/icons.js +2 -0
- package/dist/runtime/bg.js +40 -22
- package/dist/runtime/version.js +1 -1
- package/dist/segments/index.js +33 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,6 +19,18 @@ model · effort · context · cache · git · session — all at a glance
|
|
|
19
19
|
|
|
20
20
|
**Docs:** [Overview](./docs/overview.md) · [Segments & icons](./docs/segments.md) · [Development](./docs/development.md)
|
|
21
21
|
|
|
22
|
+
## Terminal Font
|
|
23
|
+
|
|
24
|
+
Use a Nerd Font in your terminal so emoji, Nerd Font icons, arrows, and box-like
|
|
25
|
+
symbols keep consistent width. [Maple Mono NF](https://github.com/subframe7536/maple-font)
|
|
26
|
+
is a good default; use `Maple Mono NF CN` if you want better CJK coverage.
|
|
27
|
+
|
|
28
|
+
ccglance intentionally outputs standard Unicode emoji. A Nerd Font improves text
|
|
29
|
+
metrics and symbol coverage, but color emoji are still rendered by the operating
|
|
30
|
+
system's emoji font (for example Segoe UI Emoji on Windows, Apple Color Emoji on
|
|
31
|
+
macOS, and Noto Color Emoji on many Linux desktops), so their artwork can differ
|
|
32
|
+
across platforms.
|
|
33
|
+
|
|
22
34
|
## Install
|
|
23
35
|
|
|
24
36
|
### Option A — npm (global, recommended)
|
|
@@ -83,6 +95,11 @@ Add a `statusLine` block to `~/.claude/settings.json`:
|
|
|
83
95
|
}
|
|
84
96
|
```
|
|
85
97
|
|
|
98
|
+
On Claude Code >= 2.1.97, you can optionally add `"refreshInterval": 30`
|
|
99
|
+
inside `statusLine` to keep elapsed time, quota resets, version hints, and other
|
|
100
|
+
time-based fields moving while the main session is idle. Keep the base block
|
|
101
|
+
above when compatibility with older Claude Code versions matters.
|
|
102
|
+
|
|
86
103
|
If you didn't install globally, point Node at the compiled file directly:
|
|
87
104
|
|
|
88
105
|
```json
|
package/README.zh-CN.md
CHANGED
|
@@ -19,6 +19,16 @@
|
|
|
19
19
|
|
|
20
20
|
**文档:** [概览](./docs/overview.zh-CN.md) · [字段与图标](./docs/segments.zh-CN.md) · [开发](./docs/development.zh-CN.md)
|
|
21
21
|
|
|
22
|
+
## 终端字体
|
|
23
|
+
|
|
24
|
+
终端建议使用 Nerd Font,避免 emoji、Nerd Font 图标、箭头和类进度符号宽度不一致。
|
|
25
|
+
首选可以用 [Maple Mono NF](https://github.com/subframe7536/maple-font);
|
|
26
|
+
需要更好的中文显示时用 `Maple Mono NF CN`。
|
|
27
|
+
|
|
28
|
+
ccglance 会固定输出标准 Unicode emoji。Nerd Font 可以改善文本宽度和符号覆盖,
|
|
29
|
+
但彩色 emoji 仍由系统 emoji 字体渲染(例如 Windows 的 Segoe UI Emoji、
|
|
30
|
+
macOS 的 Apple Color Emoji、很多 Linux 桌面的 Noto Color Emoji),所以不同平台的图案可能不同。
|
|
31
|
+
|
|
22
32
|
## 安装
|
|
23
33
|
|
|
24
34
|
### 方式 A —— npm 全局安装(推荐)
|
|
@@ -79,6 +89,10 @@ node dist/cli.js preview
|
|
|
79
89
|
}
|
|
80
90
|
```
|
|
81
91
|
|
|
92
|
+
Claude Code >= 2.1.97 可在 `statusLine` 内可选增加 `"refreshInterval": 30`,
|
|
93
|
+
让会话时长、配额重置、版本提示等时间相关字段在主会话空闲时也能更新。
|
|
94
|
+
若需兼容更旧的 Claude Code,保持上面的基础配置即可。
|
|
95
|
+
|
|
82
96
|
若未全局安装,直接用 Node 指向编译后的文件:
|
|
83
97
|
|
|
84
98
|
```json
|
package/dist/cli.js
CHANGED
|
@@ -4,8 +4,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
const readers_1 = require("./readers");
|
|
5
5
|
// preview 子命令用的内置样例(覆盖默认状态栏会展示的常规字段)
|
|
6
6
|
const PREVIEW_SAMPLE = {
|
|
7
|
-
model: { display_name: 'Opus
|
|
7
|
+
model: { display_name: 'Opus 5', id: 'claude-opus-5[1m]' },
|
|
8
8
|
effort: { level: 'high' },
|
|
9
|
+
thinking: { enabled: true },
|
|
9
10
|
fast_mode: true,
|
|
10
11
|
context_window: {
|
|
11
12
|
context_window_size: 1000000, total_input_tokens: 235000, total_output_tokens: 1200,
|
|
@@ -21,7 +22,7 @@ const PREVIEW_SAMPLE = {
|
|
|
21
22
|
worktree: { name: 'main', branch: 'main' },
|
|
22
23
|
session_name: 'ccglance',
|
|
23
24
|
cost: { total_cost_usd: 0.1234, total_duration_ms: 192000, total_lines_added: 156, total_lines_removed: 23 },
|
|
24
|
-
version: '2.
|
|
25
|
+
version: '2.1.221',
|
|
25
26
|
};
|
|
26
27
|
const argv = process.argv.slice(2);
|
|
27
28
|
// 用法 + 「安装后要做什么」指引。终端直接运行或 --help 时打印;此路径绝不读 stdin。
|
package/dist/defaults/index.js
CHANGED
|
@@ -6,9 +6,9 @@ exports.DEFAULT_SPEC = {
|
|
|
6
6
|
mode: 'responsive',
|
|
7
7
|
separator: ' | ',
|
|
8
8
|
rows: [
|
|
9
|
-
['model', 'effort', 'status', 'fast', 'context', 'cache', 'style'], // 运行时
|
|
9
|
+
['model', 'agent', 'effort', 'status', 'fast', 'context', 'cache', 'style'], // 运行时
|
|
10
10
|
['rate_limits'], // 订阅(无订阅→整行消失)
|
|
11
|
-
['dir', 'git', 'session_name', 'session', 'cost', 'version'], // 项目/会话
|
|
11
|
+
['dir', 'git', 'pr', 'session_name', 'session', 'cost', 'version'], // 项目/会话
|
|
12
12
|
],
|
|
13
13
|
minWidth: 80,
|
|
14
14
|
},
|
|
@@ -19,6 +19,7 @@ exports.DEFAULT_SPEC = {
|
|
|
19
19
|
statusIcons: { idle: '✅', paused: '⏸️', thinking: '💭', working: '⚙️', tool: '🔧' },
|
|
20
20
|
},
|
|
21
21
|
model: { enabled: true },
|
|
22
|
+
agent: { enabled: true },
|
|
22
23
|
effort: { enabled: true },
|
|
23
24
|
fast: { enabled: true },
|
|
24
25
|
context: { enabled: true, percentOnly: false, warnPct: 75, dangerPct: 90 },
|
|
@@ -34,6 +35,7 @@ exports.DEFAULT_SPEC = {
|
|
|
34
35
|
style: { enabled: true },
|
|
35
36
|
dir: { enabled: true, fullPath: false },
|
|
36
37
|
git: { enabled: true, ttlMs: 20 * 60 * 1000 },
|
|
38
|
+
pr: { enabled: true },
|
|
37
39
|
session_name: { enabled: true },
|
|
38
40
|
session: { enabled: true },
|
|
39
41
|
cost: { enabled: true },
|
package/dist/render/colors.js
CHANGED
|
@@ -15,7 +15,7 @@ const paint = (code, s, bold = false) => `\x1b[${bold ? '1;' : ''}${code}m${(0,
|
|
|
15
15
|
exports.paint = paint;
|
|
16
16
|
exports.C = {
|
|
17
17
|
// 第一行(运行时)
|
|
18
|
-
model: CYAN, effort: YELLOW, fast: GREEN,
|
|
18
|
+
model: CYAN, agent: MAGENTA, effort: YELLOW, fast: GREEN,
|
|
19
19
|
ctx: MAGENTA, cache: GREEN, style: CYAN,
|
|
20
20
|
rate: CYAN, // rate_limits 主图标/标签
|
|
21
21
|
rateReset: YELLOW, // 配额重置时间
|
|
@@ -31,6 +31,7 @@ exports.C = {
|
|
|
31
31
|
name: MAGENTA, dirIcon: YELLOW, dirText: GREEN, git: WHITE,
|
|
32
32
|
gitClean: GREEN, gitDirty: BLUE, gitConflict: RED,
|
|
33
33
|
gitAhead: GREEN, gitBehind: BLUE,
|
|
34
|
+
pr: CYAN, prApproved: GREEN, prPending: YELLOW, prChanges: RED, prDraft: WHITE,
|
|
34
35
|
sess: CYAN, add: GREEN, del: RED,
|
|
35
36
|
cost: YELLOW, // 美元成本
|
|
36
37
|
wt: GREEN, // worktree
|
package/dist/render/icons.js
CHANGED
package/dist/runtime/bg.js
CHANGED
|
@@ -101,30 +101,48 @@ function runVersionTask(cacheFile, done) {
|
|
|
101
101
|
catch { /* ignore */ }
|
|
102
102
|
done();
|
|
103
103
|
};
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
finish('');
|
|
104
|
+
const requestVersion = (url, parse, callback) => {
|
|
105
|
+
let settled = false;
|
|
106
|
+
const settle = (version) => {
|
|
107
|
+
if (settled)
|
|
108
|
+
return;
|
|
109
|
+
settled = true;
|
|
110
|
+
callback(version);
|
|
111
|
+
};
|
|
112
|
+
try {
|
|
113
|
+
const https = require('https');
|
|
114
|
+
const req = https.get(url, (r) => {
|
|
115
|
+
if (r.statusCode !== 200) {
|
|
116
|
+
r.resume();
|
|
117
|
+
return settle('');
|
|
119
118
|
}
|
|
119
|
+
let d = '';
|
|
120
|
+
r.on('data', (c) => { d += c; });
|
|
121
|
+
r.on('end', () => {
|
|
122
|
+
try {
|
|
123
|
+
settle(parse(d));
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
settle('');
|
|
127
|
+
}
|
|
128
|
+
});
|
|
120
129
|
});
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
130
|
+
req.on('error', () => settle(''));
|
|
131
|
+
req.setTimeout(5000, () => { req.destroy(); settle(''); });
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
settle('');
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
// Claude Code 新版优先跟随官方 rolling-latest 端点;旧版/npm 发布链仍作回退。
|
|
138
|
+
requestVersion('https://downloads.claude.ai/claude-code-releases/latest', (body) => {
|
|
139
|
+
const version = body.trim();
|
|
140
|
+
return /^\d+\.\d+\.\d+$/.test(version) ? version : '';
|
|
141
|
+
}, (official) => {
|
|
142
|
+
if (official)
|
|
143
|
+
return finish(official);
|
|
144
|
+
requestVersion('https://registry.npmjs.org/@anthropic-ai/claude-code/latest', (body) => JSON.parse(body).version || '', finish);
|
|
145
|
+
});
|
|
128
146
|
}
|
|
129
147
|
// 每次运行都做的轻清理:删除过期的孤儿瞬时产物(.refresh / .tmp),以及历史遗留的
|
|
130
148
|
// tasks/ 目录内容。成本很低(这些目录文件很少),能让残留不再累积。
|
package/dist/runtime/version.js
CHANGED
|
@@ -9,7 +9,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const paths_1 = require("../utils/paths");
|
|
11
11
|
const refresh_1 = require("./refresh");
|
|
12
|
-
const CACHE_TTL_MS =
|
|
12
|
+
const CACHE_TTL_MS = 2 * 3600 * 1000;
|
|
13
13
|
const REFRESH_THROTTLE_MS = 60 * 1000;
|
|
14
14
|
const cacheFile = path_1.default.join((0, paths_1.cacheDir)('version'), 'claude-code.json');
|
|
15
15
|
const refreshFile = path_1.default.join((0, paths_1.cacheDir)('version'), 'claude-code.refresh');
|
package/dist/segments/index.js
CHANGED
|
@@ -52,7 +52,18 @@ const status = (ctx) => {
|
|
|
52
52
|
};
|
|
53
53
|
const model = (ctx) => ctx.data.model && (ctx.data.model.display_name || ctx.data.model.id)
|
|
54
54
|
? iconSeg(ctx, 'model', colors_1.C.model, 'model', (0, format_1.modelName)(ctx.data.model)) : null;
|
|
55
|
-
const
|
|
55
|
+
const agent = (ctx) => ctx.data.agent?.name ? iconSeg(ctx, 'agent', colors_1.C.agent, 'agent', ctx.data.agent.name) : null;
|
|
56
|
+
// 旧版只有 effort.level;新版额外提供 thinking.enabled。字段缺失时保持旧输出。
|
|
57
|
+
const effort = ({ data }) => {
|
|
58
|
+
const level = data.effort?.level;
|
|
59
|
+
const thinking = data.thinking?.enabled;
|
|
60
|
+
if (!level && thinking == null)
|
|
61
|
+
return null;
|
|
62
|
+
const text = level
|
|
63
|
+
? `${level}${thinking === false ? ' ⊘' : ''}`
|
|
64
|
+
: thinking ? '✓' : '⊘';
|
|
65
|
+
return (0, colors_1.seg)(colors_1.C.effort, '🧠', text);
|
|
66
|
+
};
|
|
56
67
|
const fast = (ctx) => ctx.data.fast_mode ? iconSeg(ctx, 'fast', colors_1.C.fast, 'fast', 'fast') : null;
|
|
57
68
|
const context = (ctx) => {
|
|
58
69
|
const cw = ctx.data.context_window;
|
|
@@ -76,6 +87,8 @@ const context = (ctx) => {
|
|
|
76
87
|
const parts = [(0, format_1.fmtPct)(pct), `↓${(0, format_1.fmtTokens)(used)}`, `↑${(0, format_1.fmtTokens)(out)}`];
|
|
77
88
|
if (remain != null)
|
|
78
89
|
parts.push(`→${(0, format_1.fmtTokens)(remain)}`);
|
|
90
|
+
if (ctx.data.exceeds_200k_tokens)
|
|
91
|
+
parts.push('⚠200k+');
|
|
79
92
|
return iconSeg(ctx, 'context', col, 'context', parts.join(colors_1.DOT));
|
|
80
93
|
};
|
|
81
94
|
const cache = (ctx) => {
|
|
@@ -162,7 +175,23 @@ const git = (ctx) => {
|
|
|
162
175
|
if (!cwd)
|
|
163
176
|
return null;
|
|
164
177
|
const { gitSegment } = require('../runtime/git');
|
|
165
|
-
|
|
178
|
+
const worktreeName = ctx.data.worktree?.name || ctx.data.workspace?.git_worktree;
|
|
179
|
+
return gitSegment(cwd, optIcon(ctx, 'git', 'git'), opt(ctx, 'git'), ctx.data.worktree?.branch, worktreeName);
|
|
180
|
+
};
|
|
181
|
+
const pr = (ctx) => {
|
|
182
|
+
const number = ctx.data.pr?.number;
|
|
183
|
+
if (typeof number !== 'number' || !Number.isFinite(number) || number <= 0)
|
|
184
|
+
return null;
|
|
185
|
+
const state = ctx.data.pr?.review_state;
|
|
186
|
+
const states = {
|
|
187
|
+
approved: { glyph: '✓', color: colors_1.C.prApproved },
|
|
188
|
+
pending: { glyph: '○', color: colors_1.C.prPending },
|
|
189
|
+
changes_requested: { glyph: '!', color: colors_1.C.prChanges },
|
|
190
|
+
draft: { glyph: '◌', color: colors_1.C.prDraft },
|
|
191
|
+
};
|
|
192
|
+
const review = state ? states[state] : undefined;
|
|
193
|
+
const text = `#${number}${review ? ` ${review.glyph}` : ''}`;
|
|
194
|
+
return iconSeg(ctx, 'pr', review?.color ?? colors_1.C.pr, 'pr', text);
|
|
166
195
|
};
|
|
167
196
|
const sessionName = ({ data }) => data.session_name ? (0, colors_1.seg)(colors_1.C.name, '🏷️', data.session_name) : null;
|
|
168
197
|
const session = (ctx) => {
|
|
@@ -195,9 +224,9 @@ const version = (ctx) => {
|
|
|
195
224
|
};
|
|
196
225
|
exports.SEGMENTS = {
|
|
197
226
|
// 运行时
|
|
198
|
-
status, model, effort, fast, context, cache, style,
|
|
227
|
+
status, model, agent, effort, fast, context, cache, style,
|
|
199
228
|
// 订阅
|
|
200
229
|
rate_limits: rateLimits,
|
|
201
230
|
// 项目 / 会话
|
|
202
|
-
dir, git, session_name: sessionName, session, cost, version,
|
|
231
|
+
dir, git, pr, session_name: sessionName, session, cost, version,
|
|
203
232
|
};
|
package/package.json
CHANGED