fix: show OpenCode inventory fallback as available

This commit is contained in:
infiniti 2026-05-27 23:00:32 +03:00 committed by GitHub
parent e06c24a041
commit c9e7e49a78
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 67 additions and 29 deletions

View file

@ -884,6 +884,7 @@
}, },
"status": { "status": {
"checking": "Checking...", "checking": "Checking...",
"modelsAvailable": "Models available",
"checked": "Checked", "checked": "Checked",
"providerActivity": "Provider Activity", "providerActivity": "Provider Activity",
"notConnected": "Not connected", "notConnected": "Not connected",

View file

@ -884,6 +884,7 @@
}, },
"status": { "status": {
"checking": "Проверка...", "checking": "Проверка...",
"modelsAvailable": "Модели доступны",
"checked": "Проверено", "checked": "Проверено",
"providerActivity": "Активность провайдеров", "providerActivity": "Активность провайдеров",
"notConnected": "Не подключено", "notConnected": "Не подключено",

View file

@ -2759,6 +2759,7 @@ export default interface Resources {
chatGptVerificationDegraded: 'ChatGPT account detected - account verification is currently degraded.'; chatGptVerificationDegraded: 'ChatGPT account detected - account verification is currently degraded.';
checked: 'Checked'; checked: 'Checked';
checking: 'Checking...'; checking: 'Checking...';
modelsAvailable: 'Models available';
codexLocalAccountNeedsReconnect: 'Codex has a locally selected ChatGPT account, but the current session needs reconnect.'; codexLocalAccountNeedsReconnect: 'Codex has a locally selected ChatGPT account, but the current session needs reconnect.';
codexNativeReady: 'Codex native ready'; codexNativeReady: 'Codex native ready';
codexNativeUnavailable: 'Codex native unavailable'; codexNativeUnavailable: 'Codex native unavailable';

View file

@ -54,6 +54,7 @@ import {
import { import {
formatProviderAuthMethodLabelForProvider, formatProviderAuthMethodLabelForProvider,
formatProviderAuthModeLabelForProvider, formatProviderAuthModeLabelForProvider,
formatProviderStatusText,
getProviderConnectLabel, getProviderConnectLabel,
getProviderCurrentRuntimeSummary, getProviderCurrentRuntimeSummary,
isConnectionManagedRuntimeProvider, isConnectionManagedRuntimeProvider,
@ -414,7 +415,7 @@ function getProviderUsageLabel(
t t
), ),
}) })
: provider.statusMessage || t('providerRuntime.usage.notConnected'); : formatProviderStatusText(provider, t);
} }
function getCompactOpenCodeProviderDetailMessage(detailMessage?: string | null): string | null { function getCompactOpenCodeProviderDetailMessage(detailMessage?: string | null): string | null {
@ -1150,10 +1151,8 @@ export const ProviderRuntimeSettingsDialog = ({
let connectionStatusLabel: string | null = null; let connectionStatusLabel: string | null = null;
if (selectedProvider) { if (selectedProvider) {
if (!hideConnectionMethodMeta && selectedProvider.authenticated) { if (!hideConnectionMethodMeta) {
connectionStatusLabel = getProviderUsageLabel(selectedProvider, t); connectionStatusLabel = getProviderUsageLabel(selectedProvider, t);
} else if (!hideConnectionMethodMeta) {
connectionStatusLabel = t('providerRuntime.usage.notConnected');
} }
} }
const showSelectedProviderSummary = Boolean(selectedProvider) && !connectionManagedRuntime; const showSelectedProviderSummary = Boolean(selectedProvider) && !connectionManagedRuntime;

View file

@ -425,8 +425,8 @@ export function formatProviderStatusText(
if (isProviderInventoryOnlyFallback(provider)) { if (isProviderInventoryOnlyFallback(provider)) {
return translateProviderConnection( return translateProviderConnection(
t, t,
'providerRuntime.connectionUi.status.checking', 'providerRuntime.connectionUi.status.modelsAvailable',
'Checking...' 'Models available'
); );
} }

View file

@ -755,8 +755,9 @@ describe('CLI status visibility during completed install state', () => {
}); });
expect(host.textContent).toContain('OpenCode'); 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).toContain('big-pickle');
expect(host.textContent).not.toContain('Checking...');
expect(host.textContent).not.toContain('Provider status unavailable'); expect(host.textContent).not.toContain('Provider status unavailable');
expect(host.textContent).not.toContain('Models unavailable for this runtime build'); expect(host.textContent).not.toContain('Models unavailable for this runtime build');

View file

@ -1972,4 +1972,41 @@ describe('ProviderRuntimeSettingsDialog', () => {
expect(host.textContent).not.toContain('behavior abc123'); expect(host.textContent).not.toContain('behavior abc123');
expect(host.textContent).not.toContain('Desktop currently exposes status only.'); 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');
});
}); });

View file

@ -80,21 +80,19 @@ function createCodexProvider(
}, },
selectedBackendId: overrides?.selectedBackendId ?? 'codex-native', selectedBackendId: overrides?.selectedBackendId ?? 'codex-native',
resolvedBackendId: overrides?.resolvedBackendId ?? 'codex-native', resolvedBackendId: overrides?.resolvedBackendId ?? 'codex-native',
availableBackends: availableBackends: overrides?.availableBackends ?? [
overrides?.availableBackends ?? {
[ id: 'codex-native',
{ label: 'Codex native',
id: 'codex-native', description: 'Use codex exec JSON mode.',
label: 'Codex native', selectable: true,
description: 'Use codex exec JSON mode.', recommended: true,
selectable: true, available: true,
recommended: true, state: 'ready',
available: true, audience: 'general',
state: 'ready', statusMessage: 'Codex native ready',
audience: 'general', },
statusMessage: 'Codex native ready', ],
},
],
externalRuntimeDiagnostics: [], externalRuntimeDiagnostics: [],
backend: backend:
overrides?.backend ?? overrides?.backend ??
@ -123,7 +121,8 @@ function createCodexProvider(
startedAt: null, startedAt: null,
}, },
rateLimits: null, rateLimits: null,
launchAllowed: Boolean(overrides?.authenticated ?? true) || Boolean(overrides?.apiKeyConfigured), launchAllowed:
Boolean(overrides?.authenticated ?? true) || Boolean(overrides?.apiKeyConfigured),
launchIssueMessage: null, launchIssueMessage: null,
launchReadinessState: launchReadinessState:
Boolean(overrides?.authenticated ?? true) || Boolean(overrides?.apiKeyConfigured) Boolean(overrides?.authenticated ?? true) || Boolean(overrides?.apiKeyConfigured)
@ -135,9 +134,7 @@ function createCodexProvider(
}; };
} }
function createOpenCodeProvider( function createOpenCodeProvider(overrides?: Partial<CliProviderStatus>): CliProviderStatus {
overrides?: Partial<CliProviderStatus>
): CliProviderStatus {
return { return {
providerId: 'opencode', providerId: 'opencode',
displayName: 'OpenCode', displayName: 'OpenCode',
@ -458,7 +455,7 @@ describe('providerConnectionUi', () => {
expect(formatProviderStatusText(provider)).toBe('Codex native ready'); 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({ const provider = createOpenCodeProvider({
supported: false, supported: false,
authenticated: false, authenticated: false,
@ -483,7 +480,7 @@ describe('providerConnectionUi', () => {
}); });
expect(isProviderInventoryOnlyFallback(provider)).toBe(true); 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', () => { it('surfaces degraded ChatGPT verification warnings instead of flattening them to ready', () => {
@ -508,7 +505,8 @@ describe('providerConnectionUi', () => {
}, },
rateLimits: null, rateLimits: null,
launchAllowed: true, 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', launchReadinessState: 'warning_degraded_but_launchable',
}, },
}); });