Skip to content

feat(desktop): show design usage totals by day and week - #460

Merged
Sun-sunshine06 merged 5 commits into
OpenCoworkAI:mainfrom
wudilyy999:feat/usage-budget
Oct 4, 2026
Merged

Sun-sunshine06 merged 5 commits into
OpenCoworkAI:mainfrom
wudilyy999:feat/usage-budget

Conversation

@wudilyy999

@wudilyy999 wudilyy999 commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The sidebar now shows recorded token and USD totals for the current design: the design lifetime, local today, and the Monday-start local week. This is the weekly slice of the README Later item "Cost transparency". There is no separate issue. Totals come from usage already stored on settled run-journal responses. This does not add a price table, a pre-generation estimate, a budget cap, or a new database.

Cancelled runs that include a provider response are counted. Failed runs without a response are not. Invalid usage numbers are treated as zero.

The sidebar refetches those journal totals when a run settles. A cancellation that records a provider response updates the totals even though lastUsage does not change. The same design also refetches at the next local midnight, so Today and the Monday-start week move while it stays open, and again when the window is focused or shown. A response that arrives after cleanup, or after a newer read, is ignored.

The pure totals, formatting, and local-midnight helper live in @open-codesign/shared. Desktop main and the renderer both import that package. The renderer no longer imports src/main, and the web TypeScript project no longer includes a main-process file.

An earlier commit on this branch changed the macOS browser test harness. That change is reverted in e2822c9 and is not part of this PR. The same harness fix remains local on this machine and on unmerged #458.

Type of change

  • New feature
  • Bug fix
  • Refactor (no behavior change)
  • Documentation
  • Build / CI / tooling
  • Breaking change

Linked issue

No linked issue. README Later item: Cost transparency, weekly budget slice only.

Checklist

  • I checked the linked issue / relevant context before starting
  • pnpm lint && pnpm typecheck && pnpm test passes locally
  • Added/updated tests for the change
  • Added a changeset (pnpm changeset) if user-visible
  • Updated docs if behavior changed

Dependency additions (if any)

None.

Screenshots / recordings (UI changes)

Not attached. The new text sits under the existing per-run token line in the sidebar.

Checks

be0c0b7 passed local pre-push: typecheck, Biome (674 files), and the full test suite. Desktop: 175 files, 2583 tests passed. Shared: 20 files, 313 tests passed. The net diff against main remains the usage change only.

Copilot AI balanced review requested due to automatic review settings October 3, 2026 11:02
@github-actions github-actions Bot added docs Documentation area:desktop apps/desktop (Electron shell, renderer) labels Oct 3, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Findings

  • [Minor] Renderer imports runtime helper code from the main process — apps/desktop/src/renderer/src/components/Sidebar.tsx:4 pulls formatUsageCost/formatUsageTokens from ../../../main/usage-budget, and apps/desktop/tsconfig.web.json:3 had to add src/main/usage-budget.ts to the renderer TS project so it typechecks. The module is pure today, so it bundles, but a renderer → src/main/** runtime import crosses the process boundary and makes it easy to later pull Electron-only main code into the renderer bundle.
    Suggested fix: move the shared, pure pieces (UsageTotals, summarizeUsageBudget, formatUsageTokens, formatUsageCost) into packages/shared, import them from both processes, and revert the tsconfig.web.json include.

  • [Nit] Locale-independent number formatting in a multi-locale app — apps/desktop/src/main/usage-budget.ts:60 hardcodes new Intl.NumberFormat('en-US', …), so the sidebar always shows comma grouping even under es / pt-BR / zh-CN.
    Suggested fix: pass the active locale (e.g. getCurrentLocale() from @open-codesign/i18n) or use Intl.NumberFormat(undefined, { maximumFractionDigits: 0 }).

Questions

  • None.

Summary

Review mode: initial

  • No blockers or majors found. The feature is self-contained and truthful: totals are derived only from settled journal responses (apps/desktop/src/main/run-journal.ts:206), invalid usage numbers degrade to 0 for a display-only value (acceptable non-critical path), the IPC handler validates schemaVersion/designId and is read-only (apps/desktop/src/main/ipc/generate.ts:513), and failures surface as an error toast with the usage line hidden rather than showing stale or wrong totals (Sidebar.tsx:174).
  • Tests for the pure summarizer/formatter (apps/desktop/src/main/usage-budget.test.ts) and the journal reopen path (apps/desktop/src/main/run-journal.test.ts:329) are solid and timezone-independent. The IPC handler and the sidebar rendering are not directly covered (see Testing).
  • Residual risk: this PR also changes apps/desktop/vitest.config.ts:5 and three *.browser.test.ts helpers for the author's local macOS host. Those are unrelated to the feature; the worker cap is a no-op on Linux CI (process.platform === 'linux' keeps the default), and the browser-test edits only change how text is selected, so no CI regression is expected. The PR notes a conflict with unmerged #458 on those files — coordinate merge order.

Testing

  • Not run (automation).
  • Suggested: add a Vitest covering the new codesign:v1:usage-budget handler (bad schemaVersion/designId → CodesignError IPC_BAD_INPUT; journal === null → zeroed schemaVersion: 1 payload) and a renderer test asserting the sidebar shows the design/today/week line and hides it when the IPC rejects.

Open-CoDesign Bot

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Usage totals can remain stale after cancelled responses and local day or week rollover.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)
What changed in this PR

Adds recorded usage totals for the current design, using existing run-journal responses without new pricing data or storage.

Changes:

  • Displays lifetime, local-day, and Monday-start weekly token and USD totals.
  • Adds localized labels, usage aggregation, and journal replay coverage.
  • Makes browser input replacement portable and limits non-Linux test workers.
File Description
packages/​i18n/​src/​locales/​zh-CN.json Adds Chinese usage labels.
packages/​i18n/​src/​locales/​pt-BR.json Adds Brazilian Portuguese usage labels.
packages/​i18n/​src/​locales/​es.json Adds Spanish usage labels.
packages/​i18n/​src/​locales/​en.json Adds English usage labels.
apps/​desktop/​vitest.config.ts Limits non-Linux test workers.
apps/​desktop/​tsconfig.web.json Includes usage helpers in renderer typechecking.
apps/​desktop/​src/​renderer/​src/​components/​TweakPanel.browser.test.ts Uses native input selection.
apps/​desktop/​src/​renderer/​src/​components/​SourceEditPanel.browser.test.ts Uses native textarea selection.
apps/​desktop/​src/​renderer/​src/​components/​Sidebar.tsx Fetches and displays usage totals.
apps/​desktop/​src/​renderer/​src/​components/​chat/​PromptInput.browser.test.ts Makes text selection portable.
apps/​desktop/​src/​preload/​index.ts Exposes the typed usage API.
apps/​desktop/​src/​main/​usage-budget.ts Aggregates and formats usage.
apps/​desktop/​src/​main/​usage-budget.test.ts Tests usage windows and formatting.
apps/​desktop/​src/​main/​run-journal.ts Extracts settled response usage.
apps/​desktop/​src/​main/​run-journal.test.ts Tests usage recovery after reopening.
apps/​desktop/​src/​main/​ipc/​generate.ts Registers the usage totals handler.
.changeset/​usage-budget.md Records the feature release.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

config?.hasKey && config.modelPrimary ? config.modelPrimary : t('sidebar.chat.noModel');
const lastTokens = lastUsage ? lastUsage.inputTokens + lastUsage.outputTokens : null;

// lastUsage is the signal that a run finished recording provider usage.
return () => {
active = false;
};
}, [currentDesignId, lastUsage, pushToast, t]);

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Findings

  • [Nit] PR description no longer matches the current diff for the Vitest worker cap. The PR body says "caps non-Linux Vitest workers at 2", but apps/desktop/vitest.config.ts:5 now reads maxWorkers: process.platform === 'win32' ? 2 : undefined — it caps Windows only and leaves macOS uncapped. The same paragraph ties that harness change to "this Mac", so the description now misdescribes what is actually shipped.
    Suggested fix: update the PR body to state the Windows-only worker cap (and describe the macOS browser-test selection change on its own), or restore the macOS cap if that was the intent.

Questions

  • Usage totals are refetched on lastUsage in the sidebar effect deps (apps/desktop/src/renderer/src/components/Sidebar.tsx:183). The description says cancelled runs that carry a provider response are counted in the journal totals. Does a cancelled run update lastUsage? If it does not, the totals will be right on disk but the sidebar line will not refresh until the next completed run or a design switch.
  • The three browser-test helpers now select with page.keyboard.down('Control') + A (e.g. apps/desktop/src/renderer/src/components/SourceEditPanel.browser.test.ts:397). On macOS, select-all is normally Meta+A, and Control+A can instead move to line start in Chrome/Cocoa text fields. Can you confirm these still pass on your macOS host, or make the modifier platform-aware?

Summary

Review mode: follow-up after new commits

  • No blockers or majors. The feature path is unchanged from the prior revision and remains truthful: totals derive only from settled journal responses (apps/desktop/src/main/run-journal.ts:197), non-finite/negative numbers degrade to 0 (display-only, acceptable), the IPC handler validates schemaVersion/designId and is read-only (apps/desktop/src/main/ipc/generate.ts:514), and an IPC failure hides the line and raises an error toast rather than showing stale totals.
  • The new commits since the last review only touch test harness/config plus a merge; nothing in the feature code changed, so the earlier analysis still holds.
  • Residual (unchanged from the prior review, not re-filed as findings): (1) the renderer still imports formatUsageCost/formatUsageTokens from ../../../main/usage-budget (apps/desktop/src/renderer/src/components/Sidebar.tsx:4) and apps/desktop/tsconfig.web.json still adds src/main/usage-budget.ts to the web project — moving the pure helpers to packages/shared would keep the process boundary clean; (2) formatUsageTokens still hardcodes Intl.NumberFormat('en-US', …) (apps/desktop/src/main/usage-budget.ts:60), so grouping stays en-US under es/pt-BR/zh-CN.
  • Residual risk: the browser-test edits and apps/desktop/vitest.config.ts change are unrelated to the feature; the PR notes a conflict with unmerged #458 on those files — coordinate merge order.

Testing

  • Not run (automation).
  • Suggested: add a Vitest for the new codesign:v1:usage-budget handler (bad schemaVersion/designId → CodesignError IPC_BAD_INPUT; journal === null → zeroed schemaVersion: 1 payload) and a renderer test asserting the design/today/week line renders and hides when the IPC rejects.

Open-CoDesign Bot

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Findings

  • [Nit] The PR description is out of date relative to the current revision and omits the screenshot the template requires. The body says "Head is now e2822c9", but the branch head is 094eb98 (the useDesignUsageBudget extraction landed after that), and the UI section still says screenshots are "Not attached" even though .github/PULL_REQUEST_TEMPLATE.md marks screenshots as required for any visual change. apps/desktop/src/renderer/src/components/Sidebar.tsx:322 adds visible sidebar text.
    Suggested fix: refresh the description (or drop the hard-coded commit pins) and attach a screenshot of the new usage line; no code change needed.

Summary

Review mode: follow-up after new commits

  • No blockers or majors. The prior review's open items are resolved: the description no longer claims a non-Linux Vitest worker cap, and the "a cancelled run may not change lastUsage" gap is now covered by subscribing to settledGenerationIds (apps/desktop/src/renderer/src/components/usage-budget-refresh.ts:15), with a test that pins that behavior (apps/desktop/src/renderer/src/components/usage-budget-refresh.test.tsx).
  • The extraction into useDesignUsageBudget keeps the truthful-state contract: a failed read clears the line and raises one error toast per distinct message (reportedError dedupe), a stale in-flight response is dropped via the request counter and active flag, and a successful refresh never blanks the line. Midnight re-arming uses local time via nextLocalMidnight, so DST-shifted boundaries are handled.
  • nextLocalMidnight is unit-tested alongside the window math (apps/desktop/src/main/usage-budget.test.ts).
  • Residual (unchanged from the prior review, not re-filed as findings): (1) the renderer imports pure helpers from ../../../main/usage-budget in both Sidebar.tsx:4 and usage-budget-refresh.ts:2, and apps/desktop/tsconfig.web.json:3 adds src/main/usage-budget.ts to the web project — moving the pure helpers to packages/shared would keep the process boundary clean; (2) formatUsageTokens hardcodes Intl.NumberFormat('en-US', …) (apps/desktop/src/main/usage-budget.ts:65), so digit grouping stays en-US under es/pt-BR/zh-CN.
  • Residual risk: the cancel-refresh path depends on the store actually adding an entry to settledGenerationIds when a cancelled run settles; this PR's test models that store behavior but cannot verify the store itself. Worth a quick manual check if not already confirmed.

Testing

  • Not run (automation).
  • Covered by new tests: usage-budget.test.ts (summary windows, formatting, nextLocalMidnight), run-journal.test.ts (usage recorded across reopen), usage-budget-refresh.test.tsx (cancel refresh, midnight/week boundary, focus/visibility, stale-response drop).
  • Still uncovered: the codesign:v1:usage-budget handler itself (apps/desktop/src/main/ipc/generate.ts:514) — invalid schemaVersion/designId → CodesignError('IPC_BAD_INPUT'), and journal === null → zeroed schemaVersion: 1 payload. A small handler-level test would close that gap.

Open-CoDesign Bot

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Findings

No new findings. The diff since the last review only relocates the pure usage helpers into packages/shared and updates the changeset; no correctness, security, or project-constraint issue is introduced by that move.

Summary

Review mode: follow-up after new commits

  • The prior review's remaining residual observation is resolved: the shared usage math now lives in packages/shared/src/usage-budget.ts and is re-exported from packages/shared/src/index.ts:629, so the renderer no longer crosses the main/renderer process boundary (apps/desktop/src/renderer/src/components/Sidebar.tsx:1, apps/desktop/src/renderer/src/components/usage-budget-refresh.ts:1), and apps/desktop/tsconfig.web.json no longer includes src/main/usage-budget.ts.
  • .changeset/usage-budget.md:3 now bumps @open-codesign/shared alongside desktop and i18n, matching the new public exports.
  • The moved code stays pure — no new dependencies, no direct provider SDK imports — and the new IPC handler validates its input (apps/desktop/src/main/ipc/generate.ts:514).
  • Residual (unchanged, not re-filed): formatUsageTokens still hardcodes Intl.NumberFormat('en-US', …) in packages/shared/src/usage-budget.ts, so thousands grouping stays en-US under es/pt-BR/zh-CN; and the codesign:v1:usage-budget handler still has no handler-level test (invalid schemaVersion/designId → IPC_BAD_INPUT, journal === null → zeroed schemaVersion: 1 payload).
  • Residual risk: the cancel-refresh path depends on the store adding an entry to settledGenerationIds when a cancelled run settles (apps/desktop/src/renderer/src/components/usage-budget-refresh.ts:15); this PR's test models that store behavior but cannot verify the store itself. A quick manual check is worth it.
  • Non-blocking, previously noted and not re-filed: the PR description still omits the screenshot the template requires for a visual change and references 094eb98 for the local pre-push run while the branch head is be0c0b72.

Testing

  • Not run (automation).
  • Covered by new/moved tests: packages/shared/src/usage-budget.test.ts (window math, formatting, nextLocalMidnight), apps/desktop/src/main/run-journal.test.ts (usage recorded across a journal reopen), apps/desktop/src/renderer/src/components/usage-budget-refresh.test.tsx (cancel refresh, midnight/week boundary, focus/visibility, stale-response drop).
  • Still uncovered: the codesign:v1:usage-budget IPC handler itself (see residual above).

Open-CoDesign Bot

@Sun-sunshine06
Sun-sunshine06 merged commit 09f21c3 into OpenCoworkAI:main Oct 4, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:desktop apps/desktop (Electron shell, renderer) docs Documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants