Skip to content

v2.0.1: dedup fix, DeepSeek pricing, auto-refresh toggle, loading fix - #23

Merged
Carl723000 merged 16 commits into
ClaudeCodeUsage:mainfrom
Carl723000:release-candidate/v2.0.1
Jun 3, 2026
Merged

Carl723000 merged 16 commits into
ClaudeCodeUsage:mainfrom
Carl723000:release-candidate/v2.0.1

Conversation

@Carl723000

@Carl723000 Carl723000 commented Jun 3, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Patch release following v2.0.0. All changes are backwards-compatible and the new settings default to the previous behaviour.

What's fixed

What's new

  • Dashboard auto-refresh toggle — iOS-style slider pauses the webview while the status bar continues live. A "Refresh Now" button appears when off. Addresses issue Constant Refreshes When Using Tokens #17 follow-up.
  • claudeCodeUsage.fileWatching setting — opt-out of fs.watch.
  • claudeCodeUsage.pauseDashboardRefresh setting.
  • Opus 4.8 explicit pricing entry.
  • Diagnostic output channel: per-refresh stats + per-model token counts.

Docs

Dev

Credits

This release incorporates community contributions from:

Many code changes drafted with Claude Code.

Co-Authored-By: Claude noreply@anthropic.com

Carl723000 added 16 commits May 30, 2026 22:10
Assumed at the current Opus tier rate ($5 / $25 input/output per MTok,
$6.25 cache-write, $0.5 cache-read), same as 4.7 / 4.6 / 4.5.
Family-aware fallback would already pick the Opus tier for unknown
opus-4-* snapshots, but an explicit entry is cleaner and keeps the
"Per-model rates" line in the dashboard accurate.

If Anthropic differentiates Opus 4.8 pricing later, override here or
just hit the "Refresh Token Pricing" button to pull live LiteLLM data.
…eepSeek pricing

Issue ClaudeCodeUsage#18 (zhaoxiao9302): when a proxy like mimo or CC Switch writes
two records per message — a tokens=0 placeholder when streaming starts
and the real values after the response completes — both records share
the same messageId and lack a requestId, so they hash identically.
The previous dedup kept whichever appeared first, which was almost
always the zero-value placeholder, leading to massively under-reported
usage (the reporter measured \$0.20 displayed vs. \$7.98 actual on a
single day; 185 of 188 today-records had this pattern).

Fix: switch processedHashes from Set<string> to Map<string, number>
(hash → records[] index). On a duplicate hash, compare the new and
existing total token sums and keep whichever is higher. This naturally
resolves the placeholder/real pair regardless of arrival order, without
needing to detect the proxy itself.

DeepSeek pricing was also wrong: `deepseek-chat` and `deepseek-reasoner`
were priced at V4-Flash rates (\$0.14 / \$0.28 per MTok) even though
the `deepseek-chat` alias has pointed to V4-Pro since 2024-09. They are
now priced at the Pro tier (\$0.435 / \$0.87 / cache hit \$0.003625),
verified against https://api-docs.deepseek.com/quick_start/pricing/.
Added a separate `deepseek-v4-pro` entry. The family fallback for
unknown DeepSeek snapshots now also resolves to the Pro tier.

This is the same root cause behind the under-reported DeepSeek usage
seen by users running CC Switch.

Reported-by: @zhaoxiao9302 (issue ClaudeCodeUsage#18)
…cache

Three related fixes for the quota indicator and the file watcher:

1. Quota now refreshes unconditionally at the start of every refresh
   cycle and is no longer hidden when the workspace lacks Claude history
   or when the data directory cannot be found. The quota is account-
   level, so a fresh workspace should not affect it.

2. Quota fetch cache shortened from 2 min to 30 s, so switching between
   VS Code windows no longer shows a stale percentage for up to two
   minutes.

3. New setting `claudeCodeUsage.fileWatching` (default: true) — when
   disabled, falls back to interval-based refresh only. Closes issue
   ClaudeCodeUsage#17 (Rissew): constant refreshes during active token use can be
   distracting, this gives users the calmer mode on demand.

StatusBarManager.updateUsageData() no longer touches the quota item:
the caller (extension.refreshData) calls updateQuota() separately at
the very start of the cycle. This change is callback-compatible — the
optional usageLimits arg still works for callers wanting a single
update path.

Closes issue ClaudeCodeUsage#17.
Replace the Markdown table tooltip with an HTML <table> that embeds
inline SVG progress bars per row, mirroring what the official `/usage`
command shows. The bar fill colour changes by threshold to match the
status-bar warning/error backgrounds:

  - green  at  <80%   ("plenty left")
  - amber  at  >=80%  ("getting close")
  - red    at  >=95%  ("at the limit")

SVG was chosen over CSS-styled <div>s because VS Code's MarkdownString
sanitiser strips most `style` attributes but lets SVG through intact.
This means the bars render correctly on both light and dark themes
without needing theme-aware CSS variables.

The percentage and reset countdown columns are kept for users who
prefer the precise number; the weekly row still uses <br> to put the
reset moment and the countdown on two lines.
Four small follow-ups from RC testing:

- Bump package.json to 2.0.1 so the packaged .vsix has the right name
  during the RC cycle.

- Quota cache: 30 s → 120 s. Multi-workspace sync was the goal of the
  shorter window, but 30 s feels too chatty during active token writes;
  120 s matches the polling interval.

- Relax validateUsageRecord. The previous version dropped any record
  whose secondary fields had an unexpected type (e.g. `model` is null,
  `requestId` is a number). That likely cost us records from new
  Claude Code features (xhigh / ultracode / workflow) and from some
  proxies that write slightly atypical JSON. Now only the two real
  must-haves are required: timestamp + numeric input/output tokens.
  All other fields are treated as best-effort.

  Added validationDropReason() and a stats counter so the loader writes
  a one-line "X files, Y lines, kept=N, dedup-replaced=…, rejected: …"
  summary to the "Claude Code Usage" output channel on every refresh.
  This lets us see exactly which validator rule is rejecting records
  rather than guessing.

- Quota tooltip progress bars: SVG was being stripped by VS Code's
  markdown sanitiser (so the new look never reached users). Switched
  to coloured <span>s with non-breaking-space padding — pure HTML,
  background-color is in the safe-CSS allowlist, renders consistently.
  Same colour thresholds as the status-bar background (green / amber
  at 80% / red at 95%).
Small polish on the quota tooltip from RC testing:

- Bar widened from 16 to 24 segments so low percentages (5h:24%) read
  proportionally instead of "barely a sliver".
- Bar height compressed via font-size:70% on the outer span so the bar
  looks like a thin strip rather than a full-height block.
- Outer span now has a gray 100%-width background — the "track" /
  frame is always visible regardless of fill, so users can see where
  the bar ends and where the boundary is.
- Weekly reset time switched to 24-hour format (hour12:false) to
  suppress AM/PM that some locales add. "Wed 03:00" stays "Wed 03:00".
…diagnostics model breakdown

Tooltip polish (round 2):
- border-radius: 4px on both bar layers for rounded corners.
- Gray frame opacity bumped from 0.30 -> 0.55 so the 100% boundary is
  actually visible (previous version disappeared on most themes).
- font-size 70% -> 60% — bar reads as a thin horizontal strip rather
  than a full-line block.

Loader diagnostics now also list every model name found, sorted by
record count. This makes it instantly obvious whether a proxy is
writing records under a non-default model name (e.g. CC Switch's
deepseek-v4-pro[1m]) so we can investigate without guessing.
… model

Two follow-ups from RC testing round 4:

- Quota tooltip:
  - Bar height further compressed (font-size 60% → 48%) so the bar
    reads as a thin strip; height is now ~80% of what RC round 3 showed.
  - Added a 1px gray border on the outer span so the 0-100% frame is
    visible at all fill levels (the rgba track alone was easy to miss
    on busy backgrounds). Inner fill keeps 3px radius for soft corners.

- Loader diagnostic: model summary now reports token sum per model in
  addition to record count, formatted as e.g. `deepseek-v4-flash=99/0`.
  A model with N records but 0 total tokens is conclusive proof that
  every record for that model was a proxy zero-token placeholder — the
  pattern behind the missing-Flash story in CC Switch sub-agent paths.
…setting

Three RC-round-5 improvements bundled as one meaningful commit (in line
with the "every commit should pull its weight" rule):

1. Quota tooltip progress bar:
   The previous outer-span + rgba border was invisible under both light
   and dark themes. Rebuilt as four adjacent solid-coloured spans:
   `[dark-gray bookend][filled cells][light-gray empty][dark-gray bookend]`.
   The dark-gray (#666) bookends mark 0% and 100% with strong contrast on
   any theme; the light-gray (#cccccc) empty fill keeps the unfilled range
   obvious. Bar colour by threshold (green / amber / red) unchanged.

2. Diagnostic log timestamps now use the local timezone instead of UTC
   (`toLocaleTimeString(undefined, { hour12: false })`). Affects both the
   loader and the API client output channel lines.

3. New `claudeCodeUsage.pauseDashboardRefresh` setting (default false).
   When on, fs.watch and the polling timer skip the webview update; the
   status bar still refreshes so today's cost and quota stay live. The
   "Refresh Usage Data" command always force-updates the webview so
   users can pull a fresh view on demand. Addresses the issue ClaudeCodeUsage#17
   follow-up — agents writing to logs no longer thrash an open dashboard.
… track

Two improvements in one commit:

1. Dashboard now has an "Auto-refresh: ON/OFF" toggle in the header.
   Default state mirrors the `claudeCodeUsage.pauseDashboardRefresh`
   setting. Clicking the toggle:
     - flips the CSS class on <body> (auto-off) so the conditional
       "Refresh Now" button appears in the header
     - persists the new state by updating the setting
   When OFF, the status bar still refreshes; the dashboard waits for
   the user to press "Refresh Now" or run the command. This addresses
   issue ClaudeCodeUsage#17's follow-up comment — agents writing to logs no longer
   thrash an open dashboard while still keeping the user in control.

2. Quota tooltip progress bar reverted to the previously-rendering
   nested-span structure (the bookend approach didn't render in
   testing). Outer track is now solid #bbb instead of rgba — solid
   light-gray is visible on both light and dark themes without
   relying on opacity that some themes wash out. Inner colour fill
   sits on top with green/amber/red thresholds unchanged.

If the solid-gray track is still not visible enough, the path forward
is a v2.1 redesign rather than another small CSS tweak — this commit
is the last cosmetic attempt for v2.0.1.
Replace the previous text button with a proper switch:

- A native-looking <label> with an iOS-style slider (32x18 px). Slider
  turns green (#34c759) when auto-refresh is on, gray when off. Knob
  slides across via CSS transition. Focus ring uses the VS Code focus
  border colour.
- Switch state stays in sync with `claudeCodeUsage.pauseDashboardRefresh`
  and survives reload. The "Refresh Now" button only shows when the
  switch is off (controlled by the .auto-off body class).
- New i18n key `autoRefresh` translated for all six languages:
  EN "Auto refresh", DE "Auto-Aktualisierung", zh-TW "自動刷新",
  zh-CN "自动刷新", JA "自動更新", KO "자동 새로고침". Replaces the
  hardcoded English label.

Tooltip stays at 4e3f238 (nested-span with solid #bbb gray); further
cosmetic work deferred to v2.1.
…ner, iOS toggle

Summary of all changes landing in the v2.0.1 release:

Fixes
- Dedup now keeps the higher-token record when hashes collide (issue ClaudeCodeUsage#18,
  @zhaoxiao9302). Proxy "placeholder + real" pairs are handled correctly.
- DeepSeek pricing: deepseek-chat and deepseek-reasoner corrected from
  Flash rates to Pro rates ($0.435/$0.87). Added deepseek-v4-pro entry.
- Quota indicator no longer hides when workspace has no local Claude data.
- Webview / status bar no longer gets stuck on "Loading…" (PR ClaudeCodeUsage#20,
  @nickearnshaw): re-entrancy guard + spinner only on cold start.
- Log timestamps now use local time (not UTC).

Added
- Dashboard "Auto-refresh" toggle (iOS-style) with localised label.
  When off: status bar still updates, webview pauses until "Refresh Now".
- claudeCodeUsage.fileWatching setting (opt-out fs.watch).
- claudeCodeUsage.pauseDashboardRefresh setting.
- Opus 4.8 explicit pricing entry.
- Diagnostic output channel: per-refresh stats + per-model record/token counts.

Docs
- README intro rewritten to "The Claude Code coach in your status bar"
  slogan (all language variants updated).
- New Troubleshooting entries: cleanupPeriodDays for history retention
  (PR ClaudeCodeUsage#21, @nickearnshaw) and sub-agent token under-counting note.
- Credits updated for PRs ClaudeCodeUsage#20, ClaudeCodeUsage#21, ClaudeCodeUsage#22 (@nickearnshaw).

Dev
- launch.json preLaunchTask fixed for single-root checkout (PR ClaudeCodeUsage#22,
  @nickearnshaw).
@Carl723000
Carl723000 marked this pull request as ready for review June 3, 2026 12:36
@Carl723000
Carl723000 merged commit b5d69b9 into ClaudeCodeUsage:main Jun 3, 2026
1 check passed
@Carl723000
Carl723000 deleted the release-candidate/v2.0.1 branch August 24, 2026 11:29
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