diff --git a/apps/mobile/src/features/usage/usageProviders.ts b/apps/mobile/src/features/usage/usageProviders.ts index 2576ac21fb07..a9f95921ac3b 100644 --- a/apps/mobile/src/features/usage/usageProviders.ts +++ b/apps/mobile/src/features/usage/usageProviders.ts @@ -5,12 +5,13 @@ import { useAppearancePreferences } from "../settings/appearance/AppearancePrefe * Series and table order. The chart stacks providers from the bottom in this * order, so it also fixes which band sits on top of the bars. */ -export const PROVIDER_ORDER: readonly UsageProviderKind[] = ["codex", "claude", "grok"]; +export const PROVIDER_ORDER: readonly UsageProviderKind[] = ["codex", "claude", "grok", "opencode"]; export const PROVIDER_LABEL: Record = { claude: "Claude Code", codex: "Codex", grok: "Grok Build", + opencode: "OpenCode", }; /** @@ -23,5 +24,6 @@ export function useProviderColors(): Record { claude: "#d97757", codex: scheme === "dark" ? "#e6e6e6" : "#3c3c43", grok: scheme === "dark" ? "#a1a1aa" : "#52525b", + opencode: "#8b5cf6", }; } diff --git a/apps/web/src/components/usage/UsageProviderChart.test.ts b/apps/web/src/components/usage/UsageProviderChart.test.ts index a4114cfdfb57..9b61e918a523 100644 --- a/apps/web/src/components/usage/UsageProviderChart.test.ts +++ b/apps/web/src/components/usage/UsageProviderChart.test.ts @@ -87,6 +87,7 @@ describe("buildDayColumns", () => { { provider: "codex", value: 10 }, { provider: "claude", value: 20 }, { provider: "grok", value: 0 }, + { provider: "opencode", value: 0 }, ]); }); diff --git a/apps/web/src/components/usage/usageProviders.ts b/apps/web/src/components/usage/usageProviders.ts index efad95e531ad..176e7b6c41a2 100644 --- a/apps/web/src/components/usage/usageProviders.ts +++ b/apps/web/src/components/usage/usageProviders.ts @@ -1,6 +1,6 @@ import type { UsageProviderKind } from "@t3tools/contracts"; -import { ClaudeAI, GrokIcon, type Icon, OpenAI } from "../Icons"; +import { ClaudeAI, GrokIcon, type Icon, OpenAI, OpenCodeIcon } from "../Icons"; type UsageProviderPresentation = { readonly label: string; @@ -30,6 +30,11 @@ export const PROVIDER_PRESENTATION = { color: "color-mix(in oklab, var(--contrast-foreground) 72%, var(--background))", mark: GrokIcon, }, + opencode: { + label: "OpenCode", + color: "#8b5cf6", + mark: OpenCodeIcon, + }, } satisfies Record; /** Stable provider reading order across charts, summaries, tables, and hover rows. */ diff --git a/packages/contracts/src/usage.ts b/packages/contracts/src/usage.ts index 8c099ddb33aa..d853681e98fc 100644 --- a/packages/contracts/src/usage.ts +++ b/packages/contracts/src/usage.ts @@ -21,18 +21,18 @@ import { NonNegativeInt, TrimmedNonEmptyString } from "./baseSchemas.ts"; * client renders partial coverage when an environment reports an older version * rather than failing the whole page. */ -export const USAGE_CONTRACT_VERSION = 5 as const; +export const USAGE_CONTRACT_VERSION = 6 as const; /** * Oldest {@link UsageSummary} version a current client will still merge. * - * v5 only adds `grok` to {@link UsageProviderKind}; v4 Claude/Codex buckets - * remain valid, so mixed-version environments keep those totals instead of - * treating every older server as stale. + * v5 only adds `grok` to {@link UsageProviderKind}; v6 adds `opencode`. + * v4 Claude/Codex buckets remain valid, so mixed-version environments keep + * those totals instead of treating every older server as stale. */ export const USAGE_MERGE_COMPATIBLE_SINCE = 4 as const; -export const UsageProviderKind = Schema.Literals(["claude", "codex", "grok"]); +export const UsageProviderKind = Schema.Literals(["claude", "codex", "grok", "opencode"]); export type UsageProviderKind = typeof UsageProviderKind.Type; /**