Skip to content

fix(wintray): fold Grok CLI's tokens into Windows' today cost too - #119

Merged
aqua5230 merged 1 commit into
mainfrom
feat/wintray-grok-today-cost
Aug 30, 2026
Merged

fix(wintray): fold Grok CLI's tokens into Windows' today cost too#119
aqua5230 merged 1 commit into
mainfrom
feat/wintray-grok-today-cost

Conversation

@aqua5230

Copy link
Copy Markdown
Owner

問題

5463cd3 feat: fold Grok CLI's per-request tokens into today's cost/spend 讓 Grok CLI 的用量計入「今日花費/token 總計」與專案列表,但只接了 macOS:

  • macOS:menubar/state.pyapp_load_history_entries() 有呼叫 grok_loader.load_entries()
  • Windows:_WindowsTrayController._load_entries() 只讀 Claude 與 Codex

結果是每一筆 Grok 的用量在 Windows 的今日花費與專案列表裡都不存在。在開發機上實測,今天有 10 筆 Grok 記錄是系統匣完全沒看到的。

為什麼只缺這一段

指紋那半邊本來就是共用的:_history_file_sources() 已列入 GROK_LOG_PATH,Windows 透過 menubar_state.history_source_scan() 走同一條路,所以只有 Grok 活動的 session 已經能正確讓快取失效。缺的只有載入。

修法

grok_loader.load_entries() 沒有 jsonl_paths 參數——它直接讀 GROK_LOG_PATH,檔案不存在時自己 no-op——因此呼叫方式沿用相鄰兩個 loader 完全相同的 try/except 形狀,確保 Grok 讀取失敗時不會把已經收集到的 entries 丟掉。

驗證

對真實 log 實測:_load_entries() 現在回傳 2381 筆,其中 10 筆是 Grok,與直接呼叫 grok_loader 的筆數吻合。

  • 全套 1556 passed
  • ruff / mypy / check_file_size.py 全綠
  • 抽掉 wintray/app.py 的修正 → 3 個新測試轉紅;裝回 → 全綠

新增測試涵蓋:Grok entries 正常併入、Grok 丟 OSError 與丟 ValueError 時仍保留 Claude/Codex 的 entries 並設出正確的 error key。

🤖 Generated with Claude Code

https://claude.ai/code/session_01Es6czYMZ99nN8ma4QxZ98V

5463cd3 taught the popover to count Grok CLI activity toward today's
cost/token total and the project rows, but only wired it into the macOS
shell: menubar/state.py's app_load_history_entries() calls
grok_loader.load_entries(), while _WindowsTrayController._load_entries()
still read Claude and Codex only. Every Grok turn was therefore missing
from Windows' totals -- on this machine, 10 entries for today that the
tray simply never saw.

The fingerprint half was already shared: _history_file_sources() lists
GROK_LOG_PATH, and Windows reaches it through
menubar_state.history_source_scan(), so a Grok-only session already
invalidates the cache. Only the load was missing.

grok_loader.load_entries() takes no jsonl_paths -- it reads GROK_LOG_PATH
directly and no-ops when the file is absent -- so the call follows the
same try/except shape as its two neighbours, keeping a Grok read failure
from discarding the entries already gathered.

Verified against the real log: _load_entries() now returns 2381 entries,
10 of them Grok, matching a direct grok_loader call.

Full suite 1556 passed; ruff, mypy, and check_file_size.py clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Es6czYMZ99nN8ma4QxZ98V

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eeed578dac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread wintray/app.py
Comment on lines +1250 to +1252
entries.extend(grok_loader.load_entries(hours_back=0))
except OSError:
error_key = "history_load_error_file"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Propagate Grok read failures before caching partial history

When the Grok log exists but opening or reading it raises OSError—for example, during a transient Windows file lock—grok_loader.load_entries() catches that exception in loaders/grok_loader.py:59-62 and returns an empty list, so this handler never records history_load_error_file. _build_state() consequently treats the partial Claude/Codex result as successful and stores the current fingerprint at wintray/app.py:1314-1316, preventing retries until the log fingerprint or local date changes. The loader needs to expose this failure, or otherwise distinguish an unavailable log from an empty one, before the result is cached.

Useful? React with 👍 / 👎.

@aqua5230
aqua5230 merged commit e90daaf into main Aug 30, 2026
7 checks passed
@aqua5230
aqua5230 deleted the feat/wintray-grok-today-cost branch August 30, 2026 02:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant