@mai0313/vct 2.7.1 → 2.8.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.zh-CN.md CHANGED
@@ -2,24 +2,13 @@
2
2
 
3
3
  # Vibe Coding Tracker — AI 编程助手使用量追踪器
4
4
 
5
- [![Crates.io](https://img.shields.io/crates/v/vct-cli?logo=rust&style=flat-square&color=E05D44)](https://crates.io/crates/vct-cli)
6
- [![Crates.io Downloads](https://img.shields.io/crates/d/vct-cli?logo=rust&style=flat-square)](https://crates.io/crates/vct-cli)
7
- [![npm version](https://img.shields.io/npm/v/vibe-coding-tracker?logo=npm&style=flat-square&color=CB3837)](https://www.npmjs.com/package/vibe-coding-tracker)
8
- [![npm downloads](https://img.shields.io/npm/dt/vibe-coding-tracker?logo=npm&style=flat-square)](https://www.npmjs.com/package/vibe-coding-tracker)
9
- [![PyPI version](https://img.shields.io/pypi/v/vibe_coding_tracker?logo=python&style=flat-square&color=3776AB)](https://pypi.org/project/vibe_coding_tracker/)
10
- [![PyPI downloads](https://img.shields.io/pypi/dm/vibe_coding_tracker?logo=python&style=flat-square)](https://pypi.org/project/vibe-coding-tracker)
11
- [![rust](https://img.shields.io/badge/Rust-stable-orange?logo=rust&logoColor=white&style=flat-square)](https://www.rust-lang.org/)
12
- [![tests](https://img.shields.io/github/actions/workflow/status/Mai0313/VibeCodingTracker/test.yml?label=tests&logo=github&style=flat-square)](https://github.com/Mai0313/VibeCodingTracker/actions/workflows/test.yml)
13
- [![code-quality](https://img.shields.io/github/actions/workflow/status/Mai0313/VibeCodingTracker/code-quality-check.yml?label=code-quality&logo=github&style=flat-square)](https://github.com/Mai0313/VibeCodingTracker/actions/workflows/code-quality-check.yml)
14
- [![license](https://img.shields.io/badge/License-MIT-green.svg?labelColor=gray&style=flat-square)](https://github.com/Mai0313/VibeCodingTracker/tree/main?tab=License-1-ov-file)
15
- [![Star on GitHub](https://img.shields.io/github/stars/Mai0313/VibeCodingTracker?style=social&label=Star)](https://github.com/Mai0313/VibeCodingTracker)
16
- [![PRs](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/Mai0313/VibeCodingTracker/pulls)
5
+ [![Crates.io](https://img.shields.io/crates/v/vct-cli?logo=rust&style=flat-square&color=E05D44)](https://crates.io/crates/vct-cli) [![Crates.io Downloads](https://img.shields.io/crates/d/vct-cli?logo=rust&style=flat-square)](https://crates.io/crates/vct-cli) [![npm version](https://img.shields.io/npm/v/vibe-coding-tracker?logo=npm&style=flat-square&color=CB3837)](https://www.npmjs.com/package/vibe-coding-tracker) [![npm downloads](https://img.shields.io/npm/dt/vibe-coding-tracker?logo=npm&style=flat-square)](https://www.npmjs.com/package/vibe-coding-tracker) [![PyPI version](https://img.shields.io/pypi/v/vibe_coding_tracker?logo=python&style=flat-square&color=3776AB)](https://pypi.org/project/vibe_coding_tracker/) [![PyPI downloads](https://img.shields.io/pypi/dm/vibe_coding_tracker?logo=python&style=flat-square)](https://pypi.org/project/vibe-coding-tracker) [![rust](https://img.shields.io/badge/Rust-stable-orange?logo=rust&logoColor=white&style=flat-square)](https://www.rust-lang.org/) [![tests](https://img.shields.io/github/actions/workflow/status/Mai0313/VibeCodingTracker/test.yml?label=tests&logo=github&style=flat-square)](https://github.com/Mai0313/VibeCodingTracker/actions/workflows/test.yml) [![code-quality](https://img.shields.io/github/actions/workflow/status/Mai0313/VibeCodingTracker/code-quality-check.yml?label=code-quality&logo=github&style=flat-square)](https://github.com/Mai0313/VibeCodingTracker/actions/workflows/code-quality-check.yml) [![license](https://img.shields.io/badge/License-MIT-green.svg?labelColor=gray&style=flat-square)](https://github.com/Mai0313/VibeCodingTracker/tree/main?tab=License-1-ov-file) [![Star on GitHub](https://img.shields.io/github/stars/Mai0313/VibeCodingTracker?style=social&label=Star)](https://github.com/Mai0313/VibeCodingTracker) [![PRs](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/Mai0313/VibeCodingTracker/pulls)
17
6
 
18
7
  <img src="assets/social-preview.png" alt="Vibe Coding Tracker social preview" width="640">
19
8
 
20
9
  </div>
21
10
 
22
- **实时追踪你的 AI 编程开销。** Vibe Coding Tracker 是一款基于 Rust 构建的轻量级高性能 CLI 工具,用于监控和分析你在 Claude Code、Codex、Copilot、Gemini、OpenCode、Cursor、Hermes、Grok 和 DeepSeek Harness 上的使用情况——提供详细的费用明细、token 统计和代码操作洞察,同时保持极低的内存占用。
11
+ **实时追踪你的 AI 编程开销。** Vibe Coding Tracker 是一款基于 Rust 构建的轻量级高性能 CLI 工具,用于监控和分析你在 Claude Code、Codex、Copilot、Gemini、OpenCode、Cursor、Hermes、Grok、DeepSeek Harness 和 Antigravity 上的使用情况——提供详细的费用明细、token 统计和代码操作洞察,同时保持极低的内存占用。
23
12
 
24
13
  [English](README.md) | [繁體中文](README.zh-TW.md) | [简体中文](README.zh-CN.md)
25
14
 
@@ -35,7 +24,7 @@
35
24
 
36
25
  ### 超轻量级
37
26
 
38
- 使用 Rust 构建, 资源占用极低. 交互式 TUI 面板完成首次刷新后, 常驻内存通常在 **60 MB 左右**, 即使磁盘上有数千个 session 文件也不例外. `~/.vct/sessions/` 下的 session 账本让每次运行都只需重新解析新增或变更的 source, dedicated scan worker 与 glibc allocator 调整也能让长时间运行的 CPU 和 RSS 保持稳定.
27
+ 使用 Rust 构建, 资源占用极低. 交互式 TUI 面板完成首次刷新后, 常驻内存通常在 **60 MB 左右**, 即使磁盘上有数千个 session 文件也不例外. `~/.vct/sessions/` 下的 session 账本让每次运行都只需重新解析新增或变更的 source.
39
28
 
40
29
  ### 精美的可视化
41
30
 
@@ -48,7 +37,7 @@
48
37
 
49
38
  ### 零配置
50
39
 
51
- 自动检测并处理来自 Claude Code、Codex、Copilot、Gemini、OpenCode、Cursor、Hermes、Grok 和 DeepSeek Harness 的日志。无需任何设置——直接运行即可分析。首次运行时会自动生成一个带有合理默认值的 `~/.vct/config.toml`,方便你日后想调整行为时使用(参见 [配置](#%E9%85%8D%E7%BD%AE))。
40
+ 自动检测并处理来自 Claude Code、Codex、Copilot、Gemini、OpenCode、Cursor、Hermes、Grok、DeepSeek Harness 和 Antigravity 的日志。无需任何设置——直接运行即可分析。首次运行时会自动生成一个带有合理默认值的 `~/.vct/config.toml`,方便你日后想调整行为时使用(参见 [配置](#%E9%85%8D%E7%BD%AE))。
52
41
 
53
42
  ### 丰富的洞察
54
43
 
@@ -62,15 +51,15 @@
62
51
 
63
52
  ## 核心特性
64
53
 
65
- | 特性 | 说明 |
66
- | ---------------- | --------------------------------------------------------------------------------------- |
67
- | **多供应商支持** | Claude Code、Codex、Copilot、Gemini、OpenCode、Cursor、Hermes、Grok 和 DeepSeek Harness |
68
- | **智能定价** | 模糊模型匹配 + 从 LiteLLM 每日缓存更新 |
69
- | **4 种显示模式** | 交互式 TUI、静态表格、纯文本和 JSON |
70
- | **双维度分析** | token/费用统计(`usage`)+ 代码操作统计(`analysis`) |
71
- | **实时额度面板** | Claude、Codex、Copilot、Cursor 和 Grok 的实时额度用量 |
72
- | **超轻量级** | TUI 常驻内存 50 MB 以内、精简的 incremental scan, 基于 Rust 构建 |
73
- | **实时更新** | 响应式 loading 与后台 refresh, 并高亮变化 |
54
+ | 特性 | 说明 |
55
+ | ---------------- | ---------------------------------------------------------------------------------------------------- |
56
+ | **多供应商支持** | Claude Code、Codex、Copilot、Gemini、OpenCode、Cursor、Hermes、Grok、DeepSeek Harness 和 Antigravity |
57
+ | **智能定价** | 模糊模型匹配 + 从 LiteLLM 每日缓存更新 |
58
+ | **4 种显示模式** | 交互式 TUI、静态表格、纯文本和 JSON |
59
+ | **双维度分析** | token/费用统计(`usage`)+ 代码操作统计(`analysis`) |
60
+ | **实时额度面板** | Claude、Codex、Copilot、Cursor、Grok 和 Antigravity 的实时额度用量 |
61
+ | **超轻量级** | TUI 常驻内存约 60 MB、精简的 incremental scan, 基于 Rust 构建 |
62
+ | **实时更新** | 响应式 loading 与后台 refresh, 并高亮变化 |
74
63
 
75
64
  ---
76
65
 
@@ -80,8 +69,6 @@
80
69
 
81
70
  选择最适合你的安装方式:
82
71
 
83
- > **开发者**: 如果你想从源码构建或参与项目开发, 请参阅 [CONTRIBUTING.md](.github/CONTRIBUTING.md).
84
-
85
72
  #### 方式一:通过 npm 安装
86
73
 
87
74
  **前置条件**:[Node.js](https://nodejs.org/) v22 或更高版本
@@ -137,21 +124,7 @@ vct analysis
137
124
 
138
125
  ## 命令指南
139
126
 
140
- ### 快速参考
141
-
142
- ```
143
- vct <COMMAND> [OPTIONS]
144
- # Replace with `vibe_coding_tracker` if you are using the full binary name
145
-
146
- Commands:
147
- analysis Analyze local session data (single file or all sessions)
148
- usage Display token usage statistics
149
- version Display version information
150
- update Update to the latest version from GitHub releases
151
- quota Fetch a provider's raw quota/usage API response
152
- config Show or edit the persistent settings file (~/.vct/config.toml)
153
- help Print this message or the help of the given subcommand(s)
154
- ```
127
+ 运行 `vct --help` 可列出所有命令,`vct <command> --help` 则会列出该命令的 flag。
155
128
 
156
129
  时间范围 flag(`usage` 与 `analysis` 共用,互斥,默认 `--all`):
157
130
 
@@ -168,17 +141,6 @@ Commands:
168
141
 
169
142
  **追踪你在所有 AI 编程会话中的开销。**
170
143
 
171
- ### Flag 一览
172
-
173
- | Flag | 用途 |
174
- | ---------------------------------------------- | ----------------------------------------------------------------------------- |
175
- | *(不带参数)* | 互动式 TUI 面板(默认) |
176
- | `--table` | 静态表格,不启动 TUI |
177
- | `--text` | 纯文本,适合脚本处理 |
178
- | `--json` | JSON 输出,附带定价信息 |
179
- | `--merge-providers` | 合并共享同一 base 名称、仅 provider 前缀不同的 model(`--json` 会忽略此选项) |
180
- | `--daily` / `--weekly` / `--monthly` / `--all` | 时间范围筛选(见上方表格) |
181
-
182
144
  ### 基本用法
183
145
 
184
146
  ```bash
@@ -191,7 +153,7 @@ vct usage --table
191
153
  # Plain text for scripts
192
154
  vct usage --text
193
155
 
194
- # JSON 输出,包含 cost_usd 与 matched_model 字段
156
+ # JSON 输出,每行都有 cost_usd;以其他模型名称计价时才会多出 matched_model 字段
195
157
  vct usage --json
196
158
 
197
159
  # 通过 shell redirection 保存富化 JSON
@@ -208,7 +170,7 @@ vct usage --table --merge-providers
208
170
  ```
209
171
 
210
172
  > [!NOTE]
211
- > Model 行会按 cost 升序排序,因此花费最高的 model 会排在最后(在 `--table` 中紧邻 `TOTAL` 行上方)。该排序适用于交互式面板、`--table` 与 `--text` 三种输出;`--json` 也会保持相同顺序。交互式面板还会隐藏在所选范围内用量为 0 的模型。
173
+ > Model 行会按 cost 升序排序,因此花费最高的 model 会排在最后(在 `--table` 中紧邻 `TOTAL` 行上方)。该排序适用于交互式面板、`--table` 与 `--text` 三种输出;`--json` 的行则没有固定顺序。交互式面板还会隐藏在所选范围内用量为 0 的模型。
212
174
 
213
175
  > [!TIP]
214
176
  > 同一个 model 在不同 provider 前缀下路由时会显示成多行(`openai/gpt-5.5`、`azure/gpt-5.5`、纯 `gpt-5.5`)。`--merge-providers` 会把第一个 `/` 之后 base 名称相同的行合并(`gpt-5.5` 与 `gpt-5.4` 这类版本不同的仍分开),并把它们已定价的 cost 相加。在交互式面板中按 `m` 可实时切换(该选择会保存到 `~/.vct/config.toml`,因此下次启动会记住它);`--merge-providers` 则让面板一打开就是合并状态。`--json` 保持为逐一 model 的原始导出。
@@ -237,7 +199,7 @@ vct usage --table --merge-providers
237
199
  ↑/↓ scroll m merge p providers Q quota r refresh q quit | Star on GitHub
238
200
  ```
239
201
 
240
- 两个交互式面板都会在 terminal setup 完成后立即绘制居中的 `Loading sessions...` spinner. Loading 期间仍可响应 `q`, Ctrl+C 与 resize event. 后续扫描由单一 background worker 执行, 并在 `Refreshing...` footer 下保留上一次成功的数据. 重复的 refresh 请求最多只会合并为一个 pending scan. 如果 refresh 失败, 面板会保留 last-known-good view, 并在下次排程或手动刷新时重试.
202
+ 两个交互式面板都会在 terminal setup 完成后立即绘制居中的 `Loading sessions...` spinner. Loading 期间仍可响应 `q`, Ctrl+C 与 resize event. 后续扫描会在 `Refreshing...` footer 下保留上一次成功的数据. 如果 refresh 失败, 面板会保留 last-known-good view, 并在下次排程或手动刷新时重试.
241
203
 
242
204
  ### 预览:表格与 JSON(`vct usage`)
243
205
 
@@ -268,16 +230,20 @@ Totals (by Provider)
268
230
  ```
269
231
 
270
232
  ```json
271
- // vct usage --json (one model shown; rows are sorted by cost)
233
+ // vct usage --json (one model shown; rows come in no fixed order)
272
234
  [
273
235
  {
274
- "model": "claude-opus-4-8",
275
236
  "cost_usd": 151.29,
237
+ "model": "claude-opus-4-8",
276
238
  "usage": {
239
+ "cache_creation": {
240
+ "ephemeral_1h_input_tokens": 0,
241
+ "ephemeral_5m_input_tokens": 6057836
242
+ },
243
+ "cache_creation_input_tokens": 6057836,
244
+ "cache_read_input_tokens": 138099926,
277
245
  "input_tokens": 401937,
278
246
  "output_tokens": 936186,
279
- "cache_read_input_tokens": 138099926,
280
- "cache_creation_input_tokens": 6057836,
281
247
  "reasoning_output_tokens": 0,
282
248
  "total_tokens": 145495885
283
249
  }
@@ -285,7 +251,7 @@ Totals (by Provider)
285
251
  ]
286
252
  ```
287
253
 
288
- 无论来源 provider 是什么,每一行都会输出相同的扁平 token 字段(Codex 内部的嵌套结构会在输出前规范化)。若某个 provider 计费的 bucket 是其他 provider 没有的,该行会额外带上自己的 key:实际用掉 tool token 的 Gemini 行会带 `tool_tokens`,LiteLLM 没有对应费率,只计入 `total_tokens`。
254
+ 无论来源 provider 是什么,每一行都会输出相同的扁平 token 字段。有几个 key 只在该行有对应数值时才会出现:`cache_creation` 把 cache 写入拆成 5 分钟与 1 小时 TTL 两部分,`server_tool_use` 记录 Claude 的 web search 次数,`above_tier` 记录 prompt 超过长 context 计价档位的请求所用的 token,实际用掉 tool token 的 Gemini 行则会带 `tool_tokens`,LiteLLM 没有对应费率,只计入 `total_tokens`。
289
255
 
290
256
  ### 扫描范围
291
257
 
@@ -300,6 +266,7 @@ Totals (by Provider)
300
266
  - `~/.hermes/state.db`(Hermes,SQLite 数据库,遵循 `$HERMES_HOME`;仅 `usage`)
301
267
  - `$GROK_HOME/sessions/*/*/signals.json`(Grok CLI,默认使用 `~/.grok`;同层的 `updates.jsonl` 提供 `analysis` 数据)
302
268
  - `$DSH_HOME/sessions/*/*/session.jsonl.zstd`(DeepSeek Harness,默认使用 `~/.dsh`;若该 root 配置为 `compression = "none"` 则写成 `session.jsonl`,两种都会读取)
269
+ - `~/.gemini/{antigravity-cli,antigravity,jetski}/brain/*/.system_generated/logs/transcript_full.jsonl`(Antigravity:`agy` CLI、Desktop app 与 Jetski 合并算作同一个 provider;每段对话的 model 取自同层的 `conversations/<id>.db`)
303
270
 
304
271
  Grok 的 `usage` 是单一时点的本地 context 估算:vct 会把 `signals.json` 的 `contextTokensUsed` 记为 cache-read token,并按该 model 的 cache-read 费率估算费用。这不是累计的 billed usage。`analysis` 会从同层的 `updates.jsonl` 还原已完成的 Read / Write / Edit / Bash / TodoWrite 操作。至于你实际计费的额度,请参见下方的 Grok 额度面板。
305
272
 
@@ -311,7 +278,7 @@ Grok 的 `usage` 是单一时点的本地 context 估算:vct 会把 `signals.j
311
278
 
312
279
  ### 实时额度面板
313
280
 
314
- `vct usage` 会**在仪表盘中直接显示 Claude Code、Codex、GitHub Copilot、Cursor 与 Grok 的实时额度用量——完全零配置。** 不需要 status-line hook,也无需手动输入任何凭证:vct 会读取各 provider 自己的 OAuth 凭证,在后台线程调用其用量 API,并在你工作时保持面板持续更新。每个进度条都是**已用**百分比,所以进度条满格代表该额度周期已耗尽,而不是还没开始用。(想要更清爽的面板?在 [`config.toml`](#%E9%85%8D%E7%BD%AE) 中精简 `[usage.quota]` 下的 `panels`,或设为 `[]` 隐藏所有额度卡片。表格下方那行各 provider 成本是本机扫描数据而不是额度面板,所以不受这里的设置影响。)
281
+ `vct usage` 会**在仪表盘中直接显示 Claude Code、Codex、GitHub Copilot、Cursor、Grok 与 Antigravity 的实时额度用量——完全零配置。** 不需要 status-line hook,也无需手动输入任何凭证:vct 会读取各 provider 自己的 OAuth 凭证,在后台线程调用其用量 API(Antigravity 则是询问 `agy` CLI),并在你工作时保持面板持续更新。每个进度条都是**已用**百分比,所以进度条满格代表该额度周期已耗尽,而不是还没开始用。(想要更清爽的面板?在 [`config.toml`](#%E9%85%8D%E7%BD%AE) 中精简 `[usage.quota]` 下的 `panels`,或设为 `[]` 隐藏所有额度卡片。表格下方那行各 provider 成本是本机扫描数据而不是额度面板,所以不受这里的设置影响。)
315
282
 
316
283
  ```
317
284
  ┌ Claude ──────────────┐┌ Codex ───────────────┐┌ Copilot ─────────────┐┌ Cursor ────────LIMIT ┐┌ Grok ────────────────┐
@@ -321,19 +288,27 @@ Grok 的 `usage` 是单一时点的本地 context 估算:vct 会把 `signals.j
321
288
  │Fable ▰▰▰▰▱ 79% 1d23h││credits 0 · +3 reset ││ ││api ▰▰▰▱▱ 44% 16d0h││balance $12.00 │
322
289
  │bal - · $0.00 used ││reset expires 17d0h ││ ││ ││ │
323
290
  └──────────────────────┘└──────────────────────┘└──────────────────────┘└──────────────────────┘└──────────────────────┘
291
+ ┌ Antigravity ─────────┐
292
+ │- just now│
293
+ │G 7d ▰▱▱▱▱ 8% 2d18h│
294
+ │G 5h ▰▰▱▱▱ 23% 2h50m│
295
+ │C 7d ▰▰▰▱▱ 57% 20h5m│
296
+ │C 5h ▱▱▱▱▱ 0% 4h59m│
297
+ └──────────────────────┘
324
298
  ```
325
299
 
326
300
  - **Claude** — 方案类型、5 小时、每周以及单模型每周用量,来自官方 OAuth 用量 API(`GET /api/oauth/usage`),从 `~/.claude/.credentials.json` 读取,并显示额度余额。约每分钟轮询一次以避开该端点的速率限制;触及上限时标题会出现红色 `LIMIT` 标记。单模型每周那一行属于尽力而为,未返回该范围时就自动隐藏。
327
301
  - **Codex** — 套餐类型、可用的 5 小时和每周用量周期、额度余额以及已获取的可用 reset credit 中最早的到期时间,使用 `~/.codex/auth.json` 从 ChatGPT 后端(`wham/usage` + `wham/rate-limit-reset-credits`)获取(在适用时显示大致剩余讯息数 / 消费上限);API 不可用时回退到 Codex 会话日志中最新的 `rate_limits`(标题显示 `Codex` 或 `Codex (session)`)。
328
302
  - **Copilot** — 方案类型,以及你的 premium 请求额度,以两个进度条呈现:已用百分比,以及已用 / 总量的请求数(例如 `45/1500`),来自 GitHub 的 Copilot API(`GET /copilot_internal/user`),从 `~/.copilot/config.json` 读取。该请求会模拟 Copilot CLI。token 为长期有效,因此不需要刷新;遇到 `401` / `403` 时会显示 `run: copilot login` 提示。
329
- - **Cursor** — 方案类型、total / auto / API **已用**百分比,以及按需消费,来自 cursor.com(`GET /api/usage-summary`),使用 `~/.config/cursor/auth.json` 中的 session token。刷新是被动式的:vct 每次轮询都会重新读取该文件,并在 token 有效期内使用它,因为官方 Cursor 客户端会让它保持最新。
303
+ - **Cursor** — 方案类型、total / auto / API **已用**百分比,以及按需消费,来自 cursor.com(`GET /api/usage-summary`),使用 `~/.config/cursor/auth.json` 中的 session token。
330
304
  - **Grok** — 方案类型,以及当前每周或每月周期内的方案内含额度用量,来自 Grok CLI 自己的计费端点(`GET /v1/billing?format=credits`),从 `~/.grok/auth.json` 读取。预付余额只有在非零时才会显示;按量付费的消费则在你有过消费、或设置了上限之后才会显示。该请求会模拟 Grok CLI;遇到 `401` / `403` 时会显示 `run: grok login` 提示。
305
+ - **Antigravity** — 每个共享模型池(Gemini,以及 Claude / GPT)的每周与 5 小时额度,来自 `agy` CLI 自己的 `/usage` 命令(`agy -p /usage --output-format json`)。卡片以模型池名称的第一个词标示每个额度,卡片较窄时只用首字母(`G 7d` 是 Gemini 的每周额度)。`/usage` 不提供方案名称,所以第一行只显示数据的新旧。agy 会自行维持登录状态,因此 vct 只检查 `~/.gemini/antigravity-cli/antigravity-oauth-token` 是否存在,从不读取或写入它。每次轮询都会启动一次 agy(需要几秒、约 260 MB),所以这张卡片最多每 5 分钟更新一次。agy 无法登录时,卡片会显示 `run: agy acp --login` 提示,而且在该文件变动之前,仪表盘不会再运行 agy。
331
306
 
332
- **自动刷新 token。** 对 Claude、Codex 和 Grok,当 token 接近过期或被拒绝时,vct 会刷新它并把新 token 写回该 provider 自己的凭证文件(采用该 CLI 的原始格式),因此 token 会在多次检查之间复用,而不是每次都重新刷新。Grok 的 token 端点会像它自己的 CLI 那样,从登录时的 issuer 解析得出,而不是写死在代码里;写入时也会保留文件中其他所有的登录信息。如果刷新失败,面板会显示 `run: <provider> auth login` 提示,而不会直接中断。Copilot(长期有效的 token)和 Cursor(由其自身客户端保持最新)为只读——vct 从不写入它们的凭证文件。
307
+ **自动刷新 token。** 对 Claude、Codex 和 Grok,当 token 接近过期或被拒绝时,vct 会刷新它并把新 token 写回该 provider 自己的凭证文件(采用该 CLI 的原始格式)。写入 Grok 的凭证文件时,会保留文件中其他所有的登录信息。如果刷新失败,面板会显示 `run: <provider> auth login` 提示,而不会直接中断。Copilot(长期有效的 token)和 Cursor(由其自身客户端保持最新)为只读——vct 从不写入它们的凭证文件。Antigravity 的 token 属于 agy,每当 vct 向它询问 `/usage` 时由 agy 自行刷新。
333
308
 
334
- 只有在某个 provider 的凭证存在时,才会显示对应的面板。面板排在一个统一网格上:一行放得下几张就放几张,放不下的自动折到下一行,因此新增一个 provider 只是多一张卡片,不会多一条排版规则。当终端高度不足以留给网格时,它会收成一行摘要,显示放得下的 gauge,并把其余的记成数量;按 `Q` 打开完整的额度浮层,无论终端多大,每张卡片都放得下全部内容,按 `p` 打开 Provider Usage 面板,里面有各 provider 的 token 数与占比。额度面板仅在交互式 TUI 中显示;`--table`、`--text`、`--json` 不受影响。
309
+ 只有在某个 provider 的凭证存在时,才会显示对应的面板。面板排在一个统一网格上:一行放得下几张就放几张,放不下的自动折到下一行。当终端高度不足以留给网格时,它会收成一行摘要,显示放得下的 gauge,并把其余的记成数量;按 `Q` 打开完整的额度浮层,无论终端多大,每张卡片都放得下全部内容,按 `p` 打开 Provider Usage 面板,里面有各 provider 的 token 数与占比。额度面板仅在交互式 TUI 中显示;`--table`、`--text`、`--json` 不受影响。
335
310
 
336
- > **平台说明:** 在 macOS 上,Claude Code 会把 OAuth 凭证保存在系统 Keychain 中,而不是 `~/.claude/.credentials.json`,因此在 macOS 上不会显示 Claude 面板。Cursor 的 `~/.config/cursor` 凭证路径偏向 Linux。
311
+ > **平台说明:** 在 macOS 上,Claude Code 会把 OAuth 凭证保存在系统 Keychain 中,而不是 `~/.claude/.credentials.json`,因此在 macOS 上不会显示 Claude 面板。agy 在 macOS 上同样把登录信息保存在 Keychain,所以也不会显示 Antigravity 面板。Cursor 的 `~/.config/cursor` 凭证路径偏向 Linux。
337
312
 
338
313
  ---
339
314
 
@@ -341,18 +316,7 @@ Grok 的 `usage` 是单一时点的本地 context 估算:vct 会把 `signals.j
341
316
 
342
317
  **深入了解代码操作——查看你的 AI 助手到底做了什么。**
343
318
 
344
- ### 参数与 Flag
345
-
346
- | 参数 / Flag | 用途 |
347
- | ---------------------------------------------- | ---------------------------------------------------------------------------- |
348
- | *(不带参数)* | 互动式 TUI 面板, 覆盖所有 session |
349
- | `<FILE>` | 分析单一 JSONL/JSON session 文件, 并将完整 `CodeAnalysis` JSON 输出到 stdout |
350
- | `--table` | 静态摘要表格, 附带 provider 汇总 |
351
- | `--text` | 纯文本摘要, 方便脚本处理 |
352
- | `--json` | 完整 parser 结果. 搭配 `<FILE>` 时为单一 object, 否则为 object 数组 |
353
- | `--daily` / `--weekly` / `--monthly` / `--all` | 所有 session 的时间范围筛选. 不可与 `<FILE>` 同时使用, 其他说明见上方表格 |
354
-
355
- 参见 [`tests/fixtures/sessions/`](tests/fixtures/sessions/) 目录,其中包含四种 JSONL provider 的示例输入与对应 JSON 输出,以及 [`tests/fixtures/sessions/grok/`](tests/fixtures/sessions/grok/) 下的 Grok session fixture 和 [`tests/fixtures/sessions/dsh/`](tests/fixtures/sessions/dsh/) 下的 DeepSeek Harness session fixture。
319
+ 参见 [`tests/fixtures/sessions/`](tests/fixtures/sessions/) 目录,其中包含四种 JSONL provider 的示例输入与对应 JSON 输出,以及 [`tests/fixtures/sessions/grok/`](tests/fixtures/sessions/grok/) 下的 Grok session fixture 、[`tests/fixtures/sessions/dsh/`](tests/fixtures/sessions/dsh/) 下的 DeepSeek Harness session fixture,以及 [`tests/fixtures/sessions/antigravity/`](tests/fixtures/sessions/antigravity/) 下的 Antigravity fixture。
356
320
 
357
321
  ### 基本用法
358
322
 
@@ -515,27 +479,16 @@ vct version --json # 机读 JSON
515
479
  └───────────────┴──────────┘
516
480
  ```
517
481
 
518
- Binary version 由 `build.rs` 在编译期通过 `git describe` 写入,开发版本会附带 commit 计数、short SHA 与 `dirty` 后缀。
519
-
520
482
  ---
521
483
 
522
484
  ## Quota 命令
523
485
 
524
486
  **打印某个供应商的原始 quota/usage API 响应 — 不解析、不聚合。**
525
487
 
526
- 对 `usage` 面板使用的同一个 quota 端点(Claude / Codex / Copilot / Cursor / Grok)发一次请求,直接打印原始 body,方便你查看 API 的实际结构或检查凭证是否正常。它读取各供应商已保存的凭证,并且**不会**刷新 token:token 过期时,请用对应供应商自己的 CLI 重新登录(`claude` / `codex` / `copilot` / `cursor-agent` / `grok`)。
488
+ 对 `usage` 面板使用的同一个 quota 端点(Claude / Codex / Copilot / Cursor / Grok)发一次请求,直接打印原始 body,方便你查看 API 的实际结构或检查凭证是否正常。它读取各供应商已保存的凭证,并且**不会**刷新 token:token 过期时,请用对应供应商自己的 CLI 重新登录(`claude` / `codex` / `copilot` / `cursor-agent` / `grok`)。`vct quota antigravity` 则是运行一次 `agy -p /usage --output-format json` 并打印 agy 的输出;agy 会在运行时自行刷新 token。
527
489
 
528
490
  > 旧名称 `vct fetch` 保留为隐藏别名,现有脚本仍可继续使用。
529
491
 
530
- ### 参数
531
-
532
- | 参数 | 用途 |
533
- | --------- | ----------------------------- |
534
- | *(无)* | 彩色 JSON(默认) |
535
- | `--json` | 彩色 JSON |
536
- | `--text` | 摊平成 `key: value`,适合脚本 |
537
- | `--table` | 摊平成 Field / Value 表格 |
538
-
539
492
  ### 基本用法
540
493
 
541
494
  ```bash
@@ -545,6 +498,7 @@ vct quota codex
545
498
  vct quota copilot
546
499
  vct quota cursor
547
500
  vct quota grok
501
+ vct quota antigravity
548
502
 
549
503
  # 摊平成纯文本
550
504
  vct quota codex --text
@@ -554,7 +508,7 @@ vct quota copilot --table
554
508
  ```
555
509
 
556
510
  > [!NOTE]
557
- > 响应 body 会原样打印到 stdout。遇到 HTTP 错误时仍会打印 body 并以非零状态退出;401/403 还会在 stderr 额外打印 `run: <cli> login` 提示。
511
+ > 响应 body 会原样打印到 stdout。遇到 HTTP 错误时仍会打印 body 并以非零状态退出;401/403 还会在 stderr 额外打印 `run: <cli> login` 提示。agy 运行失败时也一样,若是 agy 无法登录,还会附上 `run: agy acp --login` 提示。
558
512
 
559
513
  ---
560
514
 
@@ -562,83 +516,13 @@ vct quota copilot --table
562
516
 
563
517
  vct 会把用户设置保存在 `~/.vct/config.toml` 中。该文件会在**首次运行时以默认值自动生成**,因此你完全不必手动编写——只有想修改某个默认值时才编辑它。它由 vct 的类型化设置生成,并在第一行带有 `#:schema` 指令,因此支持 schema 的 TOML 编辑器(taplo / VS Code 的 "Even Better TOML")会提供自动补全与校验。你也可以用 `vct config schema` 自行打印该 schema。由旧版 vct 生成的文件会在下次被 vct 读取时就地升级到当前布局(也可用 `vct config migrate` 手动触发),因此升级后绝不会停留在过时的格式上。该升级也会把你的文件写入之后才发布的额度面板补进来——但只补一次。你再次删除该名称后它就不会回来,而你先前已经移除的面板也绝不会被重新加回。
564
518
 
565
- ```toml
566
- #:schema https://raw.githubusercontent.com/Mai0313/VibeCodingTracker/main/vct.schema.json
567
-
568
- [general]
569
- # 未指定 --daily/--weekly/--monthly/--all flag 时使用的默认时间范围
570
- # 取值之一: "daily" | "weekly" | "monthly" | "all"
571
- default_time_range = "all"
572
- # 启动时检查新版, 并自动更新由官方 installer 创建的受支持直接安装.
573
- # 设为 false 可关闭此行为.
574
- auto_update = true
575
- # 该文件的布局版本, 由 vct 标记. 只有升级流程会读取它;
576
- # 除非你想让某次过去的升级再跑一遍, 否则不要动它.
577
- version = 3
578
-
579
- [usage]
580
- # 启动 usage 面板时就把跨 provider 前缀的 model 合并显示
581
- # 可用 `m` 实时切换, 最后一次的状态会保存回这里
582
- merge_models = false
583
- # usage TUI 自动刷新的间隔秒数 (最小为 1)
584
- refresh_interval = 10
585
-
586
- [usage.quota]
587
- # 显示哪些实时额度面板; 删除某个名称即可隐藏该面板, 用空列表 ([]) 全部隐藏
588
- panels = ["claude", "codex", "copilot", "cursor", "grok"]
589
- # 每个 provider 共用的实时额度面板轮询间隔秒数 (最小为 1)
590
- refresh_interval = 60
591
-
592
- [analysis]
593
- # analysis TUI 自动刷新的间隔秒数 (最小为 1)
594
- refresh_interval = 10
595
-
596
- [performance]
597
- # CLI session scan 使用的 Rayon worker 数. 0 代表实测最佳的 auto 默认值;
598
- # 正整数会限制在机器的 available parallelism 以内.
599
- scan_threads = 0
600
-
601
- [providers]
602
- # 是否把各 provider 的 session 纳入 usage / analysis, 设为 false
603
- # 就会完全跳过它 (不扫描目录, 也不调用 API)
604
- claude = true
605
- codex = true
606
- copilot = true
607
- gemini = true
608
- opencode = true
609
- cursor = true
610
- hermes = true
611
- grok = true
612
- dsh = true
613
-
614
- [logging]
615
- # 写入 ~/.vct/logs/vct-YYYY-MM-DD.log 的最低日志级别。
616
- # 取值: "off" | "error" | "warn" | "info" | "debug" | "trace"。
617
- level = "warn"
618
- # 保留多少天的每日日志文件; 更旧的文件会在启动时清除。0 表示全部保留。
619
- retention_days = 7
620
- ```
621
-
622
- | 设置项 | 作用 |
623
- | ------------------------------ | --------------------------------------------------------------------------------------------------------------- |
624
- | `general.default_time_range` | 当你没有传入 `--daily/--weekly/--monthly/--all` 时使用的时间范围。显式传入的 flag 始终优先。 |
625
- | `general.auto_update` | 启动时每天 UTC 日期最多检查一次, 并且只更新官方 installer 的直接安装. 设为 `false` 可关闭. |
626
- | `general.version` | vct 标记在文件上的布局版本,让后续版本新增的面板只会向你提供一次。 |
627
- | `usage.merge_models` | 让面板启动时就处于合并状态;`m` 切换会把你上次的选择保存回这里。`--merge-providers` 会强制开启。 |
628
- | `usage.refresh_interval` | `usage` 面板的自动刷新间隔(秒)。 |
629
- | `usage.quota.panels` | 显示哪些额度面板(`claude` / `codex` / `copilot` / `cursor` / `grok`);删除名称即可隐藏,`[]` 全部隐藏。 |
630
- | `usage.quota.refresh_interval` | 每个实时额度面板的轮询间隔(秒);数值越大越不容易触发 provider 的速率限制。 |
631
- | `analysis.refresh_interval` | `analysis` 面板的自动刷新间隔(秒)。 |
632
- | `performance.scan_threads` | CLI scan worker 数. `0` 优先采用正数的 `RAYON_NUM_THREADS`, 否则最多使用两个 worker; 所有值都会受 CPU 数量限制. |
633
- | `providers.*` | 设为 `false` 时完全跳过某个 provider(不扫描、不调用 API)——如果你不用某个 provider 会很方便。 |
634
- | `logging.level` | 写入日志文件的最低级别(`off`..`trace`);从不打印到终端。 |
635
- | `logging.retention_days` | 保留多少天的每日日志文件;更旧的 `vct-*.log` 会在启动时清除(`0` 表示全部保留)。 |
519
+ 运行 `vct config show` 即可打印该文件,文件中的注释说明了每一项设置。
636
520
 
637
521
  > [!NOTE]
638
- > vct 会把诊断信息写入 `~/.vct/logs/vct-YYYY-MM-DD.log`(纯文本,仅写文件,绝不显示在面板上)。健康运行时保持安静(默认级别 `warn`),且文件是惰性创建的,所以一次正常运行不会留下任何文件。当额度获取失败或某个 session 被跳过时,原因就记录在这里——需要完整细节时把 `logging.level` 调到 `debug`。
522
+ > Cursor 的 `usage` 是从聊天库得出的**本地估算**,因此它会像 Claude Code / Codex / Copilot / Gemini 一样(都是从本地 session 文件计算得出)无需联网。该估算会低估 Cursor 的真实花费,因为其中很大一部分是以 Cursor 内部的 model 名称计费,本地数据无法为这些名称定价,所以请把 Cursor 费用视为近似值。
639
523
 
640
524
  > [!NOTE]
641
- > Cursor 的 `usage` 是从聊天库得出的**本地估算**,因此它会像 Claude Code / Codex / Copilot / Gemini 一样(都是从本地 session 文件计算得出)无需联网。该估算会低估 Cursor 的真实花费,因为其中很大一部分是以 Cursor 内部的 model 名称计费,本地数据无法为这些名称定价,所以请把 Cursor 费用视为近似值。
525
+ > vct 会把诊断信息写入 `~/.vct/logs/vct-YYYY-MM-DD.log`(纯文本,仅写文件,绝不显示在面板上)。健康运行时保持安静(默认级别 `warn`),且文件是惰性创建的,所以一次正常运行不会留下任何文件。当额度获取失败或某个 session 被跳过时,原因就记录在这里——需要完整细节时把 `logging.level` 调到 `debug`。
642
526
 
643
527
  ### 管理配置文件
644
528
 
@@ -666,9 +550,8 @@ vct config migrate
666
550
  ### 工作原理
667
551
 
668
552
  1. **自动更新**: 每个 UTC 日期从 [LiteLLM](https://github.com/BerriAI/litellm) 获取一次最新定价
669
- 2. **校验后缓存**: 只接受成功且包含实际价格的 JSON model map, 再 atomic 写入 `~/.vct/`
670
- 3. **确定性匹配**: 即使 model 名称含有版本或 provider 前缀, 也会选择最具体的匹配
671
- 4. **失败保护**: 获取失败不会覆盖有效 cache, vct 会保留旧 map, 并在五分钟 backoff 后才再次尝试
553
+ 2. **确定性匹配**: 即使 model 名称含有版本或 provider 前缀, 也会选择最具体的匹配
554
+ 3. **失败保护**: 获取失败不会覆盖有效 cache, vct 会保留旧 map, 并在五分钟 backoff 后才再次尝试
672
555
 
673
556
  ### 模型匹配
674
557
 
@@ -677,7 +560,7 @@ vct config migrate
677
560
  1. **精确匹配**:`claude-sonnet-4` → `claude-sonnet-4`
678
561
  2. **标准化匹配**:`claude-sonnet-4-20250514` → `claude-sonnet-4`
679
562
  3. **子串匹配**:`custom-gpt-4` → `gpt-4`
680
- 4. **模糊匹配(AI 驱动)**:使用 Jaro-Winkler 相似度算法(70% 阈值)
563
+ 4. **模糊匹配**:使用 Jaro-Winkler 相似度算法(70% 阈值)
681
564
  5. **兜底方案**:如果未找到匹配,显示 $0.00
682
565
 
683
566
  通用的占位名称(例如 cursor-agent 在 auto 模式写入的 `default`)与过短的名称不会进行子串或模糊匹配——宁可不计价,也不捡相似名称的价格。
@@ -689,14 +572,11 @@ vct config migrate
689
572
  - **OpenCode**:只有在 LiteLLM 上**精确**匹配时,才会根据 token 为一个全新的 model 名称定价;若没有精确匹配,vct 会信任该 assistant message 自身存储的费用,而不是从一个只是大致相似的名称去猜测。
690
573
  - **Hermes**:与 OpenCode 相同,LiteLLM 上**精确**匹配时按 token 定价,否则使用 Hermes 自身存储的费用。
691
574
  - **DeepSeek Harness**:`dsh` 本身不记录任何费用,因此全部经由与其他 file-based provider 相同的查找链依 LiteLLM 计价,没有 OpenCode 或 Hermes 那样的 stored cost 兜底。它会路由到部署方配置的任意 provider,因此部署自定义的 model 名称很常见;LiteLLM 完全比对不到时费用为 $0。
575
+ - **Antigravity**:与其他 file-based provider 一样依 LiteLLM 计价,model 取自每个 request 的 generation 记录。Compaction request 没有记录 model,其 token 会记在 `unknown` 下,费用为 $0。
692
576
  - **Grok**:只会把 `contextTokensUsed` 作为 cache-read token 计价(若该 model 未公布 cache-read 费率则改用 input 费率);这是单一时点的本地 context 估算,不是累计的 billed usage。
693
- - **缓存为原始数据**: 每日 cache 保存经过筛选的 LiteLLM 上游原始 JSON (而非派生结构), 因此 tiered / batch 定价无需重新获取即可使用. 每个 pricing map 各自拥有一个小型 process-local LRU, 重复查找保持低开销, 也不会在不同 map 之间互相污染.
694
577
 
695
578
  ---
696
579
 
697
- ## Docker 支持
580
+ ## 开发
698
581
 
699
- ```bash
700
- # Build image
701
- docker build -f docker/Dockerfile --target prod -t vibe_coding_tracker:latest .
702
- ```
582
+ 开发环境配置、从源码构建、测试、代码质量、commit 规范,以及发布与打包说明,都在 [CONTRIBUTING.md](./.github/CONTRIBUTING.md)。