fix(wintray): fold Grok CLI's tokens into Windows' today cost too - #119
Conversation
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
There was a problem hiding this comment.
💡 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".
| entries.extend(grok_loader.load_entries(hours_back=0)) | ||
| except OSError: | ||
| error_key = "history_load_error_file" |
There was a problem hiding this comment.
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 👍 / 👎.
問題
5463cd3 feat: fold Grok CLI's per-request tokens into today's cost/spend讓 Grok CLI 的用量計入「今日花費/token 總計」與專案列表,但只接了 macOS:menubar/state.py的app_load_history_entries()有呼叫grok_loader.load_entries()_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的筆數吻合。wintray/app.py的修正 → 3 個新測試轉紅;裝回 → 全綠新增測試涵蓋:Grok entries 正常併入、Grok 丟
OSError與丟ValueError時仍保留 Claude/Codex 的 entries 並設出正確的 error key。🤖 Generated with Claude Code
https://claude.ai/code/session_01Es6czYMZ99nN8ma4QxZ98V