diff --git a/mobile/src/components/AccountUsage.tsx b/mobile/src/components/AccountUsage.tsx
index 9d85bf434..00b3e6074 100644
--- a/mobile/src/components/AccountUsage.tsx
+++ b/mobile/src/components/AccountUsage.tsx
@@ -21,9 +21,9 @@ export {
hasRenderableUsage
} from './account-usage-state'
-// Why: matches desktop StatusBar convention — bars show percent remaining
-// (so a fresh account renders full, a depleted one renders empty), not
-// percent used. Color thresholds invert accordingly.
+// Why: matches desktop StatusBar — bars show percent used (consumption), same
+// as Claude/Codex harness meters. Fresh account is empty/green; depleted is
+// full/red.
export function UsageBar({
label,
usedPercent,
@@ -35,13 +35,15 @@ export function UsageBar({
unavailable: boolean
loading?: boolean
}) {
- const remaining = usedPercent == null ? null : Math.max(0, Math.min(100, 100 - usedPercent))
+ // Why: round then clamp so bar width, color, and label share one value (desktop parity).
+ const used = usedPercent == null ? null : Math.max(0, Math.min(100, Math.round(usedPercent)))
+ // Why: same consumption bands as desktop barColor (green <60, amber <80, red ≥80).
const barColor =
- remaining == null
+ used == null
? colors.textMuted
- : remaining <= 10
+ : used >= 80
? colors.statusRed
- : remaining <= 30
+ : used >= 60
? colors.statusAmber
: colors.statusGreen
return (
@@ -52,7 +54,7 @@ export function UsageBar({
style={[
styles.usageFill,
{
- width: `${remaining ?? 0}%`,
+ width: `${used ?? 0}%`,
backgroundColor: unavailable ? colors.textMuted : barColor
}
]}
@@ -61,9 +63,7 @@ export function UsageBar({
{loading ? (
) : (
-
- {unavailable || remaining == null ? '—' : `${Math.round(remaining)}%`}
-
+ {unavailable || used == null ? '—' : `${used}%`}
)}
)
diff --git a/src/renderer/src/assets/main.css b/src/renderer/src/assets/main.css
index a85d7fb6c..56841b772 100644
--- a/src/renderer/src/assets/main.css
+++ b/src/renderer/src/assets/main.css
@@ -2433,7 +2433,7 @@
}
/* Brief one-shot pulse when the Codex limits popover swaps accounts and the
- "100% left" label flashes from red to green. */
+ "0% used" label flashes from red to green. */
@keyframes feature-wall-meta-pulse {
0% {
color: rgb(220 38 38);
diff --git a/src/renderer/src/components/feature-wall/agents-orchestration/UsagePage.tsx b/src/renderer/src/components/feature-wall/agents-orchestration/UsagePage.tsx
index faac3d456..a7f73f3b9 100644
--- a/src/renderer/src/components/feature-wall/agents-orchestration/UsagePage.tsx
+++ b/src/renderer/src/components/feature-wall/agents-orchestration/UsagePage.tsx
@@ -77,10 +77,11 @@ function Popover(props: {
pulseKey: number
}): JSX.Element {
const { expanded, targeted, swapped, pulseKey } = props
- const sessionPctText = swapped ? '100% left' : '4% left'
+ // Why: bars show % used (consumption), matching the live status-bar meter.
+ const sessionPctText = swapped ? '0% used' : '96% used'
const sessionResetText = swapped ? 'Resets in 5h' : 'Resets in 47m'
- const sessionFillWidth = swapped ? '100%' : '4%'
- const weeklyFillWidth = '62%'
+ const sessionFillWidth = swapped ? '0%' : '96%'
+ const weeklyFillWidth = '38%'
return (
{translate(
'auto.components.feature.wall.agents.orchestration.UsagePage.05ce4ecdd3',
- '62% left'
+ '38% used'
)}
}
@@ -201,15 +202,15 @@ function Popover(props: {
@@ -295,11 +296,12 @@ function SwitchAccount(props: {
// The 340px-wide light pill at the bottom of the panel that the popover tip
// points down to. Codex chip is the "active" one — it animates from a near-
-// empty red bar to a full green bar after the account swap.
+// full red bar (% used) to an empty green bar after the account swap.
function BottomBar(props: { swapped: boolean }): JSX.Element {
- const codexFillWidth = props.swapped ? '100%' : '4%'
+ // Why: match live status-bar consumption meters (% used), same as the popover.
+ const codexFillWidth = props.swapped ? '0%' : '96%'
const codexFillColor = props.swapped ? 'rgb(34 197 94)' : 'rgb(239 68 68)'
- const codexMeta = props.swapped ? '100% 5h · 96% wk' : '4% 47m'
+ const codexMeta = props.swapped ? '0% used 5h · 4% used wk' : '96% used 47m'
return (
-
+
{translate(
'auto.components.feature.wall.agents.orchestration.UsagePage.64265cb295',
- '71% 5h'
+ '29% used 5h'
)}
diff --git a/src/renderer/src/components/status-bar/StatusBar.tsx b/src/renderer/src/components/status-bar/StatusBar.tsx
index 71cc71ffe..59c9fe08e 100644
--- a/src/renderer/src/components/status-bar/StatusBar.tsx
+++ b/src/renderer/src/components/status-bar/StatusBar.tsx
@@ -51,6 +51,7 @@ import {
ProviderIcon,
ProviderPanel,
barColor,
+ clampUsedPercent,
formatResetCreditExpiry,
getProviderUsageStatusLabel
} from './tooltip'
@@ -932,15 +933,15 @@ function ClaudeSwitcherMenu({
}
// ---------------------------------------------------------------------------
-// Mini progress bar (shows remaining capacity, grey)
+// Mini progress bar (shows consumption / % used, grey)
// ---------------------------------------------------------------------------
-function MiniBar({ leftPct }: { leftPct: number }): React.JSX.Element {
+function MiniBar({ usedPct }: { usedPct: number }): React.JSX.Element {
return (
)
@@ -957,29 +958,32 @@ export function InlineUsageBars({
limits: ProviderRateLimits
isFetching: boolean
}): React.JSX.Element {
+ // Why: show % used (consumption), not remaining — matches harness meters (#7551).
+ // Keep the "used" word in compact labels so bare "32% 5h" is not read as remaining.
+ const usedSuffix = translate('auto.components.status.bar.tooltip.cedb7b99e3', '% used')
const usageWindows = [
limits.session
? {
key: 'session',
- left: Math.max(0, Math.round(100 - limits.session.usedPercent)),
- label: translate('auto.components.status.bar.StatusBar.d79c3362c4', '% 5h')
+ used: clampUsedPercent(limits.session.usedPercent),
+ label: translate('auto.components.status.bar.StatusBar.d79c3362c4', '5h')
}
: null,
limits.weekly
? {
key: 'weekly',
- left: Math.max(0, Math.round(100 - limits.weekly.usedPercent)),
- label: translate('auto.components.status.bar.StatusBar.5c938d39ac', '% wk')
+ used: clampUsedPercent(limits.weekly.usedPercent),
+ label: translate('auto.components.status.bar.StatusBar.5c938d39ac', 'wk')
}
: null,
limits.fableWeekly
? {
key: 'fableWeekly',
- left: Math.max(0, Math.round(100 - limits.fableWeekly.usedPercent)),
- label: translate('auto.components.status.bar.StatusBar.54e8d6bb2d', '% Fable')
+ used: clampUsedPercent(limits.fableWeekly.usedPercent),
+ label: translate('auto.components.status.bar.StatusBar.54e8d6bb2d', 'Fable')
}
: null
- ].filter((window): window is { key: string; left: number; label: string } => window !== null)
+ ].filter((window): window is { key: string; used: number; label: string } => window !== null)
return (
- {window.left}
- {window.label}
+ {window.used}
+ {usedSuffix} {window.label}
))}
@@ -1071,14 +1075,16 @@ function InlineUsageSkeleton(): React.JSX.Element {
}
// ---------------------------------------------------------------------------
-// Window label (shows percent remaining)
+// Window label (shows percent used / consumption)
// ---------------------------------------------------------------------------
function WindowLabel({ w, label }: { w: RateLimitWindow; label: string }): React.JSX.Element {
- const left = Math.max(0, Math.round(100 - w.usedPercent))
+ const used = clampUsedPercent(w.usedPercent)
+ // Why: "32% 5h" is ambiguous after the remaining→used flip; keep "used" explicit.
return (
- {left}% {label}
+ {used}
+ {translate('auto.components.status.bar.tooltip.cedb7b99e3', '% used')} {label}
)
}
@@ -1150,12 +1156,13 @@ function ProviderSegment({
{visibleBuckets.map((bucket, i) => {
- const left = Math.max(0, Math.round(100 - bucket.usedPercent))
+ const used = clampUsedPercent(bucket.usedPercent)
return (
{i > 0 && ·}
- {bucket.name} {left}%
+ {bucket.name} {used}
+ {translate('auto.components.status.bar.tooltip.cedb7b99e3', '% used')}
)
@@ -1195,7 +1202,7 @@ function ProviderSegment({
return (
- {p.session && !compact && }
+ {p.session && !compact && }
{visibleWindows.map((window, index) => (
{index > 0 && ·}
diff --git a/src/renderer/src/components/status-bar/inline-usage-bars.test.tsx b/src/renderer/src/components/status-bar/inline-usage-bars.test.tsx
index 0160978be..018d26076 100644
--- a/src/renderer/src/components/status-bar/inline-usage-bars.test.tsx
+++ b/src/renderer/src/components/status-bar/inline-usage-bars.test.tsx
@@ -46,8 +46,9 @@ describe('InlineUsageBars', () => {
)
- expect(markup).toContain('68% 5h')
- expect(markup).toContain('84% wk')
- expect(markup).toContain('58% Fable')
+ // Why: bars show % used with explicit "used" so compact labels are not ambiguous.
+ expect(markup).toContain('32% used 5h')
+ expect(markup).toContain('16% used wk')
+ expect(markup).toContain('42% used Fable')
})
})
diff --git a/src/renderer/src/components/status-bar/status-bar-provider-menu-focus.test.tsx b/src/renderer/src/components/status-bar/status-bar-provider-menu-focus.test.tsx
index 143c562fc..25dfa651b 100644
--- a/src/renderer/src/components/status-bar/status-bar-provider-menu-focus.test.tsx
+++ b/src/renderer/src/components/status-bar/status-bar-provider-menu-focus.test.tsx
@@ -28,7 +28,8 @@ vi.mock('./tooltip', () => ({
ProviderPanel: function ProviderPanel(props: Record) {
return { type: 'ProviderPanel', props }
},
- barColor: () => 'bg-green-500'
+ barColor: () => 'bg-green-500',
+ clampUsedPercent: (n: number) => Math.max(0, Math.min(100, Math.round(n)))
}))
vi.mock('@/components/ui/dropdown-menu', () => ({
diff --git a/src/renderer/src/components/status-bar/tooltip.test.ts b/src/renderer/src/components/status-bar/tooltip.test.ts
index dea9af3ab..8f214ecc7 100644
--- a/src/renderer/src/components/status-bar/tooltip.test.ts
+++ b/src/renderer/src/components/status-bar/tooltip.test.ts
@@ -22,6 +22,8 @@ vi.mock('@/i18n/i18n', () => ({
}))
import {
+ barColor,
+ clampUsedPercent,
formatResetCreditExpiry,
formatResetCountdown,
getProviderUsageErrorMessage,
@@ -409,7 +411,7 @@ describe('ProviderPanel reset rendering', () => {
expect(markup).toContain('Resets in 6d 17h')
})
- it('renders MiniMax session as `100 - usedPercent` left so the value matches the bar', () => {
+ it('renders MiniMax session as usedPercent so the value matches the bar', () => {
vi.useFakeTimers()
vi.setSystemTime(new Date(2026, 6, 4, 15, 0))
const p = provider({
@@ -425,14 +427,13 @@ describe('ProviderPanel reset rendering', () => {
const markup = renderToStaticMarkup(ProviderPanel({ p }))
- // Why: the bar reads "65% 5h"; the tooltip must read "65% left" from the
- // same source field so the two views stay consistent.
- expect(markup).toContain('65%')
- expect(markup).toContain('% left')
- expect(markup).not.toContain('100% left')
+ // Why: bars show consumption (% used), matching harness meters (#7551).
+ expect(markup).toContain('35%')
+ expect(markup).toContain('% used')
+ expect(markup).not.toContain('% left')
})
- it('clamps MiniMax session to 0% left when usedPercent reports 100', () => {
+ it('clamps MiniMax session to 100% used when usedPercent reports 100', () => {
vi.useFakeTimers()
vi.setSystemTime(new Date(2026, 6, 4, 15, 0))
const p = provider({
@@ -448,7 +449,52 @@ describe('ProviderPanel reset rendering', () => {
const markup = renderToStaticMarkup(ProviderPanel({ p }))
- expect(markup).toContain('0% left')
+ expect(markup).toContain('100%')
+ expect(markup).toContain('% used')
+ })
+
+ it('clamps over-100 usedPercent to 100% used in the panel', () => {
+ vi.useFakeTimers()
+ vi.setSystemTime(new Date(2026, 6, 4, 15, 0))
+ const p = provider({
+ provider: 'minimax',
+ status: 'ok',
+ session: {
+ usedPercent: 140,
+ windowMinutes: 300,
+ resetsAt: Date.now() + 2 * 60 * 60_000,
+ resetDescription: null
+ }
+ })
+
+ const markup = renderToStaticMarkup(ProviderPanel({ p }))
+
+ expect(markup).toContain('100%')
+ expect(markup).toContain('width:100%')
+ expect(markup).not.toContain('140%')
+ })
+})
+
+describe('clampUsedPercent', () => {
+ it('rounds and clamps into 0–100', () => {
+ expect(clampUsedPercent(-3)).toBe(0)
+ expect(clampUsedPercent(32.4)).toBe(32)
+ expect(clampUsedPercent(32.6)).toBe(33)
+ expect(clampUsedPercent(100)).toBe(100)
+ expect(clampUsedPercent(140)).toBe(100)
+ })
+})
+
+describe('barColor', () => {
+ // Why: thresholds are on % used (consumption). Guard against flipping back
+ // to remaining-based colors without noticing.
+ it('maps used percent to green / yellow / red bands', () => {
+ expect(barColor(0)).toBe('bg-green-500')
+ expect(barColor(59)).toBe('bg-green-500')
+ expect(barColor(60)).toBe('bg-yellow-500')
+ expect(barColor(79)).toBe('bg-yellow-500')
+ expect(barColor(80)).toBe('bg-red-500')
+ expect(barColor(100)).toBe('bg-red-500')
})
})
diff --git a/src/renderer/src/components/status-bar/tooltip.tsx b/src/renderer/src/components/status-bar/tooltip.tsx
index be174965b..47ba64142 100644
--- a/src/renderer/src/components/status-bar/tooltip.tsx
+++ b/src/renderer/src/components/status-bar/tooltip.tsx
@@ -191,13 +191,19 @@ export function getWindowSections(
// `text-background` for primary text and `text-background/50` for secondary
// to stay readable inside the inverted tooltip container.
-// Why: color-coded by remaining capacity so users can quickly gauge urgency.
-// Green = comfortable (>40% left), yellow = caution (20-40%), red = critical (<20%).
-export function barColor(leftPct: number): string {
- if (leftPct > 40) {
+// Why: single clamp for bar width + label so status bar and tooltip never diverge.
+export function clampUsedPercent(usedPercent: number): number {
+ return Math.max(0, Math.min(100, Math.round(usedPercent)))
+}
+
+// Why: color-coded by consumption so users can quickly gauge urgency.
+// Matches common harness usage meters (Claude/Codex): bars fill with % used.
+// Green = comfortable (<60% used), yellow = caution (60-80%), red = critical (≥80%).
+export function barColor(usedPct: number): string {
+ if (usedPct < 60) {
return 'bg-green-500'
}
- if (leftPct > 20) {
+ if (usedPct < 80) {
return 'bg-yellow-500'
}
return 'bg-red-500'
@@ -282,7 +288,9 @@ export function ProviderPanel({
if (!w) {
return null
}
- const leftPct = Math.max(0, Math.round(100 - w.usedPercent))
+ // Why: show % used (consumption), not remaining — matches Claude/Codex
+ // harness meters and avoids the "full green bar = exhausted" misread (#7551).
+ const usedPct = clampUsedPercent(w.usedPercent)
const resetLabel = w.resetsAt ? formatResetCountdown(w.resetsAt - Date.now()) : null
return (
@@ -290,14 +298,14 @@ export function ProviderPanel({
{label}
- {leftPct}
- {translate('auto.components.status.bar.tooltip.cedb7b99e3', '% left')}
+ {usedPct}
+ {translate('auto.components.status.bar.tooltip.cedb7b99e3', '% used')}
{resetLabel && {resetLabel}}
diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json
index 8a91f7965..c0f48f1cc 100644
--- a/src/renderer/src/i18n/locales/en.json
+++ b/src/renderer/src/i18n/locales/en.json
@@ -2999,9 +2999,9 @@
"2483c60695": "···",
"c35af53b73": "Sign in",
"f19a63e7cd": "Sign in to see usage",
- "5c938d39ac": "% wk",
- "54e8d6bb2d": "% Fable",
- "d79c3362c4": "% 5h",
+ "5c938d39ac": "wk",
+ "54e8d6bb2d": "Fable",
+ "d79c3362c4": "5h",
"a79c64f87e": "Fable",
"8295903d17": "Restart live Claude terminals before continuing old conversations after switching.",
"c98ea88392": "No other accounts",
@@ -3169,7 +3169,7 @@
}
},
"tooltip": {
- "cedb7b99e3": "% left",
+ "cedb7b99e3": "% used",
"6d6df77f41": "No data available",
"7f7f208060": "Monthly",
"252c096536": "Weekly",
@@ -10996,11 +10996,11 @@
"945865332e": "Signing in"
},
"UsagePage": {
- "64265cb295": "71% 5h",
+ "64265cb295": "29% used 5h",
"be5a165875": "Switch to",
"277a9c65a9": "Codex Account",
"4dce5ca3aa": "Resets in 4d 3h",
- "05ce4ecdd3": "62% left",
+ "05ce4ecdd3": "38% used",
"0470aaed99": "Weekly",
"f421abf962": "Session",
"5e45fb1238": "Updated 1m ago",
diff --git a/src/renderer/src/i18n/locales/es.json b/src/renderer/src/i18n/locales/es.json
index 694ea52f8..37f554861 100644
--- a/src/renderer/src/i18n/locales/es.json
+++ b/src/renderer/src/i18n/locales/es.json
@@ -2999,9 +2999,9 @@
"2483c60695": "···",
"c35af53b73": "Iniciar sesión",
"f19a63e7cd": "Inicia sesión para ver el uso",
- "5c938d39ac": "% semana",
- "54e8d6bb2d": "% Fable",
- "d79c3362c4": "% 5h",
+ "5c938d39ac": "semana",
+ "54e8d6bb2d": "Fable",
+ "d79c3362c4": "5h",
"a79c64f87e": "Fable",
"8295903d17": "Reinicia los terminales Claude activos antes de continuar conversaciones antiguas después de cambiar.",
"c98ea88392": "Ninguna otra cuenta",
@@ -3169,7 +3169,7 @@
}
},
"tooltip": {
- "cedb7b99e3": "% restante",
+ "cedb7b99e3": "% usado",
"6d6df77f41": "No hay datos disponibles",
"7f7f208060": "Mensual",
"252c096536": "Semanal",
@@ -10996,11 +10996,11 @@
"945865332e": "Iniciando sesión"
},
"UsagePage": {
- "64265cb295": "71% 5h",
+ "64265cb295": "29% usado 5h",
"be5a165875": "Cambiar a",
"277a9c65a9": "Cuenta de Codex",
"4dce5ca3aa": "Se restablece en 4d 3h",
- "05ce4ecdd3": "62% restante",
+ "05ce4ecdd3": "38% usado",
"0470aaed99": "Semanal",
"f421abf962": "Sesión",
"5e45fb1238": "Actualizado hace 1 min",
diff --git a/src/renderer/src/i18n/locales/ja.json b/src/renderer/src/i18n/locales/ja.json
index 59b3e7640..eb83299b3 100644
--- a/src/renderer/src/i18n/locales/ja.json
+++ b/src/renderer/src/i18n/locales/ja.json
@@ -2999,9 +2999,9 @@
"2483c60695": "・・・",
"c35af53b73": "サインイン",
"f19a63e7cd": "サインインして使用状況を確認する",
- "5c938d39ac": "%週",
- "54e8d6bb2d": "% Fable",
- "d79c3362c4": "% 5時間",
+ "5c938d39ac": "週",
+ "54e8d6bb2d": "Fable",
+ "d79c3362c4": "5時間",
"a79c64f87e": "Fable",
"8295903d17": "切り替え後に古い会話を続ける前に、ライブ Claude terminals を再起動します。",
"c98ea88392": "他のアカウントはありません",
@@ -3169,7 +3169,7 @@
}
},
"tooltip": {
- "cedb7b99e3": "% 左",
+ "cedb7b99e3": "% 使用",
"6d6df77f41": "利用可能なデータがありません",
"7f7f208060": "毎月",
"252c096536": "毎週",
@@ -10996,11 +10996,11 @@
"945865332e": "サインインする"
},
"UsagePage": {
- "64265cb295": "71% 5時間",
+ "64265cb295": "29% 使用 5時間",
"be5a165875": "に切り替えます",
"277a9c65a9": "Codex アカウント",
"4dce5ca3aa": "4d 3h でリセット",
- "05ce4ecdd3": "62%残っています",
+ "05ce4ecdd3": "38%使用",
"0470aaed99": "毎週",
"f421abf962": "セッション",
"5e45fb1238": "1分前に更新されました",
diff --git a/src/renderer/src/i18n/locales/ko.json b/src/renderer/src/i18n/locales/ko.json
index 3a81820ec..29d25e04b 100644
--- a/src/renderer/src/i18n/locales/ko.json
+++ b/src/renderer/src/i18n/locales/ko.json
@@ -2999,9 +2999,9 @@
"2483c60695": "···",
"c35af53b73": "로그인",
"f19a63e7cd": "사용량을 보려면 로그인하세요.",
- "5c938d39ac": "%주간",
- "54e8d6bb2d": "% Fable",
- "d79c3362c4": "% 5h",
+ "5c938d39ac": "주간",
+ "54e8d6bb2d": "Fable",
+ "d79c3362c4": "5h",
"a79c64f87e": "Fable",
"8295903d17": "전환 후 이전 대화를 계속하기 전에 라이브 Claude terminals을 다시 시작하십시오.",
"c98ea88392": "다른 계정 없음",
@@ -3169,7 +3169,7 @@
}
},
"tooltip": {
- "cedb7b99e3": "% 남음",
+ "cedb7b99e3": "% 사용",
"6d6df77f41": "데이터가 없습니다",
"7f7f208060": "월간",
"252c096536": "주간",
@@ -10996,11 +10996,11 @@
"945865332e": "로그인 중"
},
"UsagePage": {
- "64265cb295": "71% 5시간",
+ "64265cb295": "29% 사용 5시간",
"be5a165875": "다음으로 전환",
"277a9c65a9": "Codex 계정",
"4dce5ca3aa": "4일 3시간 후에 재설정됩니다.",
- "05ce4ecdd3": "62% 남음",
+ "05ce4ecdd3": "38% 사용",
"0470aaed99": "주간",
"f421abf962": "세션",
"5e45fb1238": "1분 전에 업데이트됨",
diff --git a/src/renderer/src/i18n/locales/zh.json b/src/renderer/src/i18n/locales/zh.json
index ec6987a59..e8c2c8a10 100644
--- a/src/renderer/src/i18n/locales/zh.json
+++ b/src/renderer/src/i18n/locales/zh.json
@@ -2999,9 +2999,9 @@
"2483c60695": "···",
"c35af53b73": "登录",
"f19a63e7cd": "登录查看使用情况",
- "5c938d39ac": "% 周",
- "54e8d6bb2d": "% Fable",
- "d79c3362c4": "% 5小时",
+ "5c938d39ac": "周",
+ "54e8d6bb2d": "Fable",
+ "d79c3362c4": "5小时",
"a79c64f87e": "Fable",
"8295903d17": "切换后继续旧对话之前,请重新启动实时 Claude 终端。",
"c98ea88392": "没有其他账户",
@@ -3169,7 +3169,7 @@
}
},
"tooltip": {
- "cedb7b99e3": "剩余 %",
+ "cedb7b99e3": "% 已用",
"6d6df77f41": "无可用数据",
"7f7f208060": "每月",
"252c096536": "每周",
@@ -10996,11 +10996,11 @@
"945865332e": "登录"
},
"UsagePage": {
- "64265cb295": "71% 5小时",
+ "64265cb295": "29% 已用 5小时",
"be5a165875": "切换到",
"277a9c65a9": "Codex 账户",
"4dce5ca3aa": "4d 3h后重置",
- "05ce4ecdd3": "还剩 62%",
+ "05ce4ecdd3": "已用 38%",
"0470aaed99": "每周",
"f421abf962": "会话",
"5e45fb1238": "更新于 1 分钟前",