cc-usage-bar 0.4.0 → 0.4.2

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/AGENTS.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # AGENTS.md — cc-usage-bar 全功能说明
2
2
 
3
- > 这份文件是面向 AI 助手(Claude Code、Cursor、Codex 等)的安装/配置说明。如果用户对你说「装 cc-usage-bar」「帮我配 statusline 用量条」「装下 cc-usage-bar 帮我配好」之类的话,请按本文档完成全部步骤。**默认无需向用户追加确认**,除以下情况:用户的现有 `statusLine.command` 看上去包含定制脚本而你不确定如何保留时;或者用户没登录过 Claude Code(凭证查不到)。
3
+ > 这份文件是面向 AI 助手(Claude Code、Cursor、Codex 等)的安装/配置说明。如果用户对你说「装 cc-usage-bar」「帮我配 statusline 用量条」「装下 cc-usage-bar 帮我配好」之类的话,请按本文档完成全部步骤。**默认无需向用户追加确认**;只有用户没登录过 Claude Code(凭证查不到)时才停下来让用户先登录。
4
4
 
5
5
  ## 1. 这个包是什么
6
6
 
@@ -18,6 +18,8 @@
18
18
 
19
19
  > **用户只描述偏好,你把 `statusLine.command` 配成 `cc-usage-bar-wrap`,并保留用户原有前缀。**
20
20
 
21
+ 如果已有 `statusLine.command`、`statusline-command.sh`、自定义 shell 脚本、git/path/model 展示等前缀内容,**一律视为要保留的前缀**:按 3.4 抽出它,并用 `cc-usage-bar-wrap --prefix=...` 串起来。不要询问是否覆盖、追加或暂不修改;追加保留是本项目默认行为。
22
+
21
23
  ## 3. 安装流程(必走)
22
24
 
23
25
  按顺序执行,每一步执行前简要告知用户:
@@ -39,7 +41,7 @@ which cc-usage-bar-wrap && which cc-usage-fetch
39
41
  where.exe cc-usage-bar-wrap
40
42
  ```
41
43
 
42
- 要求:`cc-usage-bar` ≥ **0.4.0**(自适应换行 + 周限额上色 + countdown 预设 + 颜色 ramp 自定义)。已装旧版的话用 `npm i -g cc-usage-bar@latest` 升级。
44
+ 要求:`cc-usage-bar` ≥ **0.4.1**(自适应换行 + 周限额上色 + countdown 预设 + 颜色 ramp 自定义 + tint reverse 样式)。已装旧版的话用 `npm i -g cc-usage-bar@latest` 升级。
43
45
 
44
46
  ### 3.3 读取现有 statusLine.command
45
47
 
@@ -169,8 +171,11 @@ CC_USAGE_COLORS_BALANCE='0:cyan,60:yellow,90:red'
169
171
  # 自定义填充/空槽字符(cells)
170
172
  --bar-spec='{"mode":"cells","filled":"▰","empty":"▱","width":12}'
171
173
 
172
- # 单色渐变(tint)—— 完成部分上色,剩余部分变暗
173
- --bar-spec='{"mode":"tint","text":"████████","emptyStyle":"dim"}'
174
+ # 单色渐变(tint)—— 默认 reverse:完成部分反色底块,剩余部分变暗
175
+ --bar-spec='{"mode":"tint","text":"Ciallo~(∠・ω< )⌒★"}'
176
+
177
+ # 想要旧的"只染前景"效果,显式加 style:"fg"
178
+ --bar-spec='{"mode":"tint","text":"████████","style":"fg","emptyStyle":"dim"}'
174
179
 
175
180
  # 动画帧(frames)—— 按百分比从帧序列里挑一帧
176
181
  --bar-spec='{"mode":"frames","frames":["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"]}'
package/README.md CHANGED
@@ -20,6 +20,36 @@ Or, with `--format=bar-time`:
20
20
  [█████░░░░░] 47% until 18:00 / [██████░░░░] 59% until 5/9 09:00
21
21
  ```
22
22
 
23
+ ## Quick usage
24
+
25
+ ### Method 1: Command line
26
+
27
+ ```bash
28
+ npm install -g cc-usage-bar@latest
29
+ cc-usage-bar install --format=bar-countdown
30
+ ```
31
+
32
+ If you already have a Claude Code statusline command, the installer keeps it as the prefix and appends the usage bar. Run diagnostics any time with:
33
+
34
+ ```bash
35
+ cc-usage-bar status
36
+ ```
37
+
38
+ ### Method 2: Ask an AI assistant
39
+
40
+ In Claude Code, Cursor, Codex, or another coding assistant, say:
41
+
42
+ ```text
43
+ Install cc-usage-bar for my Claude Code statusline.
44
+ Keep my existing statusline prefix and use the bar-countdown format.
45
+ ```
46
+
47
+ If the assistant needs exact instructions, give it the AI-readable guide:
48
+
49
+ ```bash
50
+ npx cc-usage-bar@latest agents
51
+ ```
52
+
23
53
  ## Install
24
54
 
25
55
  ```bash
@@ -111,12 +141,18 @@ cc-usage-bar install --format=bar-time \
111
141
  --bar-spec='{"mode":"tint","text":"Ciallo~(∠・ω< )⌒★"}'
112
142
  ```
113
143
 
114
- `tint` keeps the whole text visible and colors the completed prefix while dimming the rest:
144
+ `tint` keeps the whole text visible. By default the completed prefix is rendered as a reversed-color block (high contrast), and the rest is dimmed:
115
145
 
116
146
  ```json
117
147
  {"mode":"tint","text":"Ciallo~(∠・ω< )⌒★"}
118
148
  ```
119
149
 
150
+ If you prefer the older "color the foreground only" look, set `style:"fg"`:
151
+
152
+ ```json
153
+ {"mode":"tint","text":"Ciallo~(∠・ω< )⌒★","style":"fg"}
154
+ ```
155
+
120
156
  `cells` replaces the default block characters:
121
157
 
122
158
  ```json
package/README.zh-CN.md CHANGED
@@ -22,6 +22,36 @@
22
22
  [█████░░░░░] 47% until 18:00 / [██████░░░░] 59% until 5/9 09:00
23
23
  ```
24
24
 
25
+ ## 快速使用
26
+
27
+ ### 方法一:正常命令行
28
+
29
+ ```bash
30
+ npm install -g cc-usage-bar@latest
31
+ cc-usage-bar install --format=bar-countdown
32
+ ```
33
+
34
+ 如果你已经有自己的 Claude Code statusline 命令,安装器会把它保留为前缀,再追加用量条。需要诊断时运行:
35
+
36
+ ```bash
37
+ cc-usage-bar status
38
+ ```
39
+
40
+ ### 方法二:直接和大模型交流
41
+
42
+ 在 Claude Code、Cursor、Codex 或其他编程助手里直接说:
43
+
44
+ ```text
45
+ 请安装 cc-usage-bar 并帮我配置 Claude Code statusline。
46
+ 保留我原来的 statusline 前缀,使用 bar-countdown 格式。
47
+ ```
48
+
49
+ 如果大模型需要更精确的操作说明,把下面命令输出的 AI 可读安装指南发给它:
50
+
51
+ ```bash
52
+ npx cc-usage-bar@latest agents
53
+ ```
54
+
25
55
  ## 安装
26
56
 
27
57
  ```bash
@@ -111,7 +141,7 @@ cc-usage-bar install --format <preset> --bar-width <n>
111
141
 
112
142
  #### tint:整段文字始终可见
113
143
 
114
- 推荐给颜文字、短句、logo 风格文本。已完成部分会染色,未完成部分会变暗,但整段文字一直可见:
144
+ 推荐给颜文字、短句、logo 风格文本。整段文字一直可见,**默认**已完成部分会用反色底块(reverse)增强对比,未完成部分变暗:
115
145
 
116
146
  ```bash
117
147
  cc-usage-bar install --format=bar-time \
@@ -122,6 +152,12 @@ cc-usage-bar install --format=bar-time \
122
152
  {"mode":"tint","text":"Ciallo~(∠・ω< )⌒★"}
123
153
  ```
124
154
 
155
+ 如果更喜欢"只给完成部分上前景色、不反色"的旧风格,显式加 `style:"fg"`:
156
+
157
+ ```json
158
+ {"mode":"tint","text":"Ciallo~(∠・ω< )⌒★","style":"fg"}
159
+ ```
160
+
125
161
  #### cells:替换默认块字符
126
162
 
127
163
  ```json
@@ -23,6 +23,7 @@ exports.FORMAT_PRESETS = [
23
23
  'bar-countdown',
24
24
  ];
25
25
  const ANSI_RESET = '\x1b[0m';
26
+ const ANSI_REVERSE = '\x1b[7m';
26
27
  exports.COLOR_MAP = {
27
28
  none: '',
28
29
  dim: '\x1b[2m',
@@ -146,6 +147,7 @@ function parseBarSpec(raw) {
146
147
  const out = { mode: 'tint', text: obj.text };
147
148
  if (obj.emptyStyle === 'plain' || obj.emptyStyle === 'dim')
148
149
  out.emptyStyle = obj.emptyStyle;
150
+ out.style = obj.style === 'fg' ? 'fg' : 'reverse';
149
151
  return out;
150
152
  }
151
153
  if (obj.mode === 'frames') {
@@ -240,7 +242,8 @@ function formatBar(pct, width = 10, spec, activeColor = null, useColor = false)
240
242
  const inactive = chars.slice(filled).join('');
241
243
  if (!useColor)
242
244
  return active + inactive;
243
- const activePart = activeColor && active ? paint(active, activeColor, true) : active;
245
+ const activeStyle = activeColor && spec.style === 'reverse' ? `${activeColor}${ANSI_REVERSE}` : activeColor;
246
+ const activePart = activeStyle && active ? paint(active, activeStyle, true) : active;
244
247
  const inactivePart = inactive && spec.emptyStyle !== 'plain' ? paint(inactive, exports.COLOR_MAP.dim, true) : inactive;
245
248
  return activePart + inactivePart;
246
249
  }
@@ -257,10 +260,22 @@ function paint(text, color, useColor) {
257
260
  return `${color}${text}${ANSI_RESET}`;
258
261
  }
259
262
  function applyTierPaint(text, color, opts, tpl) {
260
- if (opts.barSpec?.mode === 'tint' && opts.color && tpl.includes('{bar}'))
261
- return text;
262
263
  return paint(text, color, opts.color);
263
264
  }
265
+ function applyTintTemplate(tpl, vars, color, opts) {
266
+ if (!opts.color || !color)
267
+ return applyTemplate(tpl, vars);
268
+ return tpl
269
+ .split(/(\{bar\})/g)
270
+ .map((part) => (part === '{bar}' ? vars.bar ?? '{bar}' : paint(applyTemplate(part, vars), color, true)))
271
+ .join('');
272
+ }
273
+ function renderTemplate(tpl, vars, color, opts) {
274
+ if (opts.barSpec?.mode === 'tint' && tpl.includes('{bar}')) {
275
+ return applyTintTemplate(tpl, vars, color, opts);
276
+ }
277
+ return applyTierPaint(applyTemplate(tpl, vars), color, opts, tpl);
278
+ }
264
279
  function prependProvider(text, planName, opts) {
265
280
  return opts.showProviderName && planName ? `${planName} ${text}` : text;
266
281
  }
@@ -272,15 +287,15 @@ function renderTier(ctx, opts) {
272
287
  const tpl = opts.template ?? SUB_PRESET_TPL[opts.format];
273
288
  const ramp = ctx.label === '5h' ? opts.colorRamp5h ?? exports.DEFAULT_RAMP : opts.colorRampWk ?? exports.DEFAULT_RAMP;
274
289
  const color = colorFromRamp(pct, ramp);
275
- const text = applyTemplate(tpl, {
290
+ const vars = {
276
291
  label: ctx.label,
277
292
  percent: String(pct),
278
293
  bar: formatBar(pct, opts.barWidth, opts.barSpec, color, opts.color),
279
294
  expiry: formatExpiry(ctx.tier.resets_at, opts.now),
280
295
  countdown: formatCountdown(ctx.tier.resets_at, opts.now),
281
296
  provider: ctx.provider,
282
- });
283
- return applyTierPaint(text, color, opts, tpl);
297
+ };
298
+ return renderTemplate(tpl, vars, color, opts);
284
299
  }
285
300
  function currencySymbol(unit) {
286
301
  switch (unit.toUpperCase()) {
@@ -315,18 +330,18 @@ function renderBalance(d, opts) {
315
330
  }
316
331
  if (typeof d.total !== 'number') {
317
332
  const tpl = opts.template ?? BAL_PRESET_TPL.compact;
318
- const text = applyTemplate(tpl, {
333
+ const vars = {
319
334
  label: '', percent: '0', bar: '', expiry: '', countdown: '',
320
335
  provider: d.planName ?? '',
321
336
  amount: fmtMoney(d.remaining, d.unit),
322
- });
323
- return prependProvider(applyTierPaint(text, null, opts, tpl), d.planName, opts);
337
+ };
338
+ return prependProvider(renderTemplate(tpl, vars, null, opts), d.planName, opts);
324
339
  }
325
340
  const total = d.total;
326
341
  const usedPct = total > 0 ? ((total - d.remaining) / total) * 100 : 0;
327
342
  const tpl = opts.template ?? BAL_PRESET_TPL[opts.format];
328
343
  const color = colorFromRamp(usedPct, opts.colorRampBalance ?? exports.DEFAULT_RAMP);
329
- const text = applyTemplate(tpl, {
344
+ const vars = {
330
345
  label: '',
331
346
  percent: String(Math.round(usedPct)),
332
347
  bar: formatBar(usedPct, opts.barWidth, opts.barSpec, color, opts.color),
@@ -334,8 +349,8 @@ function renderBalance(d, opts) {
334
349
  countdown: '',
335
350
  provider: d.planName ?? '',
336
351
  amount: `${fmtMoney(d.remaining, d.unit)}/${fmtMoney(total, d.unit)}`,
337
- });
338
- return prependProvider(applyTierPaint(text, color, opts, tpl), d.planName, opts);
352
+ };
353
+ return prependProvider(renderTemplate(tpl, vars, color, opts), d.planName, opts);
339
354
  }
340
355
  function renderUsage(data, opts) {
341
356
  if (!data)
@@ -3,13 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.minimaxAdapter = void 0;
4
4
  exports.parseMinimax = parseMinimax;
5
5
  const http_1 = require("./http");
6
- function tier(total, used, endMs) {
7
- if (typeof total !== 'number' || typeof used !== 'number' || total <= 0)
8
- return undefined;
9
- return {
10
- utilization: ((total - (total - used)) / total) * 100,
11
- resets_at: typeof endMs === 'number' ? new Date(endMs).toISOString() : undefined,
12
- };
6
+ function isoFromMs(ms) {
7
+ return typeof ms === 'number' ? new Date(ms).toISOString() : undefined;
13
8
  }
14
9
  function parseMinimax(body) {
15
10
  if (!body || typeof body !== 'object')
@@ -19,16 +14,22 @@ function parseMinimax(body) {
19
14
  if (typeof code === 'number' && code !== 0) {
20
15
  return { error: r.base_resp?.status_msg ?? `MiniMax error ${code}` };
21
16
  }
22
- const remains = r.model_remains?.[0];
23
- if (!remains)
17
+ if (!Array.isArray(r.model_remains))
18
+ return null;
19
+ const item = r.model_remains.find((m) => m && m.model_name === 'general');
20
+ if (!item)
24
21
  return null;
25
22
  const out = { kind: 'subscription', planName: 'MiniMax' };
26
- const fh = tier(remains.current_interval_total_count, remains.current_interval_usage_count, remains.end_time);
27
- if (fh)
28
- out.five_hour = fh;
29
- const wk = tier(remains.current_weekly_total_count, remains.current_weekly_usage_count, remains.weekly_end_time);
30
- if (wk)
31
- out.seven_day = wk;
23
+ const fhRemain = item.current_interval_remaining_percent;
24
+ if (typeof fhRemain === 'number') {
25
+ out.five_hour = { utilization: 100 - fhRemain, resets_at: isoFromMs(item.end_time) };
26
+ }
27
+ if (item.current_weekly_status === 1) {
28
+ const wkRemain = item.current_weekly_remaining_percent;
29
+ if (typeof wkRemain === 'number') {
30
+ out.seven_day = { utilization: 100 - wkRemain, resets_at: isoFromMs(item.weekly_end_time) };
31
+ }
32
+ }
32
33
  if (!out.five_hour && !out.seven_day)
33
34
  return null;
34
35
  return out;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-usage-bar",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Show your Claude Code subscription usage (5h / 7d, or balance) in the statusline. Supports Anthropic, Kimi, GLM, MiniMax, DeepSeek, StepFun, SiliconFlow, OpenRouter, Novita.",
5
5
  "keywords": [
6
6
  "claude",