Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ClaudeCodeUsage/ClaudeCodeUsage
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v2.1.1
Choose a base ref
...
head repository: ClaudeCodeUsage/ClaudeCodeUsage
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v2.2.0
Choose a head ref
  • 12 commits
  • 50 files changed
  • 5 contributors

Commits on Jul 1, 2026

  1. fix: recognize Claude Sonnet 5 as a 1M-context model (#50)

    Co-authored-by: UfukTanriverdi8 <UfukTanriverdi8@users.noreply.github.com>
    UfukTanriverdi8 and UfukTanriverdi8 authored Jul 1, 2026
    Configuration menu
    Copy the full SHA
    e2003b9 View commit details
    Browse the repository at this point in the history

Commits on Jul 3, 2026

  1. ci: autolabel PRs via release-drafter (pull_request_target) (#53)

    The autolabeler config in .github/release-drafter.yml was ready but never fired — the workflow only triggered on push-to-main, so PRs were never labelled and the maintainer had to set the version label by hand. Adds a pull_request_target trigger + pull-requests: write so title/branch-based labels are applied automatically (works on fork PRs too; the autolabeler reads the title/branch only, never runs PR code).
    
    Co-authored-by: Claude <noreply@anthropic.com>
    Carl723000 and claude authored Jul 3, 2026
    Configuration menu
    Copy the full SHA
    0fa6d0e View commit details
    Browse the repository at this point in the history
  2. ci: enable @ccu-bot first-pass automation (issues + PRs), inert until…

    … switched on (#56)
    
    Adds only the automation-enablement slice so the bot can be tested without merging the rest of V2.2:
    - `.github/workflows/claude.yml` — maintainer `@ccu-bot` mention agent.
    - `.github/workflows/issue-first-pass.yml` — one first-pass comment per new issue.
    - `.github/workflows/pr-first-pass.yml` — one first-pass review per new PR (base checkout only; reads the diff via API, never runs PR code).
    - Publishes the technical `ARCHITECTURE.md` (+ zh-CN) so the bot has a real map.
    - CONTRIBUTING: a section describing @ccu-bot and its limits.
    
    SAFE BY DEFAULT: every job's `if:` requires the repo variable
    AUTOMATION_ENABLED == 'true' AND the ANTHROPIC_API_KEY secret; official or a third-party Anthropic-format endpoint via ANTHROPIC_BASE_URL. First-pass replies are labelled automated + disclaimed; a maintainer reviews everything.
    
    Co-authored-by: Claude <noreply@anthropic.com>
    Carl723000 and claude authored Jul 3, 2026
    Configuration menu
    Copy the full SHA
    d160612 View commit details
    Browse the repository at this point in the history
  3. fix(ci): add id-token: write to the first-pass workflows (OIDC) (#58)

    The issue/PR first-pass runs failed with "Could not fetch an OIDC token. Did you
    remember to add id-token: write?" — claude-code-action@v1 mints its GitHub token
    via OIDC and needs that permission (the mention workflow already had it). Added
    it to issue-first-pass.yml and pr-first-pass.yml.
    
    Co-authored-by: Claude <noreply@anthropic.com>
    Carl723000 and claude authored Jul 3, 2026
    Configuration menu
    Copy the full SHA
    39150ac View commit details
    Browse the repository at this point in the history
  4. fix(ci): use github.token so @ccu-bot needs no Claude GitHub App (#60)

    The first-pass runs failed with "Claude Code is not installed on this
    repository" — by default claude-code-action@v1 exchanges its OIDC token for a
    Claude GitHub App installation token. We drive a third-party model (DeepSeek), so
    installing Anthropic's app is the wrong dependency. Passing
    `github_token: ${{ github.token }}` makes the action use the workflow token
    directly for commenting (issues/pull-requests: write already granted), skipping
    the app entirely. Applied to all three workflows.
    
    Co-authored-by: Claude <noreply@anthropic.com>
    Carl723000 and claude authored Jul 3, 2026
    Configuration menu
    Copy the full SHA
    1ba48d0 View commit details
    Browse the repository at this point in the history

Commits on Jul 4, 2026

  1. feat(ci): controlled single-call @ccu-bot first-pass (no autonomous a…

    …gent) (#64)
    
    Replaces the autonomous claude-code-action first-pass (which hit CI tool-
    permission denials AND is a prompt-injection risk on public issues) with a
    deterministic script: .github/scripts/first-pass.mjs reads the project docs
    (+ PR diff), makes ONE Anthropic-format model call, and posts ONE comment. It
    runs NO tools and never executes anything from the issue/PR, so a malicious
    public issue can't steer it into misusing the token or leaking the key.
    
    - Works against a third-party endpoint (ANTHROPIC_BASE_URL); model defaults to
      deepseek-v4-flash (override via CCU_BOT_MODEL).
    - PR path checks out the BASE repo, fetches the diff via the API (`gh pr diff`)
      — never runs PR head code.
    - Labelled automated + disclaimed; reply in the author's language; answer from
      docs, ask-don't-guess. INERT until AUTOMATION_ENABLED='true'.
    - The @ccu-bot MENTION workflow keeps the agent (maintainer-gated = safe).
    
    Co-authored-by: Claude <noreply@anthropic.com>
    Carl723000 and claude authored Jul 4, 2026
    Configuration menu
    Copy the full SHA
    e52634c View commit details
    Browse the repository at this point in the history
  2. feat(ci): two-tier first-pass bot with controlled repo-file escalation (

    #66)
    
    Builds on #64. When the cheap first-pass model (CCU_BOT_MODEL, default
    deepseek-v4-flash) reports it can't answer from the docs alone, escalate to a
    stronger model (new CCU_BOT_MODEL_PRO, default deepseek-v4-pro) with thinking
    on, and let it NAME a few repo source files. The SCRIPT reads them — repo-
    relative text files only, no "..", size-capped, must resolve inside the repo
    root — so there is still no agent tool and no way for a malicious issue to make
    it read or execute anything arbitrary (same injection-safe property as #64,
    just with a controlled retrieval step). If it still can't answer, the reply asks
    for the specific missing info/logs and suggests the issue template.
    
    Also standardizes every reply into a skimmable shape: TL;DR/结论 first, then
    analysis, then suggested next steps. The thinking param is best-effort — the
    script retries once without it if the endpoint rejects it — so this stays
    portable across third-party Anthropic-format endpoints.
    
    Still INERT until AUTOMATION_ENABLED='true' + ANTHROPIC_API_KEY, unchanged.
    
    Co-authored-by: Claude <noreply@anthropic.com>
    Carl723000 and claude authored Jul 4, 2026
    Configuration menu
    Copy the full SHA
    a55968a View commit details
    Browse the repository at this point in the history
  3. fix(ci): don't auto-review maintainer PRs; treat an empty model reply…

    … as a no-op (#67)
    
    - The PR first-pass now SKIPS pull requests authored by OWNER / MEMBER /
      COLLABORATOR — a maintainer's own finished PR doesn't need an auto first-pass
      (that review is for external contributors). #66 showed it firing on our own
      PR and failing on the big self-referential diff.
    - An empty model reply is now a soft no-op (exit 0) instead of a hard failure,
      so a benign blank response doesn't leave a red check on the PR/issue.
    
    Co-authored-by: Claude <noreply@anthropic.com>
    Carl723000 and claude authored Jul 4, 2026
    Configuration menu
    Copy the full SHA
    947ce32 View commit details
    Browse the repository at this point in the history

Commits on Jul 5, 2026

  1. fix: timezone bucketing and cache-write cost accuracy (#62)

    * fix: timezone bucketing and cache-write cost accuracy
    
    * bucket Today/month/daily/hourly totals by the configured IANA zone
    * keep the loader zone in lockstep with display; recompute on change
    * split cache writes into 1h (2x) vs 5m (1.25x) when the log has the ttl
    * add tests for zone bucketing and the cache-write split
    
    * i18n: note timezone sets the daily cost boundary
    
    * add the day-boundary clause to the timezone help in all six locales
    * update the timezone description in README and the locale editions
    
    * fix: changelog minor touch-up
    
    * Maintainer edit: keep the cache-write TTL pricing; drop the timezone changes
    
    The timezone-bucketing half overlaps with the shared zone-aware day-key rework
    landing in V2.2, so this reduces the PR to just the cache-write TTL pricing
    (pricing.ts + types.ts + pricing.test.ts) to merge cleanly. zeyutang's original
    commits are preserved; the timezone work is welcome as a follow-up PR.
    
    * Remove stray sample-card SVGs accidentally swept into the maintainer edit
    
    ---------
    
    Co-authored-by: Carl <74130028+Carl723000@users.noreply.github.com>
    zeyutang and Carl723000 authored Jul 5, 2026
    Configuration menu
    Copy the full SHA
    434b8e6 View commit details
    Browse the repository at this point in the history
  2. Drop unused @types/glob to clear vulnerability (#63)

    * @types/glob was unused and deprecated (glob ships its own types)
    * it transitively pulled glob → minimatch → brace-expansion
    * removing it clears 3 high-severity advisories; audit now clean
    * never shipped to users (devDependency; node_modules excluded from the vsix)
    zeyutang authored Jul 5, 2026
    Configuration menu
    Copy the full SHA
    547d52a View commit details
    Browse the repository at this point in the history

Commits on Jul 6, 2026

  1. feat: V2.2 — usage share card, conversation viewer, insights suite, h…

    …eatmap & more (#68)
    
    * chore: V2.2 changelog scaffold, v2.0.3 + v2.1.0 dates, org metadata
    
    - CHANGELOG: add [2.2.0] — Unreleased; date [2.1.0] — 2026-06-26; add the
      missing [2.0.3] maintenance section (macOS Keychain, node:test, issue
      templates, CI hardening, release workflow).
    - package.json: repository / bugs / homepage now point at the org
      (ClaudeCodeUsage/ClaudeCodeUsage), not jack21.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(settings): tokenDecimalPlaces — decimals for compact token display
    
    New setting (default 1, 0–2) controlling only compact token rendering (1.2M /
    345.6K), separate from cost decimalPlaces; full integer counts are unaffected.
    Wired through I18n.formatTokensCompact and the formatNumber compact path, the
    settings catalog + SETTINGS_I18N (5 locales), ExtensionConfig and config apply.
    7 new node:test cases (0/1/2 places, K/M/B, integer pass-through, clamp).
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(quota): clean status-bar quota text; opt-in reset + 5h-only
    
    Status bar stays clean — default '5h 6% · wk 1%' (space, middot), not the dense
    '5h:6%:4.8h | wk:1%:1.6d'. Two opt-in settings (both default off):
    - showResetInStatusBar → '5h 6% ↻4.8h | wk 1% ↻1.6d' (compact countdown, bar sep)
    - quotaFiveHourOnly → show only the 5h window
    Full reset times always remain in the tooltip. Extracted a pure, dependency-free
    src/quotaFormat.ts (formatQuotaStatusText / compactReset / worstShownUtilisation)
    so it's unit-tested without vscode; statusBar.updateQuota now uses it. Catalog +
    SETTINGS_I18N (5 locales) + config wiring. 8 new node:test cases.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(settings): dashboardAutoRefresh (positive) replacing pauseDashboardRefresh
    
    Double-negative 'Pause dashboard auto-refresh' becomes the positive
    'Dashboard auto-refresh' (key dashboardAutoRefresh, default true). One-shot
    SettingsStore.migrateDashboardAutoRefresh inverts any old pauseDashboardRefresh
    value (globalState or settings.json) — true→false, false/undefined→true — behind
    its own migration flag so it runs even post-v1-migration. All consumers
    (extension refresh gating, webview body auto-off class + toggle handler) and
    SETTINGS_I18N (5 locales) updated. Compile clean; 26/26 node:test green.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(v2.2): share-card + heatmap pure-logic cores (tested)
    
    Tested, dependency-free foundations for the two big V2.2 features; the webview
    rendering + PNG export + heatmap cells will build on these in follow-up PRs.
    
    - src/shareCard.ts (Usage Share Card / 用量卡片): totalTokens, cacheSharePct,
      modelFamily (no version exposed), selectShareBadge (deterministic, local rules:
      Context Marathoner / Cache Saver / Token Sprinter / Workflow Pilot / Steady
      Builder), buildShareCardData (privacy redaction — project name OFF by default,
      no room in the data shape for paths/ids/prompts), DEFAULT_SECTIONS,
      shareCardFilename.
    - src/heatmap.ts: daysInMonth, intensityBucket (0..4), buildMonthHeatmap (zero-
      fills every day, tokens/cost/sessions metric switch).
    - 11 new node:test cases (Phase 5.8 + 6.4). 37/37 green.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * docs: V2.2 roadmap + V2.3 achievements spec
    
    - docs/V2.2.md: what shipped in 2.2 (status-legended), the Usage Share Card
      design + enforced privacy model, the token heatmap design, the settings
      changes, session/quota status, the contributor/PR credit policy, and the
      planning items (advice 'new session/clear' nudge, Optimizer opt-in file
      reading, conversation export, subscription sharing, Codex adapter, GitHub
      profile heatmap).
    - docs/V2.3-achievements.md: SPEC ONLY (no V2.2 code) — positioning, privacy,
      the full achievement catalogue (token/session/prompt/workflow/model/plugin/
      hidden), levels, anti-gaming, community roadmap, the icon-prompt template,
      milestones, and the GitHub-profile sharing plan.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * docs(changelog): fill [2.2.0] with shipped items
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * docs: consolidate V2.2 specs into one local master
    
    Fold the public roadmap (docs/V2.2.md) and the two local working specs
    (V2.2-FEATURES-SPEC.md, V2.2-AUTOMATION-SPEC.md) into a single gitignored
    master, docs/V2.2-SPEC.md (+ a zh-CN mirror for review), so the whole V2.2
    plan can be handed to one execution pass. Drop the CHANGELOG pointer to the
    now-removed public roadmap; the Added/Changed entries already record what
    actually shipped in 2.2.0.
    
    * fix(stats): drop API-error retry re-logs from the Messages count
    
    When a request errors, Claude Code retries and re-logs the same user prompt,
    so an identical prompt can appear several times seconds apart around a
    system:api_error record — inflating "Messages". Dedupe identical prompts that
    recur within a short window (retry re-logs); genuine re-sends minutes/hours
    later still count. Logic isolated in a pure, unit-tested module.
    
    Verified on real sessions: removes only true retry re-logs, keeps repeats.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(dashboard): cache-hit-rate column in the breakdown tables
    
    Adds a cache hit rate (cacheRead / input-side tokens) column to the All-time
    monthly table, the This-month daily table, and both expanded drill-downs
    (month→days, day→hours), so cache efficiency is readable per row. Reuses the
    existing cacheHitRate/formatPercent helpers server-side and a small cacheHitPct
    helper client-side; detail-row colspans bumped 8→9.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix(dashboard): timezone-correct date bucketing + table scroll behavior
    
    Bucketing: the month/day breakdowns mixed a UTC day key with a local month
    boundary, so a record just after local midnight on the 1st was filed under the
    previous month's last day (visible as a stray "30th" inside This-Month). Day
    and month keys now both derive from the configured timezone (empty = system)
    via a pure, unit-tested dateKeys module.
    
    Table scroll (2b): number cells no longer wrap — compact k/M numbers fit the
    panel with no horizontal scrollbar; full integer numbers overflow so only the
    table scrolls, while the daily bar chart keeps its own independent scroll.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(dashboard): click a month's Token composition to drill into daily
    
    The All-time Token-composition bars are now clickable (each is a month): a
    click expands that month's detail — which now includes a per-day composition
    chart next to the daily chart and table — so the input/output/cache split is
    readable day by day. Reuses the existing month-detail round-trip
    (toggleMonthlyDetail → getDailyData), with a small client-side composition
    renderer mirroring the server one.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix(i18n): finish wiring pt-BR (settings dropdown + READMEs + CLAUDE.md)
    
    pt-BR shipped in 2.1.1 (#48) with the strings, package.json enum and
    SupportedLanguage type, but was missing from the dashboard language dropdown
    (settings.ts enumValues) and every README's UI-language list — so users
    couldn't actually pick it. Added it in all those places and noted it in
    CLAUDE.md (which also flags that de-DE strings exist but are exposed nowhere).
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(heatmap): GitHub-style contribution-graph SVG core (Claude orange)
    
    Pure, unit-tested heatmapSvg module: lays a calendar year of daily usage
    (Jan 1 → today, no future padding, GitHub current-year style) into a
    contribution grid and renders a self-contained SVG — Claude-orange intensity
    ramp, title row (no month-label overlap), month + weekday labels, Less/More
    legend, a bottom-left source watermark, per-day tooltips — for a GitHub profile
    README. Not wired to a command yet; a real-data preview was generated.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(heatmap): GitHub-style contribution-graph SVG core (Claude orange)
    
    Pure, unit-tested heatmapSvg module for a GitHub profile README: trailing ~year
    ending today (GitHub's default view, no future padding), Claude-orange intensity
    ramp, a top-left summary ("5.3B tokens in Claude Code · 2026"), GitHub-style
    per-day tooltips ("1.2M tokens on June 18th"), month + weekday labels, Less/More
    legend, and a bottom-left source watermark. Not wired to a command yet.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(heatmap): Export Token Heatmap command (GitHub-style SVG)
    
    Adds "Claude Code Usage: Export Token Heatmap (GitHub style SVG)" — builds a
    per-day usage map (timezone-aware, via getDailyUsageMap) and writes the
    contribution-graph SVG to a chosen file, offering to copy the Markdown embed
    snippet for a GitHub profile README. Command-palette accessible.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(heatmap): larger fonts (title 15 / months 12 / labels 11), 12px cells
    
    * feat(dashboard): opt-in token heatmap on the All tab (showHeatmap, default off)
    
    Adds a showHeatmap setting (default off). When on, the All tab shows a
    GitHub-style yearly token heatmap at the top, built from allRecords via
    getDailyUsageMap + renderHeatmapSvg. Inline SVG, so per-day hover tooltips work
    in the dashboard (unlike GitHub's image-sanitised READMEs). Mainly a shareable
    re-view of existing data, hence opt-in.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix(stats): exclude the compaction "session continued" summary from Messages
    
    Verifying the Messages count on real logs surfaced ~5 counted "prompts" that
    were actually Claude Code's auto-injected "This session is being continued from
    a previous conversation…" compaction summary (a user-role message the user never
    typed). isSyntheticUserText now drops it, alongside interrupted-request and
    slash-command echoes. (Tool-result user messages were already excluded.)
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix: timezone is a validated dropdown, not free text (#51)
    
    The reporter suggested a dropdown of valid zones — the right fix, since it makes
    an invalid value impossible to enter. The Timezone setting is now an enum
    populated from Intl.supportedValuesOf('timeZone') ('' = system default). Kept a
    validation guard in I18n.setTimezone as belt-and-suspenders for old synced
    configs that already hold a bad hand-typed value (which otherwise made Intl
    throw and crashed the dashboard). Also the explicit claude-sonnet-5 pricing
    entry. Unit-tested.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat: one-time "what's new" prompt after an upgrade (feature discovery)
    
    Shows a single dismissible notification the first time a new major.minor runs,
    pointing at the dashboard — so users find new features, including the opt-in
    default-off ones they'd otherwise never notice. Keyed by major.minor in
    globalState (patch releases don't re-nag); skipped on fresh installs.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(content): opt-in top-10 costliest conversations (showEfficiency)
    
    New showEfficiency setting (default off — not everyone wants cost metrics).
    When on, the Content tab gains a "Top 10 costliest conversations" panel: rows
    ranked by cost, each expandable (native <details>, no JS) to its tokens,
    cache-hit rate, top model and project. Same toggle will gate the
    cost-per-message + cache-savings chips on Today/projects (next).
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(content): efficiency chips — cost per message + realised cache savings
    
    Under the usage summary (Today / Month / All), gated by showEfficiency: an exact
    "cost per message" chip (totalCost ÷ messages) and a "cache savings" chip
    (cacheRead tokens × the per-model input−cacheRead price gap — what caching
    actually saved vs. full input price). Off by default.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(share-card): render usage share card as self-contained SVG + export command
    
    Batch 6 (V2.2 share card) — make the tested shareCard.ts core visible/exportable.
    
    - shareCardSvg.ts: renderShareCardSvg(ShareCardData) -> SVG. No DOM, no
      html-to-image dep, no CSP concerns. Landscape 1200x630 social-card layout:
      header, big token hero (falls back to cost/sessions), up to four stat tiles,
      a per-day rhythm strip, badge pill, and watermark. Only draws fields present
      in ShareCardData, so privacy stays enforced by the type's shape.
    - ClaudeDataLoader.buildShareInput(records, range): aggregate inputs for
      today / last 7 days / this month, timezone-bucketed to match the dashboard.
      Returns only aggregate numbers (no records, no identifiers).
    - extension.ts: "Export Usage Share Card (SVG)" command — pick range, save,
      and open for review.
    - 8 renderer tests (well-formed output, hero fallback, omitted sections,
      tiles/badge/rhythm, XSS-escaping, watermark toggle). 75/75 pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix(efficiency): scope efficiency chips to the Today view
    
    Per spec the cost/message + cache-savings chips belong on Today (and
    per-project), not on the Month / All-time summaries. renderUsageData now
    takes an { efficiency } opt and only Today passes it, so the chips no longer
    leak onto the other two scopes. Still opt-in via showEfficiency.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(efficiency): add opt-in "Cost/msg" column to the projects table
    
    Completes the "Today + projects" efficiency surfacing. Projects is a table,
    so per-project cost-per-message reads better as a column than a summary chip.
    Gated by showEfficiency (off by default); shows "—" when a project has no
    counted messages. Non-sortable column — sortTable() reads data-sort-* row
    attributes, so inserting it doesn't disturb the other columns' sorting.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(v2.2): efficiency tokens/msg chip, curated tz dropdown, quota Xd Yh, session-delete opt-in, whats-new preview
    
    Batch of the smaller items from Carl's review:
    
    - Efficiency chips: add "Tokens / message"; show on Today AND Month AND
      All-time again (removed the Today-only scoping). Projects keeps its column.
    - Timezone: trimmed the ~400-zone dropdown to a curated common set, each
      labelled with its live (DST-aware) UTC offset, e.g. "(UTC+08:00) Shanghai".
      Settings enum renderer now keeps a stored-but-uncurated value selectable.
    - Quota tooltip: weekly reset countdown now "4d 12h" instead of "4.5d"
      (statusBar.formatCountdown); the compact status-bar form keeps "4.5d".
    - Session delete: gated behind new opt-in "enableSessionDelete" (off by
      default) — it touches local history files, so it shouldn't be on for
      everyone. Resume tooltip now explains what resume does (EN/zh-CN/zh-TW).
    - What's-new: extracted showWhatsNew(); added "Preview What's New" command so
      it's testable (a fresh F5 install otherwise just sets the baseline silently).
    
    Compile clean, 75/75 tests pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(content): rework "costliest" panel to top-10 single MESSAGES
    
    The old panel just re-ranked sessions (a dupe of the Sessions tab). Carl wants
    the Content tab's version to fit that tab's theme (AI advice / optimizer):
    rank individual assistant turns and let each expand to explain itself.
    
    - getCostliestMessages(records, limit): walks each session in timestamp order,
      attaches the preceding user prompt, and keeps the top-N billed turns by cost
      (bounded insertion). Each carries the full model id, the authoritative
      skill/plugin attribution, the 4 token types, cost, prompt, project.
    - Store a truncated _promptText (300 chars) on the synthetic user-prompt
      records so the panel can show what triggered an expensive turn.
    - Webview: renderCostliestMessages() — summary row = rank + prompt + cost;
      expands to the prompt (blockquote), model, skill, token breakdown, project.
      Precomputed in the extension and passed in (not re-walked per re-render).
    
    Verified on real data (8855 records): top-10 with prompts + full model ids
    (fable-5 / opus-4-8 / opus-4-7) attach correctly.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(share-card): discoverable in-dashboard preview + richer card (composition, QR, full model, peak)
    
    Addresses Carl's share-card review:
    - Discoverable: an always-visible "Share card" panel on the All tab with an
      inline, responsive preview + "Export as SVG…" button (the command alone was
      unfindable). Export now matches the preview (composition on).
    - More metrics: a token-composition stacked bar (the four billed token types)
      with a legend — off in DEFAULT_SECTIONS but on in the dashboard/export.
    - Bar scale: the daily-rhythm strip now has a baseline, a peak gridline and a
      "peak <N>" label so the bars carry a scale.
    - Full model name: prettyModelName() → "Opus 4.8" (not just "Opus"); the card
      shows the specific model.
    - Traffic (引流): a real QR to the upstream repo bottom-right, wrapped in a
      link + "★ Star us on GitHub". QR is a static embedded asset (generated once
      with `qrcode`, then uninstalled — zero runtime deps). See shareCardQr.ts.
    - Canvas grew to 1200×760 to fit the new blocks; layout verified overlap-free.
    
    +6 tests (QR link, full model, composition bar, peak label, prettyModelName).
    80/80 pass, compile clean.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix(content): show hidden thinking honestly + full scrollable prompt in top-10
    
    Two fixes from Carl's review:
    
    #6 Thinking-share = 0 bug. Models that omit their raw reasoning (Fable 5;
    Opus 4.8 by default) log `"thinking":""` with the CoT encrypted in `signature`,
    so the text-length estimate read 0% even though thinking was on and billed.
    Now: detect a thinking block with empty text + a signature and flag the
    session (ThinkingShare.hiddenThinking). The Sessions "thinking share" column
    shows "hidden" (tooltip explains) instead of a misleading 0%; a partly-hidden
    session shows "N%*". i18n across all 7 languages.
    
    #1 Top-10 costliest messages: raise the stored prompt cap 300 → 4000 chars and
    render the prompt in a scrollable box (max-height 220px) so the whole triggering
    prompt is visible for cost analysis; giant pastes still capped + marked
    "(truncated)".
    
    Verified on real data: 33 measurable / 2 hidden / 14 genuine-zero sessions.
    Compile clean, 80/80 tests pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(settings): timezone dropdown covers all IANA zones (Common + All optgroups)
    
    #3: the curated list was nicer but not complete. Now enumValues holds every
    IANA zone (418) so any is valid, and the dropdown groups them with <optgroup>:
    "Common" (25 curated, offset-labelled) at the top for quick picking, then
    "All zones" (the remaining 395, alphabetical, also offset-labelled). Added an
    optional enumGroups to SettingDef; the webview enum renderer draws optgroups
    when present and still injects a previously-stored out-of-list value.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(share-card): configurable, default-off share panel (range/scope/metrics, on-demand)
    
    Overhaul from Carl's review (Q2):
    - Drop the QR (deleted shareCardQr.ts) — watermark now carries the repo URL.
    - Default OFF: new `enableShareCard` setting; the All-tab panel shows a
      discoverable pointer to Settings until enabled.
    - Config IN the plugin: range (this month / last 7d / last 12 months / today /
      last 12 specific calendar months) + scope (overall / a project / a session) +
      per-metric checkboxes. buildShareInput now takes range+scope; supports
      `month:YYYY-MM` and `year`, resolves a project/session filter, and returns
      dailyDates + a human range label ("June 2026").
    - Generate-on-demand: nothing renders until "Generate preview" (no
      per-keystroke re-render). Export uses the same config (webview builds + saves).
    - More selectable sections incl. a new `messages` (message count); default ON =
      est. cost + top model + cache-hit (+ token hero, rhythm, badge). Sessions,
      messages, composition, project name are opt-in.
    - Token composition legend now shows the absolute amount as well as the %.
    - Rhythm strip labels the first & last date so the x-axis is meaningful.
    - Buttons reuse the plugin's .btn-secondary style. Canvas back to 1200×680.
    
    Verified on real data (month/year/specific-month, project & session scope).
    Compile clean, 83/83 tests pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(heatmap): publish token heatmap to GitHub via built-in auth (Q4)
    
    One-click "Publish Token Heatmap to GitHub" — uses VS Code's GitHub
    authentication (getSession 'github' ['repo'], no PAT handling), then creates or
    updates the heatmap SVG in a repo via the Contents API. Defaults to the user's
    profile repo (owner/name = username) so it renders on their GitHub home page;
    remembers the last repo/path. Buttons added to the heatmap panel (Export /
    Publish to GitHub) + a command-palette entry. Minimal https helper (the codebase
    avoids fetch). Supersedes the spec's earlier "no GitHub in V2.2" note — Carl
    approved it for V2.2.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(ci): mention-driven @claude agent (Track 2 A1) — inert until owner enables
    
    First piece of the V2.2 AI automation. A maintainer can summon Claude with
    "@claude ..." in an issue / comment / PR review; it reads the repo (CLAUDE.md,
    ARCHITECTURE.md, CONTRIBUTING.md) and can reply or open a PR.
    
    SAFE BY DEFAULT — the job's `if:` requires BOTH a repo variable
    AUTOMATION_ENABLED='true' (kill switch) AND the ANTHROPIC_API_KEY secret, and
    only fires for OWNER/MEMBER/COLLABORATOR authors. With neither set it never runs
    and spends no budget. `anthropics/claude-code-action@v1`, --max-turns 12,
    timeout 15m, concurrency-guarded.
    
    A2 (triage draft-queue) and A3 (PR first-pass review) — the auto-posting pieces
    — are the next, separately-reviewed step; they need the owner to add the
    ANTHROPIC_API_KEY secret first. See docs/V2.2-SPEC.md Track 2.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(settings): timezone dropdown = full UTC-offset coverage (not every city)
    
    Carl clarified Q3: it's the UTC *offsets* that must be complete, not every
    location. Replaced the 418-city "All zones" group with a "UTC offset" group
    covering every offset (-12:00 … +14:00, incl. the real :30/:45 ones). Whole
    hours use fixed-offset Etc/GMT zones (no DST); fractional offsets use a
    representative zone with a region hint. "Common" named zones stay at the top.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(content): quantify cache-miss in top-10 costliest messages (Q7)
    
    Seeing the prompt alone didn't explain the cost. Each costly message now carries
    its cost split by token type (cache write / read / output / uncached input), and
    the panel shows the main cost driver (e.g. "cache writes (miss) — 96% of cost"),
    the cache-hit rate, and the full split. On real data the top turns are ~0-2%
    cache-hit and cache-write-dominated — i.e. the context was re-sent uncached
    (a cache miss), not that the answer was long. Now distinguishable at a glance.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(share-card): portrait + size presets, avatar, hourly today, tidy panel (Q1/Q2/Q3/Q5/Q6 review)
    
    Share-card round 2 from Carl's review:
    - Layout rewritten to flow vertically and distribute spare height as even gaps,
      so the same content reads well at every size. Size presets: Landscape
      1200×680, Square 1080×1080, Portrait 1080×1350, Story 1080×1920 (portrait for
      phones). Watermark pinned to the bottom with a clear gap — fixes the date/name
      overlap.
    - Rhythm bars are centred + width-capped, so short ranges don't look sparse;
      "today" now uses HOURLY buckets (24 bars, 00:00→23:00) instead of one bar.
    - Avatar: opt-in "GitHub avatar" fetches the signed-in user's avatar
      (read:user, on demand, cached) and embeds it (circular, top-right, replacing
      the badge). Renderer supports opts.size + opts.avatarDataUri.
    - Config panel beautified to the plugin's card language (bordered card, field
      grid, chip checkboxes, checkerboard preview frame) + a Size select; the range
      dropdown is grouped (Rolling / Specific month) with a "(last month)" marker.
    - Heatmap→GitHub publish now shows a consent modal first (it's an auth+write
      action, unlike a local export).
    
    +4 tests (size presets, avatar embed). 85/85 pass, compile clean.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(settings): group opt-in toggles under "Optional features" (Q3)
    
    Reorganized the settings for user habit: the four opt-in dashboard toggles
    (token heatmap, efficiency insights, share card, delete-session action) move out
    of the General grab-bag into a dedicated "Optional features" group, so General
    holds just locale/format/behaviour. New SettingGroup 'features' + i18n label
    across all 7 languages. (Share-card range dropdown grouping / "last month"
    shipped in af3509e.)
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(ci): let the @claude agent use a third-party Anthropic-compatible endpoint (Q8)
    
    A Claude subscription can't drive CI (Actions needs a key). For maintainers
    without an official Anthropic key, the mention agent now honours a repo variable
    ANTHROPIC_BASE_URL (env on the action step) so it can point at any
    Anthropic-format-compatible provider, with that provider's key in the
    ANTHROPIC_API_KEY secret. Unset = official API. Still inert until enabled.
    Clarified that repo guidance is read from CLAUDE.md/ARCHITECTURE.md (no full-repo
    re-read each run).
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix(quota): don't fabricate a 5h reset countdown while idle after a reset (#3)
    
    The 5h / weekly windows are usage-anchored: the next window (and its reset)
    only starts when you send your next message. When a window's resets_at passed
    while idle, liveWindows() rolled it forward ("reset = old + 5h") and showed a
    countdown that was wrong until the next real fetch — exactly the "reset already
    ticking before I sent anything, then jumps when I do" bug. Now a recently-expired
    window shows 0% with NO countdown (resets_at cleared → "—"); the real reset
    lands on next use. (Long-expired still drops; unparseable still kept.)
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(share-card+content): round-4 review — landscape-only, last-30 default, full numbers, >4 fix, avatar/refresh fixes, top-10 privacy toggle, neutral tz labels
    
    Share card:
    - Size selector removed — landscape 1200×680 only for now (other sizes need
      per-size tuning; deferred to a patch). Aesthetic redesign is coming separately.
    - Default range is now the last 30 days (added `last30`), not "this month".
    - New "Full numbers" toggle shows the exact token count in the hero (font
      auto-shrinks so it fits).
    - Fixed the >4-metrics bug: tiles allow up to 6 and wrap to a second row.
    - Rhythm first/last date labels now sit UNDER their bars (centred), not pinned
      to the axis ends — correct for short, centred ranges.
    - Avatar fix: httpsGet now follows redirects (GitHub avatars 302 to a CDN — not
      following them was why the avatar came back blank); + xlink:href for export.
    - Refresh no longer wipes the card: the last generated SVG + the config (range/
      scope/metrics/toggles) are remembered and rehydrated on re-render. (Same class
      of issue Carl hit with the optimizer output.)
    
    Content: the "top 10 costliest messages" panel is now its OWN opt-in
    (`showCostliestMessages`, off) — separate from the efficiency chips — because it
    displays your prompt text (privacy).
    
    Timezone: labels use canonical IANA identifiers (official/apolitical) — dropped
    the editorialised country groupings; the UTC-offset group shows only the offset.
    
    85/85 tests pass, compile clean.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(content+webview): top-10 input-interval metric, keep expanded rows on refresh, fix avatar CSP
    
    #1 Top-10: each costly turn now shows "Time since last turn" (gap to the
    previous billable turn in the same session; "New conversation" for the first),
    and both Cache-hit rate and the gap are bold. A gap past the ~5-min cache TTL is
    flagged. On real data the priciest turns pair 0-2% cache-hit with multi-hour
    gaps — i.e. the cache went cold while idle, then had to be rewritten. Now
    obvious at a glance.
    
    #2 Auto-refresh no longer collapses expanded <details data-persist> rows — open
    state is saved (vscode.setState) and restored across re-renders, so a data
    refresh doesn't interrupt reading. Switching tabs resets to default (as asked).
    
    #7 Avatar root cause: the webview CSP had no img-src, so it inherited
    default-src 'none' and blocked ALL images incl. data: URIs — the avatar <image>
    never rendered even once fetched. Added `img-src data:;` (data URIs only, still
    no external hosts). Combined with the earlier redirect-follow fix, the avatar
    should now show.
    
    85/85 tests pass, compile clean.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(ci): AI auto first-pass on every issue + PR; rename mention handle to @ccu-bot (Q4)
    
    Carl authorized auto-replies and added the API key (repo secret, third-party
    1M-context, ANTHROPIC_BASE_URL-capable). Two new workflows:
    - issue-first-pass.yml (issues: opened): posts ONE first-pass comment.
    - pr-first-pass.yml (pull_request_target: opened): posts ONE first-pass review;
      base-repo checkout only, reads the diff via API — never runs PR code.
    
    Both: labelled "🤖 Automated first-pass reply (via Claude Code)", end with a
    model-generated / a-maintainer-follows-up disclaimer, read ARCHITECTURE.md/
    CLAUDE.md/CONTRIBUTING.md and — if those are insufficient — the repo files
    (never guess), reply in the author's language. Skip bot authors; concurrency +
    timeout + max-turns. Inert until AUTOMATION_ENABLED='true'; third-party endpoint
    via ANTHROPIC_BASE_URL.
    
    Renamed the mention trigger @claude → @ccu-bot (the model may be third-party, so
    "@claude" was misleading). A2 draft-queue stays deferred until this runs stably.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(share-card): avatar + badge + GitHub name together (personalized corner)
    
    Carl: avatar and badge shouldn't be mutually exclusive, and a name adds
    personality. The top-right corner now shows the avatar circle with a two-line
    name / badge block to its left — any subset renders. New opt-in "GitHub name"
    checkbox; getGithubIdentity() fetches avatar + display name in one call (cached),
    so the name and avatar share the single read:user sign-in. Config (avatar/name)
    is persisted across refresh like the rest.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(content): detect model-switch cache flush + estimate the cache TTL (Q1)
    
    Model switch: top-10 messages now carry the previous turn's model; when the
    hit rate is low the panel names the likely cause — "model switch (Opus→Sonnet)
    flushed the cache" vs "idle Xh — cache went cold". Distinguishes the two
    cache-miss reasons Carl noticed (a 17m/1h25m gap with a low hit rate is usually
    a switch, not idle expiry).
    
    Cache-TTL estimate (Carl approved for V2.2): estimateCacheTtl() buckets
    same-model consecutive turns by idle gap and finds where the hit rate drops.
    On real data the hit rate holds ~100% to ~60 min then falls off — i.e. the
    warm window is ~1 hour here, NOT the assumed 5 min. Surfaced as a "Cache warmth"
    insight on the Content tab (opt-in via showEfficiency; aggregate only, no
    prompts): "cache stays warm ~60 min; batch complex work within that window."
    
    86/86 tests pass, compile clean.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat: @ccu-bot contributor note, data-contribution scaffold; graceful arch-doc fallback
    
    - CONTRIBUTING.md: section explaining @ccu-bot (labelled + disclaimed,
      comment-only, ask-not-guess, off unless the maintainer enables it). (Q9)
    - src/dataContribution.ts: opt-in data-contribution SCAFFOLD for future
      cross-user features (cache-TTL by tier/task, etc.). OFF by default, no
      endpoint, no-op transport; Observation type has no identifying field; tier
      redacted unless shared. +4 tests. (Q2)
    - Automation: ARCHITECTURE.md is gitignored (a private local context pack), so
      CI can't read it — the first-pass prompts now say "ARCHITECTURE.md if present"
      and fall back to CLAUDE.md + reading src/. Whether to publish a scrubbed
      technical ARCHITECTURE.md is Carl's call (see docs/ARCHITECTURE-private.md). (Q6)
    
    90/90 tests pass, compile clean.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(share-card): implement GPT "Code Pulse · Aurora Console" redesign with dual themes
    
    Executes docs/V2.2-ShareCard-GPT-design.md. One renderer, theme tokens:
    - Two themes: **Claude Cream** (default — warm/editorial) and **Aurora Dark**
      (technical/social). SHARE_CARD_THEMES token set drives bg, panels, text,
      accents, composition/rhythm colors, badge. Theme option auto|claudeCream|
      auroraDark; "auto" follows the VS Code theme (resolveShareCardTheme).
    - New composition: aurora gradient bg + soft blobs, brand block ("Claude Code
      Usage" / "AI coding usage snapshot" / range), glass stat tiles with an accent
      rail, token-mix bar (semantic colors), daily-pulse strip (peak highlighted),
      brand-signature watermark. No longer looks like a dashboard screenshot.
    - Badge redesigned as a sticker card with on-brand copy + a one-line
      explanation (BADGE_COPY: Cache Alchemist "缓存命中高,token 没白烧" etc.),
      sharing the corner with the avatar + GitHub name.
    - Defaults follow the design: hero + 4 tiles (cost/cache/model/sessions) + token
      mix + daily pulse + badge; messages/project/workflow/peak opt-in.
    - Theme selector added to the config panel (default Claude Cream), persisted.
      Palette export command + webview both theme-aware (isDark for "auto").
    - Landscape 1200×680 only (square/portrait deferred, per the brief).
    
    Privacy/self-contained constraints unchanged. Tests updated for the new look +
    theme parsing/default/auto/colors/hidden-fields. 89/89 pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * docs: publish the technical ARCHITECTURE.md (Q6 — Carl chose to publish)
    
    Un-ignored ARCHITECTURE.md + ARCHITECTURE-zh-CN.md so they're public: they're
    already technical-only (module map, data flow, exact token/cost computation,
    log-format facts, invariants, refresh, release), so nothing needed scrubbing.
    Now the @ccu-bot first-pass automation and contributors get a real technical
    map instead of re-reading src/. Maintainer product-direction stays private in
    docs/ARCHITECTURE-private.md; the public file must remain technical-only.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(share-card): add Claude Classic (orange) theme + adaptive layout fixes
    
    - New "Claude Classic (orange)" theme — the pre-redesign single-hue orange
      (monochrome orange ramp for the token mix, no violet/mint), for Carl to
      compare against the busier Claude Cream. Aurora Dark unchanged.
    - Layout: content moved up (contentTop 134); the hero now sits at a fixed
      top-left position and the full-width sections flow BELOW whichever of the
      hero / top-right corner reaches lower — so enabling the GitHub avatar no
      longer pushes the whole card down and off the canvas (the reported overflow).
      Verified: with avatar, max content y=592, watermark at 652, all within 680.
    - Token mix gets internal padding (h 64→84) so it no longer crowds the tiles
      above / pulse below; inter-section gaps clamped to [14,38] (not hollow, not
      cramped). Adapts to whichever sections are enabled.
    
    89/89 tests pass, compile clean. Theme selector now offers Cream / Classic /
    Aurora Dark / Auto.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * docs(architecture): bring the public technical map current (V2.2)
    
    - Fixed stale facts: 6→7 languages (added pt-BR); the "~5-min cache TTL" note
      corrected to the MEASURED ~60 min (estimateCacheTtl infers it from the user's
      own turns).
    - Added a "V2.2 additions" table: shareCard/shareCardSvg (dual themes),
      heatmap/heatmapSvg + GitHub publish, dateKeys, promptDedup, quotaFormat,
      dataContribution; new dataLoader methods (getCostliestMessages, estimateCacheTtl,
      buildShareInput); efficiency/cache insights; thinking-hidden; UTC-offset
      timezone; and the @ccu-bot first-pass CI (inert unless enabled).
    
    Keeps the file technical-only; product direction stays in the private companion.
    The @ccu-bot automation now reads an up-to-date map.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(share-card): default to Claude Classic (orange) theme
    
    Carl's pick — Claude Classic is now the default (dropdown first, panel/export/
    handler defaults, and resolve's light fallback); Cream + Aurora Dark + Auto stay
    available. Tests updated.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * chore(v2.2): settings i18n for new toggles (7 langs), resume tooltip de/ja/ko/pt, what's-new + CHANGELOG
    
    Pre-release polish so V2.2 is release-ready:
    - SETTINGS_I18N: added the 5 new opt-in toggles (showHeatmap, showEfficiency,
      showCostliestMessages, enableShareCard, enableSessionDelete) in de-DE / zh-TW /
      zh-CN / ja / ko / pt-BR, and refreshed the timezone help (now UTC-offset).
    - Resume-session tooltip: the fuller "reopens in Claude Code / claude --resume"
      explanation now in de/ja/ko/pt too (en/zh already done).
    - What's-new toast copy updated for the real V2.2 (share card, GitHub heatmap
      publish, efficiency + cache insights).
    - CHANGELOG [2.2.0]: added share card (themes), heatmap publish, top-10
      costliest MESSAGES (cost split / cache-miss / interval / model-switch), cache
      warmth, efficiency chips, session-delete opt-in, UTC-offset timezone, and the
      thinking-hidden / quota-format / refresh-persist / avatar-CSP fixes.
    
    89/89 tests pass, compile clean.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(share-card): localize the card to the UI language (no en/zh mixing)
    
    Carl: the card was English-only, and the badge line was Chinese even on an
    English card. Now the whole card (subtitle, hero unit, tile labels, token-mix
    legend, pulse, watermark, and the badge title + line) renders in the UI language.
    Fully localized for en / zh-CN / zh-TW (the maintainer's languages); any other UI
    language falls back to English — so a card never mixes languages. Card strings +
    per-language BADGE_COPY live in shareCardSvg.ts (self-contained + tested); the
    webview/export pass I18n.getLocale(). Badge line width widened so English lines
    aren't clipped.
    
    90/90 tests pass. de/ja/ko/pt card localization = a follow-up (they fall back to
    en for now, consistently).
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix(settings): heatmap toggle references the actual "All" tab name per language
    
    Carl: the token-heatmap toggle said "全部标签" (unclear), not the real tab name.
    Now the parenthetical matches each language's All-time tab label — zh-CN
    "("所有"选项卡)", zh-TW "(「所有」分頁)", ja "(「すべて」タブ)", de/pt use their
    tab labels; en "(All-time tab)".
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(share-card): Chinese cards use 万/亿 units + hero keeps one decimal
    
    Carl: on a zh-CN card the token unit should read in 万 / 亿 (万 / 億 for zh-TW),
    not M/K — and the hero total should always show one decimal (e.g. "5.1亿",
    "5.0B"). compact() is now language-aware (万/亿 for Chinese) with a keepDecimal
    flag the hero uses; tiles, composition amounts and the pulse peak follow the
    card language too.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(analysis): cache-churn cost data layer (缓存损耗账单) — first V2.2 analysis
    
    estimateCacheChurnCost(): the $ spent RE-writing cache that a warm cache would
    have served cheaply, split by the two AVOIDABLE causes — a model switch (per-
    model cache flush) and an idle gap past the TTL (~60 min). Only counts a rewrite
    of a cache that existed on the previous same-session turn (read≈0, write>0), so a
    genuine big-new-context isn't blamed. Waste ≈ cacheCreation × (writeRate −
    readRate) per model, via getModelRatesPerMillion.
    
    IMPORTANT framing (per Carl): a switch can still be net-worth-it if the other
    model is cheaper per token — this is the churn cost, not "never switch". On real
    data (30d): ~$240, mostly from idle gaps (71×) not switches (5×) — so momentum
    within the warm window matters more than avoiding switches here.
    
    Data layer + 2 tests now; the styled Content-tab section + model-fit (C5) land
    next (with frontend-design). 93/93 pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix(ci): add id-token: write to first-pass workflows (sync #58 to V2.2 branch)
    
    * feat(content): "Experimental insights" section — cache-churn bill (first card)
    
    The V2.2 analysis workstream, styled to the plugin's card language (theme vars,
    consistent with the costly-messages / cache-warmth panels) with a small
    "estimate" tag as the honest signature.
    
    - New `showInsights` setting (Optional features, default OFF) — these are our own
      heuristics, not standardized metrics, so opt-in + labelled.
    - Content tab gains an "Experimental insights" section. First card: the
      **cache-churn bill** — headline $ (last 30 days) spent re-writing cache a warm
      cache would have served cheaply, split into idle-gap vs model-switch pills, with
      the honest note that a switch can still be worth it (this is only the churn
      cost). Built on estimateCacheChurnCost; aggregate only, no prompts.
    
    C5 model right-sizing (next card) + the other insights come next.
    showInsights settings i18n (7 langs) folded into the pre-release i18n pass.
    93/93 tests pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * polish(content): insight card — separate the caveat onto its own line + crisper copy
    
    The cache-churn card read as a wall of text. Split it: a "💡" actionable
    takeaway line (recoverable — keep momentum in the warm window), then the "a
    switch can still be worth it" caveat as a smaller, top-bordered note on its own
    line. Pills clarified ($ · cause · count). Reads as an insight now, not a
    paragraph.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * chore(ci): sync controlled-API first-pass bot to V2.2 branch (matches #64)
    
    * feat(content): cache-hit-rate-by-model insight + weekly throttle for cache analyses
    
    Second insight card (Carl's top pick — cache is the key cost lever): cache hit
    rate per model, with the model family's nominal provider and a volume bar.
    cacheStatsByModel() aggregates read ÷ input-side per model over 30 days. Real
    data shows opus-4-8 97% / deepseek-v4-pro 98% / fable 96% etc. — so you can see
    which models actually serve from cache. Tip: favour low-hit models for short,
    self-contained tasks. (True cross-PROVIDER comparison needs pooled cross-user
    data — reserved via the dataContribution scaffold.)
    
    Also: the cache analyses (TTL / churn / by-model) now recompute at most WEEKLY
    (analysisCache), not every render — Carl's call; they move slowly.
    
    93/93 tests pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(content): cache card shows per-model warm window (TTL), not just hit rate
    
    Carl's call: the durable, cross-user-comparable signal is how long each model's
    cache actually stays warm — and it drifts over time — so make TTL the primary
    metric. cacheStatsByModel() now also buckets same-model idle gaps per model and
    infers a warm window; hit rate + volume ride along as secondary.
    
    Real data is telling: DeepSeek-v4-pro stays warm ~240 min, Opus 4.8 ~60 min,
    Fable 5 only ~2 min (bursty, rarely resumed after a gap). That per-model spread
    is exactly what you can't see from a single global number.
    
    Also fixes the bar/number ambiguity Carl flagged: the bar AND the bold number
    are now the same metric (TTL); "—" shown when a model has too few gaps to
    estimate. Hit% + token volume moved to a muted sub-line.
    
    93/93 tests pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(bot): two-tier first-pass with controlled repo-file escalation + skimmable template
    
    When the cheap model (CCU_BOT_MODEL, default deepseek-v4-flash) says it can't
    answer from the docs alone, escalate to a stronger model (CCU_BOT_MODEL_PRO,
    default deepseek-v4-pro) with thinking on, and let it NAME a few repo source
    files. The SCRIPT reads them — repo-relative text files only, no "..", size-
    capped, must resolve inside the repo root — so there's still no agent tool and
    no way for a malicious issue to make it read or run anything arbitrary. If it
    still can't answer, its reply asks for the specific missing info/logs and
    suggests the issue template.
    
    Also gives every reply a skim-friendly shape: TL;DR/结论 first, then analysis,
    then suggested next steps. Thinking param is best-effort (retries without it if
    the endpoint rejects it), so it stays portable across third-party endpoints.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(sessions): read-only conversation viewer (opt-in) — re-read a session without spending context
    
    Carl's use case: after /clear or /compact he wants to RE-READ his prompts and
    the model's answers to jog his memory, but resume (`claude --resume`) reloads
    the whole session INTO context and costs tokens. This viewer is the zero-context
    path — it just reads the session .jsonl and shows it.
    
    - conversationLog.ts: pure, tested parser (.jsonl text -> ordered display turns).
      Keeps prompts + assistant text front and centre; carries thinking / tool_use /
      tool_result too. Skips meta + sidechain lines, dedupes by uuid, truncates per
      turn, supports "last N turns". 7 unit tests.
    - conversationViewerHtml.ts: frontend design per Carl's ask — user PROMPTS are
      the star (accent rail + tint + a top "jump to your prompts" nav), model TEXT
      is a readable card, thinking / tool traffic is present but quiet (collapsed
      <details>, muted). No scripts (webview enableScripts:false); VS Code theme vars
      only; a read-only badge makes the zero-context promise explicit.
    - webview.ts: an eye view action on Sessions rows (gated by the new setting) ->
      viewConversation message -> openConversationViewer() reads the file and opens a
      panel. settings.ts: showConversationViewer (features, default OFF).
    - i18n: viewConversation button tooltip in all 7 languages. (Viewer panel chrome
      is English-first like the other experimental surfaces; folded into the
      pre-release i18n pass.)
    
    100/100 tests pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(viewer): chat-mode conversation viewer — rendered Markdown, filled answers, default-hidden tools
    
    Round of viewer feedback from Carl:
    - Model answers now render Markdown (new dependency-free miniMarkdown.ts, 8
      tests) instead of showing raw source — much better to read inside the panel.
    - Assistant answers get their OWN filled card (was plain), so they stand apart
      from both prompts (accent) and the muted tool traffic.
    - Default is a clean CHAT view: thinking and tool activity are HIDDEN behind two
      pure-CSS toggles (checkbox hack, no scripts) — on open you see only prompts +
      answers.
    - Opens on the last ~10 rounds; earlier rounds collapse into a <details>.
    - Prompt nav items are now expandable to the full prompt text, each with a
      "jump ↓" link.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(sessions): add "Active" column — idle-capped hands-on time
    
    The Duration column is the first→last wall-clock span, which is misleading for
    long-lived sessions (one real session spans 957h but only ~12.5h was hands-on).
    The new Active column sums the gaps between turns with each idle gap capped at
    5 min (activeDurationBySession), so it reflects time actually spent. Sortable,
    with a tooltip explaining the estimate; labelled in all 7 languages.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix(ci): don't auto-review maintainer PRs; treat an empty model reply as a no-op
    
    Two first-pass bot fixes (also going to main via PR):
    - The PR first-pass now SKIPS pull requests authored by OWNER / MEMBER /
      COLLABORATOR. A maintainer's own finished PR doesn't need an auto first-pass
      (that review is for external contributors) — and #66 showed it firing on our
      own PR and failing on the big self-referential diff.
    - An empty model reply is now a soft no-op (exit 0) instead of a hard failure,
      so a benign blank response doesn't leave a red ✗ check.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(viewer): interim-answer toggle, Markdown tables, visible jump + latest marker
    
    More viewer feedback from Carl:
    - Assistant answers that aren't the round's FINAL output are marked "interim"
      and can be toggled off (default ON — intermediate results have value); the
      final answer of each round always stays.
    - Markdown tables now render (added GFM table support to miniMarkdown + 2 tests).
    - Prompt-nav jump link no longer clipped on long prompts — it sits outside the
      truncating text (flex), always visible; the caret still expands full text.
    - The most recent prompt gets a "latest" badge in the nav for quick jumping.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(sessions,insights): active-time tuning, merge session mutating actions, C5 right-sizing
    
    One round of Carl's feedback on sessions + insights:
    
    - Active column: idle-gap cap raised 5m → 90m (reading/reviewing a diff is real
      work the log doesn't capture; the old cap badly under-counted). Column moved
      BEFORE Duration; header + cells carry the estimate tooltip. Help text updated
      in all 7 languages.
    - Resume + Delete now share ONE opt-in (enableSessionActions, default off):
      both ACT on the user's Claude Code (reopen / trash a log), at odds with the
      extension being read-only, so they hide together. The read-only conversation
      viewer flips to default ON (showConversationViewer) — it only reads local logs.
    - C5 "Premium models on lightweight turns": the compute premium spent running a
      top-tier model (output ≥ $20/M) on small-output turns (≤800 out — the
      translation / quick-edit signature), vs Haiku-4.5 rates. Surfaces a per-switch
      churn cost so it says "batch simple tasks on the cheap model", not "flip every
      turn". Real data: ~$19.74 over 2339 turns, mostly Opus. Weekly-cached.
    
    110/110 tests pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * refactor(insights,viewer): defer C5 card; cap prompt-nav to the last 10
    
    - C5 "premium models on lightweight turns" is no longer rendered. Output size is
      a weak proxy for task difficulty, and the advice ("use a cheaper model for
      simple tasks") isn't something users lack — in practice they stay on the top
      model and tack simple work onto long tasks. A worthwhile version needs a real
      difficulty judgement (sampling prompt text via the opt-in AI-advice API, which
      must be clearly labelled). modelRightsizing() stays as dormant scaffolding.
    - Viewer prompt-nav is capped to the last 10 prompts (matching the recent rounds
      shown) so the list is a consistent length and every jump lands in expanded
      content; a note flags any earlier prompts folded into "Show earlier".
    
    110/110 tests pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix(viewer): cap by rounds, not raw turns — long sessions now show 10+ prompts
    
    Bug (Carl): a long session with 79 prompts showed only the latest ~3. Cause: the
    viewer capped at the last 500 RAW turns, but one prompt is followed by dozens of
    tool turns, so 500 turns held only ~4 prompts.
    
    Fix: parseConversation now caps by ROUNDS (a round = a prompt + its replies) via
    maxRounds, with a raw-turn ceiling as a safety net. The viewer keeps the last 15
    rounds (10 shown + a small "earlier" buffer). Parser also reports totalRounds;
    the header now reads "N prompts total · … · showing last 15 of N rounds".
    Verified on the real 79-prompt / 6798-turn session: nav shows the last 10
    prompts, latest badge on the newest, ~0.6 MB html.
    
    111/111 tests pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(insights): "Big one-shot turns" card — nudge toward more checkpoints
    
    Next insights-roadmap card (session-health), implementing the checkpoint habit
    Carl wanted surfaced: sessionHealth() measures how much of your output came from
    a few very large single responses (≥4k output tokens — a big one-shot generation
    with no human checkpoint mid-way). Real data: ~39% of output over 321 jumbo
    turns (largest ≈50k). The card frames it as a gentle nudge (smaller checkpoints
    = cheaper/faster review, catch a wrong direction early), not a verdict — a big
    single turn is sometimes exactly right. Weekly-cached, opt-in (showInsights).
    
    111/111 tests pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat: viewer refreshes one reusable panel; new "Your active hours" insight
    
    Two items from Carl's feedback:
    
    - Conversation viewer now (re)uses a SINGLE panel: each "view" click re-reads
      the session .jsonl fresh and refreshes that panel (revealing it), instead of
      piling up a new tab per click. An ongoing session shows its latest turns.
    
    - New insights card "Your active hours": activeHours() buckets non-cache work
      (input+output tokens) by hour-of-day in the user's timezone, with a 24-hour
      sparkline and the busiest contiguous 4-hour window + its share. Real data:
      peak 15:00–19:00, 35% of work. Tip ties it to protecting the peak window and
      keeping momentum in one warm session there. Weekly-cached, opt-in.
    
    111/111 tests pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(insights): "Skill ROI" card — cost vs output per skill/plugin
    
    Next roadmap card. skillRoi() uses the authoritative _skill/_plugin attribution
    Claude Code ≥2.1 stamps on usage lines: per skill, the cost spent while it was
    active and the output it returned, with outPerUsd (output tokens per $) as the
    ROI angle. Real data separates lean skills (lit-review ~15k tok/$, paper-plotting
    ~13.5k) from context-heavy ones (claude-api ~1.9k, code-review ~2.1k) — so you
    can see which skills burn context for little output. Bar/number = cost; note
    flags it's a proxy (cost attributed to the active skill, output isn't "value").
    Weekly-cached, opt-in. (Budget-pacing card skipped for V2.2 per Carl.)
    
    111/111 tests pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix(insights): Skill ROI shows output-tokens-per-$ as the bar AND number
    
    Carl: the right-hand figure was a bare dollar amount, unclear as "ROI" and not
    matching the bar. Now the bar and the number are the SAME metric — output tokens
    returned per $ (with a "/$" unit) — sorted by it so the bars rank; cost + turns
    move to the muted sub-line.
    
    * feat(settings): live-refresh delay dropdown (0/1/2/5/10/20/30s) + settings i18n sync
    
    - Replaces the fileWatching on/off toggle with a discrete "Live refresh delay"
      choice: Off / 1 / 2 / 5 / 10 / 20 / 30s (fileWatchSeconds, default 2s ≈ old
      1.5s). The fs watcher uses it as the debounce; Off stops watching. Help makes
      clear this only re-reads LOCAL log files — no API call; the /usage quota fetch
      is throttled separately, so a short delay doesn't hammer the official API.
    - Settings i18n sync (Carl's release check): localized the setting label/help in
      all 6 non-English locales for fileWatchSeconds, plus showInsights and
      showConversationViewer (previously English-only), and renamed the
      enableSessionDelete labels to enableSessionActions to match the merged setting.
    
    111/111 tests pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix(viewer,charts): cache-write bars were invisible; viewer "show earlier" was confusing
    
    - Cache-write ("input cache miss") bars rendered transparent in every usage bar
      chart. Cause: .cache-creation-bar's gradient referenced var(--vscode-charts-pink),
      which VS Code doesn't define — an invalid color makes the whole gradient (and
      thus the background) invalid, so only the axis + value labels showed. Added a
      pink fallback so the gradient is valid.
    - Conversation viewer: dropped the "Show earlier conversation (N rounds)" collapse.
      It was confusing — the top prompt-nav didn't reflect it, so you couldn't tell
      whether the earlier prompts were shown, and toggling it only changed the body.
      Now every loaded round renders flat and the nav lists every loaded prompt (all
      jump targets exist). Default load is the last 10 rounds ("showing last 10 of N").
    
    111/111 tests pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * docs(release): V2.2 CHANGELOG + What's New; drop unused @types/glob
    
    - CHANGELOG [2.2.0]: added the conversation viewer, Experimental insights suite
      (cache-churn / warmth-by-model / big one-shot / active hours / skill ROI),
      Sessions "Active" column, live-refresh delay control, Chinese share-card units,
      the enableSessionActions merge + timezone-aware bucketing (Changed), the
      cache-write invisible-bars fix (Fixed), and the @types/glob removal (Removed).
    - Refreshed the in-extension "What's New" 2.2 blurb to match.
    - Removed the unused @types/glob devDependency (folds in #63, thanks @zeyutang).
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * docs(architecture): add v2.2 modules + Experimental-insights methods
    
    ARCHITECTURE.md module table now lists sessionResume.ts, conversationLog.ts,
    conversationViewerHtml.ts and miniMarkdown.ts, and the data-layer notes cover the
    new insight methods (estimateCacheChurnCost, cacheStatsByModel, sessionHealth,
    activeHours, skillRoi, activeDurationBySession, modelRightsizing).
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix: timezone bucketing and cache-write cost accuracy (#62)
    
    * fix: timezone bucketing and cache-write cost accuracy
    
    * bucket Today/month/daily/hourly totals by the configured IANA zone
    * keep the loader zone in lockstep with display; recompute on change
    * split cache writes into 1h (2x) vs 5m (1.25x) when the log has the ttl
    * add tests for zone bucketing and the cache-write split
    
    * i18n: note timezone sets the daily cost boundary
    
    * add the day-boundary clause to the timezone help in all six locales
    * update the timezone description in README and the locale editions
    
    * fix: changelog minor touch-up
    
    * Maintainer edit: keep the cache-write TTL pricing; drop the timezone changes
    
    The timezone-bucketing half overlaps with the shared zone-aware day-key rework
    landing in V2.2, so this reduces the PR to just the cache-write TTL pricing
    (pricing.ts + types.ts + pricing.test.ts) to merge cleanly. zeyutang's original
    commits are preserved; the timezone work is welcome as a follow-up PR.
    
    * Remove stray sample-card SVGs accidentally swept into the maintainer edit
    
    ---------
    
    Co-authored-by: Carl <74130028+Carl723000@users.noreply.github.com>
    
    * docs(changelog): credit #62 cache-write TTL pricing (@zeyutang)
    
    * chore(release): bullet the 2.2 "What's New"; let #63 own the @types/glob removal
    
    - What's New for 2.2 is now newline bullets (• per feature) instead of one dense
      paragraph, so the toast is scannable. Copy unchanged (Carl approved it).
    - Restore @types/glob locally: #62-style, the removal now traces solely to
      zeyutang's merged #63 rather than a duplicate local edit. It's a devDependency
      (never packaged), so the vsix is unaffected; the merge to main drops it.
    
    ---------
    
    Co-authored-by: Claude <noreply@anthropic.com>
    Co-authored-by: Zeyu Tang <tang@zeyu.one>
    3 people authored Jul 6, 2026
    Configuration menu
    Copy the full SHA
    3badd1c View commit details
    Browse the repository at this point in the history
  2. fix: refresh status bar when a window regains focus (#55) (#69)

    Each VS Code window is a separate extension host, and Electron throttles both
    timers and fs.watch delivery in unfocused/hidden windows — so with several
    windows open, only the one you last worked in keeps its status bar current;
    the others lag or stop updating. Now, when a window regains focus, we force an
    immediate refresh and re-arm the timer + file watcher, so a background window
    catches up at once instead of after the next (throttled) tick — or never.
    Carl723000 authored Jul 6, 2026
    Configuration menu
    Copy the full SHA
    0b4b750 View commit details
    Browse the repository at this point in the history
Loading