From 8c6ce31036eed23795700a1b662b0dacaa15ae7a Mon Sep 17 00:00:00 2001 From: Siddiqui Qamar <137684575+siddqamar@users.noreply.github.com> Date: Sat, 20 Jun 2026 19:28:12 -0300 Subject: [PATCH] fix: narrow rate-limit provider config Narrow RateLimitService provider config wiring so OpenCode Go receives provider-specific config while Gemini keeps its OAuth-enabled setting through a separate resolver.\n\nValidated locally with the full src/main/rate-limits test suite and typecheck. --- src/main/index.ts | 9 ++++++- src/main/rate-limits/service.test.ts | 24 ++++++++++++------ src/main/rate-limits/service.ts | 38 ++++++++++++++-------------- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/main/index.ts b/src/main/index.ts index 8f53b7704..871c8feaf 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1328,7 +1328,14 @@ app.whenReady().then(async () => { rateLimits.setClaudeAuthPreparationResolver((target) => claudeRuntimeAuth!.prepareForRateLimitFetch(target) ) - rateLimits.setSettingsResolver(() => store!.getSettings()) + rateLimits.setOpenCodeGoConfigResolver(() => { + const settings = store!.getSettings() + return { + sessionCookie: settings.opencodeSessionCookie, + workspaceIdOverride: settings.opencodeWorkspaceId + } + }) + rateLimits.setGeminiCliOAuthEnabledResolver(() => store!.getSettings().geminiCliOAuthEnabled) keybindings = new KeybindingService({ homePath: app.getPath('home'), getLegacyOverrides: () => store!.getSettings().keybindings diff --git a/src/main/rate-limits/service.test.ts b/src/main/rate-limits/service.test.ts index 9423d87ab..47d5a5dd0 100644 --- a/src/main/rate-limits/service.test.ts +++ b/src/main/rate-limits/service.test.ts @@ -335,10 +335,11 @@ describe('RateLimitService', () => { it('fetches Gemini and OpenCode Go alongside Claude and Codex', async () => { const service = new RateLimitService() - service.setSettingsResolver(() => ({ - opencodeSessionCookie: 'session=abc123', - opencodeWorkspaceId: '' + service.setOpenCodeGoConfigResolver(() => ({ + sessionCookie: 'session=abc123', + workspaceIdOverride: '' })) + service.setGeminiCliOAuthEnabledResolver(() => true) vi.mocked(fetchClaudeRateLimits).mockResolvedValueOnce(okProvider('claude', 10, Date.now())) vi.mocked(fetchCodexRateLimits).mockResolvedValueOnce(okProvider('codex', 20, Date.now())) @@ -356,6 +357,7 @@ describe('RateLimitService', () => { }) expect(fetchCodexRateLimits).toHaveBeenCalledTimes(1) expect(fetchGeminiRateLimits).toHaveBeenCalledTimes(1) + expect(fetchGeminiRateLimits).toHaveBeenCalledWith(true) expect(fetchOpenCodeGoRateLimits).toHaveBeenCalledTimes(1) expect(fetchOpenCodeGoRateLimits).toHaveBeenCalledWith('session=abc123', undefined) @@ -678,7 +680,10 @@ describe('RateLimitService', () => { it('isolates provider failures so one error does not block others', async () => { const service = new RateLimitService() - service.setSettingsResolver(() => ({ opencodeSessionCookie: '', opencodeWorkspaceId: '' })) + service.setOpenCodeGoConfigResolver(() => ({ + sessionCookie: '', + workspaceIdOverride: '' + })) vi.mocked(fetchClaudeRateLimits).mockRejectedValueOnce(new Error('claude down')) vi.mocked(fetchCodexRateLimits).mockResolvedValueOnce(okProvider('codex', 20, Date.now())) @@ -701,7 +706,10 @@ describe('RateLimitService', () => { it('discards stale data when a provider becomes unavailable', async () => { const service = new RateLimitService() let cookie = 'session=valid' - service.setSettingsResolver(() => ({ opencodeSessionCookie: cookie, opencodeWorkspaceId: '' })) + service.setOpenCodeGoConfigResolver(() => ({ + sessionCookie: cookie, + workspaceIdOverride: '' + })) // 1. Success fetch vi.mocked(fetchClaudeRateLimits).mockResolvedValue(okProvider('claude', 10, Date.now())) @@ -736,9 +744,9 @@ describe('RateLimitService', () => { it('discards stale data when Workspace ID override is changed', async () => { const service = new RateLimitService() let workspaceId = 'wrk_A' - service.setSettingsResolver(() => ({ - opencodeSessionCookie: 'session=valid', - opencodeWorkspaceId: workspaceId + service.setOpenCodeGoConfigResolver(() => ({ + sessionCookie: 'session=valid', + workspaceIdOverride: workspaceId })) // 1. Success fetch for Workspace A diff --git a/src/main/rate-limits/service.ts b/src/main/rate-limits/service.ts index 32bdd930a..2745faea1 100644 --- a/src/main/rate-limits/service.ts +++ b/src/main/rate-limits/service.ts @@ -37,6 +37,13 @@ type ClaudeAuthPreparationResolver = ( target?: ClaudeAccountSelectionTarget ) => Promise +type OpenCodeGoRateLimitConfig = { + sessionCookie: string + workspaceIdOverride: string +} + +type GeminiCliOAuthEnabledResolver = () => boolean + // Why: Claude's subscription usage endpoint has a tight request budget. Quota // state is informational, so prefer keeping a recent snapshot over polling it // into 429s during long focused Orca sessions. @@ -98,13 +105,8 @@ export class RateLimitService { runtime: 'host', wslDistro: null } - private settingsResolver: - | (() => { - opencodeSessionCookie: string - opencodeWorkspaceId: string - geminiCliOAuthEnabled?: boolean - }) - | null = null + private openCodeGoConfigResolver: (() => OpenCodeGoRateLimitConfig) | null = null + private geminiCliOAuthEnabledResolver: GeminiCliOAuthEnabledResolver | null = null private inactiveClaudeAccountsResolver: (() => InactiveClaudeAccountInfo[]) | null = null private inactiveCodexAccountsResolver: (() => InactiveCodexAccountInfo[]) | null = null private inactiveClaudeCache = new Map() @@ -142,14 +144,12 @@ export class RateLimitService { this.claudeFetchTarget = normalizeClaudeAccountSelectionTarget(target) } - setSettingsResolver( - resolver: () => { - opencodeSessionCookie: string - opencodeWorkspaceId: string - geminiCliOAuthEnabled?: boolean - } - ): void { - this.settingsResolver = resolver + setOpenCodeGoConfigResolver(resolver: () => OpenCodeGoRateLimitConfig): void { + this.openCodeGoConfigResolver = resolver + } + + setGeminiCliOAuthEnabledResolver(resolver: GeminiCliOAuthEnabledResolver): void { + this.geminiCliOAuthEnabledResolver = resolver } setInactiveClaudeAccountsResolver(resolver: () => InactiveClaudeAccountInfo[]): void { @@ -819,10 +819,10 @@ export class RateLimitService { const codexProvenance = this.getCodexProvenance(codexTarget, codexHomePath) const codexGeneration = this.codexFetchGeneration const previousState = this.state - const settings = this.settingsResolver?.() - const cookie = settings?.opencodeSessionCookie ?? '' - const workspaceIdOverride = settings?.opencodeWorkspaceId ?? '' - const geminiCliOAuthEnabled = settings?.geminiCliOAuthEnabled ?? false + const openCodeGoConfig = this.openCodeGoConfigResolver?.() + const cookie = openCodeGoConfig?.sessionCookie ?? '' + const workspaceIdOverride = openCodeGoConfig?.workspaceIdOverride ?? '' + const geminiCliOAuthEnabled = this.geminiCliOAuthEnabledResolver?.() ?? false // Detect if configuration changed — if it did, we must discard any stale // data because it belongs to a different session/workspace.