diff --git a/src/renderer/src/components/status-bar/CodexSwitcherMenu.tsx b/src/renderer/src/components/status-bar/CodexSwitcherMenu.tsx index 53b19dac519..259d79ffdae 100644 --- a/src/renderer/src/components/status-bar/CodexSwitcherMenu.tsx +++ b/src/renderer/src/components/status-bar/CodexSwitcherMenu.tsx @@ -250,7 +250,13 @@ export function CodexSwitcherMenu({ ) : null} - {inactiveUsage?.isFetching && !inactiveUsage.rateLimits ? ( + {/* Why: rows follow this desktop's codexTarget, so a remote owner's usage could land on the wrong row. */} + {target.active && !hasActiveRuntimeEnvironment ? ( + + ) : inactiveUsage?.isFetching && !inactiveUsage.rateLimits ? ( ) : showSignInAction ? ( {}) const toastSuccess = vi.fn() @@ -18,6 +19,7 @@ const fetchSettings = vi.fn(async () => {}) const reauthenticate = vi.fn(async (_args: unknown) => codexSnapshot(null)) let storeSettings: GlobalSettings +let accountOwner: RuntimeClientTarget function codexAccount(id: string, updatedAt: number): CodexManagedAccountSummary { return { @@ -86,6 +88,11 @@ vi.mock('@/runtime/runtime-provider-accounts-client', () => ({ selectClaudeProviderAccount: vi.fn(async () => ({ accounts: [], activeAccountId: null })) })) +vi.mock('@/runtime/use-worktree-runtime-target', async (importOriginal) => ({ + ...(await importOriginal>()), + useActiveAccountOwner: () => ({ target: accountOwner, wslHostDistro: null }) +})) + vi.mock('@/lib/windows-terminal-capabilities', () => ({ useWindowsTerminalCapabilities: () => ({ wslDistros: [], isLoading: false }), getWindowsTerminalCapabilityOwnerKey: () => 'local' @@ -165,11 +172,21 @@ const codexProvider: ProviderRateLimits = { updatedAt: 1 } as unknown as ProviderRateLimits -async function renderSwitcherAndOpenAccounts(summaryLabel: string): Promise { +const liveUsage: ProviderRateLimits = { + ...codexProvider, + status: 'ok', + error: null, + weekly: { usedPercent: 11, windowMinutes: 10_080, resetsAt: null, resetDescription: null } +} + +async function renderSwitcherAndOpenAccounts( + summaryLabel: string, + codex = codexProvider +): Promise { const { CodexSwitcherMenu } = await import('./StatusBar') render( React.createElement(CodexSwitcherMenu, { - codex: codexProvider, + codex, compact: false, iconOnly: false }) @@ -182,6 +199,7 @@ describe('status bar Codex sign-in action', () => { beforeEach(() => { vi.clearAllMocks() storeSettings = settingsWithActive(null) + accountOwner = { kind: 'local' } Object.defineProperty(window, 'api', { configurable: true, writable: true, @@ -193,6 +211,32 @@ describe('status bar Codex sign-in action', () => { cleanup() }) + it.each([null, 'account-1'])( + 'shows live usage in the active account row, including system default: %s', + async (activeAccountId) => { + storeSettings = settingsWithActive(activeAccountId) + await renderSwitcherAndOpenAccounts( + activeAccountId ? 'account-1@example.com' : 'System default', + liveUsage + ) + + const activeRow = screen.getByRole('menuitem', { name: /Active/ }) + expect(within(activeRow).getByText('11% used wk')).toBeTruthy() + } + ) + + it("keeps a remote owner's usage off rows picked by this desktop's runtime target", async () => { + accountOwner = { kind: 'environment', environmentId: 'remote-1' } + const { CodexSwitcherMenu } = await import('./StatusBar') + render( + React.createElement(CodexSwitcherMenu, { codex: liveUsage, compact: false, iconOnly: false }) + ) + fireEvent.click(screen.getByText('System default')) + + const activeRow = await screen.findByRole('menuitem', { name: /Active/ }) + expect(within(activeRow).queryByText('11% used wk')).toBeNull() + }) + it.each([null, 'Enterprise'])( 'selects the exact same-email account when workspace labels collide: %s', async (workspaceLabel) => {