From c9e7e49a78f171b88b30cadcaf709f42a26693f5 Mon Sep 17 00:00:00 2001 From: infiniti <52129260+developerInfiniti@users.noreply.github.com> Date: Wed, 27 May 2026 23:00:32 +0300 Subject: [PATCH] fix: show OpenCode inventory fallback as available --- .../renderer/locales/en/settings.json | 1 + .../renderer/locales/ru/settings.json | 1 + .../localization/renderer/resources.d.ts | 1 + .../runtime/ProviderRuntimeSettingsDialog.tsx | 7 ++-- .../runtime/providerConnectionUi.ts | 4 +- .../cli/CliStatusVisibility.test.ts | 3 +- .../ProviderRuntimeSettingsDialog.test.ts | 37 ++++++++++++++++ .../runtime/providerConnectionUi.test.ts | 42 +++++++++---------- 8 files changed, 67 insertions(+), 29 deletions(-) diff --git a/src/features/localization/renderer/locales/en/settings.json b/src/features/localization/renderer/locales/en/settings.json index 2e8e2e23..d41f7f8c 100644 --- a/src/features/localization/renderer/locales/en/settings.json +++ b/src/features/localization/renderer/locales/en/settings.json @@ -884,6 +884,7 @@ }, "status": { "checking": "Checking...", + "modelsAvailable": "Models available", "checked": "Checked", "providerActivity": "Provider Activity", "notConnected": "Not connected", diff --git a/src/features/localization/renderer/locales/ru/settings.json b/src/features/localization/renderer/locales/ru/settings.json index 441b0c2d..f9a89a76 100644 --- a/src/features/localization/renderer/locales/ru/settings.json +++ b/src/features/localization/renderer/locales/ru/settings.json @@ -884,6 +884,7 @@ }, "status": { "checking": "Проверка...", + "modelsAvailable": "Модели доступны", "checked": "Проверено", "providerActivity": "Активность провайдеров", "notConnected": "Не подключено", diff --git a/src/features/localization/renderer/resources.d.ts b/src/features/localization/renderer/resources.d.ts index 203d93e9..f70bbd5e 100644 --- a/src/features/localization/renderer/resources.d.ts +++ b/src/features/localization/renderer/resources.d.ts @@ -2759,6 +2759,7 @@ export default interface Resources { chatGptVerificationDegraded: 'ChatGPT account detected - account verification is currently degraded.'; checked: 'Checked'; checking: 'Checking...'; + modelsAvailable: 'Models available'; codexLocalAccountNeedsReconnect: 'Codex has a locally selected ChatGPT account, but the current session needs reconnect.'; codexNativeReady: 'Codex native ready'; codexNativeUnavailable: 'Codex native unavailable'; diff --git a/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx b/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx index a94caf76..9384abe4 100644 --- a/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +++ b/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx @@ -54,6 +54,7 @@ import { import { formatProviderAuthMethodLabelForProvider, formatProviderAuthModeLabelForProvider, + formatProviderStatusText, getProviderConnectLabel, getProviderCurrentRuntimeSummary, isConnectionManagedRuntimeProvider, @@ -414,7 +415,7 @@ function getProviderUsageLabel( t ), }) - : provider.statusMessage || t('providerRuntime.usage.notConnected'); + : formatProviderStatusText(provider, t); } function getCompactOpenCodeProviderDetailMessage(detailMessage?: string | null): string | null { @@ -1150,10 +1151,8 @@ export const ProviderRuntimeSettingsDialog = ({ let connectionStatusLabel: string | null = null; if (selectedProvider) { - if (!hideConnectionMethodMeta && selectedProvider.authenticated) { + if (!hideConnectionMethodMeta) { connectionStatusLabel = getProviderUsageLabel(selectedProvider, t); - } else if (!hideConnectionMethodMeta) { - connectionStatusLabel = t('providerRuntime.usage.notConnected'); } } const showSelectedProviderSummary = Boolean(selectedProvider) && !connectionManagedRuntime; diff --git a/src/renderer/components/runtime/providerConnectionUi.ts b/src/renderer/components/runtime/providerConnectionUi.ts index e5fbb883..f8ade973 100644 --- a/src/renderer/components/runtime/providerConnectionUi.ts +++ b/src/renderer/components/runtime/providerConnectionUi.ts @@ -425,8 +425,8 @@ export function formatProviderStatusText( if (isProviderInventoryOnlyFallback(provider)) { return translateProviderConnection( t, - 'providerRuntime.connectionUi.status.checking', - 'Checking...' + 'providerRuntime.connectionUi.status.modelsAvailable', + 'Models available' ); } diff --git a/test/renderer/components/cli/CliStatusVisibility.test.ts b/test/renderer/components/cli/CliStatusVisibility.test.ts index f79140c7..984a410b 100644 --- a/test/renderer/components/cli/CliStatusVisibility.test.ts +++ b/test/renderer/components/cli/CliStatusVisibility.test.ts @@ -755,8 +755,9 @@ describe('CLI status visibility during completed install state', () => { }); expect(host.textContent).toContain('OpenCode'); - expect(host.textContent).toContain('Checking...'); + expect(host.textContent).toContain('Models available'); expect(host.textContent).toContain('big-pickle'); + expect(host.textContent).not.toContain('Checking...'); expect(host.textContent).not.toContain('Provider status unavailable'); expect(host.textContent).not.toContain('Models unavailable for this runtime build'); diff --git a/test/renderer/components/runtime/ProviderRuntimeSettingsDialog.test.ts b/test/renderer/components/runtime/ProviderRuntimeSettingsDialog.test.ts index 582d5a29..c9471c76 100644 --- a/test/renderer/components/runtime/ProviderRuntimeSettingsDialog.test.ts +++ b/test/renderer/components/runtime/ProviderRuntimeSettingsDialog.test.ts @@ -1972,4 +1972,41 @@ describe('ProviderRuntimeSettingsDialog', () => { expect(host.textContent).not.toContain('behavior abc123'); expect(host.textContent).not.toContain('Desktop currently exposes status only.'); }); + + it('shows OpenCode inventory fallback as models available instead of disconnected', async () => { + const host = document.createElement('div'); + document.body.appendChild(host); + const root = createRoot(host); + const provider: CliProviderStatus = { + ...createOpenCodeProvider(), + supported: false, + authenticated: false, + authMethod: null, + verificationState: 'unknown', + statusMessage: null, + detailMessage: null, + models: ['opencode/big-pickle'], + backend: null, + availableBackends: [], + connection: null, + }; + + await act(async () => { + root.render( + React.createElement(ProviderRuntimeSettingsDialog, { + open: true, + onOpenChange: vi.fn(), + providers: [provider], + initialProviderId: 'opencode', + projectPath: '/tmp/project-a', + onSelectBackend: vi.fn(), + onRefreshProvider: vi.fn(() => Promise.resolve(undefined)), + }) + ); + await Promise.resolve(); + }); + + expect(host.textContent).toContain('Models available'); + expect(host.textContent).not.toContain('Not connected'); + }); }); diff --git a/test/renderer/components/runtime/providerConnectionUi.test.ts b/test/renderer/components/runtime/providerConnectionUi.test.ts index 6847eddf..3a321fec 100644 --- a/test/renderer/components/runtime/providerConnectionUi.test.ts +++ b/test/renderer/components/runtime/providerConnectionUi.test.ts @@ -80,21 +80,19 @@ function createCodexProvider( }, selectedBackendId: overrides?.selectedBackendId ?? 'codex-native', resolvedBackendId: overrides?.resolvedBackendId ?? 'codex-native', - availableBackends: - overrides?.availableBackends ?? - [ - { - id: 'codex-native', - label: 'Codex native', - description: 'Use codex exec JSON mode.', - selectable: true, - recommended: true, - available: true, - state: 'ready', - audience: 'general', - statusMessage: 'Codex native ready', - }, - ], + availableBackends: overrides?.availableBackends ?? [ + { + id: 'codex-native', + label: 'Codex native', + description: 'Use codex exec JSON mode.', + selectable: true, + recommended: true, + available: true, + state: 'ready', + audience: 'general', + statusMessage: 'Codex native ready', + }, + ], externalRuntimeDiagnostics: [], backend: overrides?.backend ?? @@ -123,7 +121,8 @@ function createCodexProvider( startedAt: null, }, rateLimits: null, - launchAllowed: Boolean(overrides?.authenticated ?? true) || Boolean(overrides?.apiKeyConfigured), + launchAllowed: + Boolean(overrides?.authenticated ?? true) || Boolean(overrides?.apiKeyConfigured), launchIssueMessage: null, launchReadinessState: Boolean(overrides?.authenticated ?? true) || Boolean(overrides?.apiKeyConfigured) @@ -135,9 +134,7 @@ function createCodexProvider( }; } -function createOpenCodeProvider( - overrides?: Partial -): CliProviderStatus { +function createOpenCodeProvider(overrides?: Partial): CliProviderStatus { return { providerId: 'opencode', displayName: 'OpenCode', @@ -458,7 +455,7 @@ describe('providerConnectionUi', () => { expect(formatProviderStatusText(provider)).toBe('Codex native ready'); }); - it('treats OpenCode inventory-only fallback as still loading', () => { + it('treats OpenCode inventory-only fallback as models available', () => { const provider = createOpenCodeProvider({ supported: false, authenticated: false, @@ -483,7 +480,7 @@ describe('providerConnectionUi', () => { }); expect(isProviderInventoryOnlyFallback(provider)).toBe(true); - expect(formatProviderStatusText(provider)).toBe('Checking...'); + expect(formatProviderStatusText(provider)).toBe('Models available'); }); it('surfaces degraded ChatGPT verification warnings instead of flattening them to ready', () => { @@ -508,7 +505,8 @@ describe('providerConnectionUi', () => { }, rateLimits: null, launchAllowed: true, - launchIssueMessage: 'ChatGPT account detected, but account verification is currently degraded.', + launchIssueMessage: + 'ChatGPT account detected, but account verification is currently degraded.', launchReadinessState: 'warning_degraded_but_launchable', }, });