@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-TW.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`,日後若想微調行為即可編輯它(見 [設定](#%E8%A8%AD%E5%AE%9A))。
40
+ 自動偵測並處理 Claude Code、Codex、Copilot、Gemini、OpenCode、Cursor、Hermes、Grok、DeepSeek Harness 及 Antigravity 的日誌檔。不需要任何設定——直接執行就能分析。首次執行時會以合理的預設值建立 `~/.vct/config.toml`,日後若想微調行為即可編輯它(見 [設定](#%E8%A8%AD%E5%AE%9A))。
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 cache 更新 |
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 cache 更新 |
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 輸出,附帶 pricing 資訊 |
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;以其他 model 名稱計價時才會多出 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 的 model。
173
+ > Model 列會依 cost 由小到大排序,所以花費最高的 model 會排在最後(在 `--table` 中緊鄰 `TOTAL` 列上方)。這個排序會套用到互動式儀表板、`--table` 與 `--text` 三種輸出;`--json` 的列則沒有固定順序。互動式儀表板也會隱藏在所選範圍內用量為 0 的 model。
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`](#%E8%A8%AD%E5%AE%9A) 中精簡 `[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`](#%E8%A8%AD%E5%AE%9A) 中精簡 `[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` 保留為隱藏別名,現有 script 仍可繼續使用。
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。把某個 provider 設為 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),沒在用的話很方便。 |
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. **驗證後 cache**: 只接受成功且包含實際價格的 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 訊息本身儲存的費用,而不是從名稱相近的 model 去猜測。
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**: 每日 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)。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mai0313/vct",
3
- "version": "2.7.1",
3
+ "version": "2.8.0",
4
4
  "description": "Vibe Coding Tracker - AI coding assistant telemetry/usage parser, aggregate JSONL events into CodeAnalysis results",
5
5
  "author": "Wei Lee <mai@mai0313.com>",
6
6
  "license": "MIT",