From f828171ef1ab94e2acf73a28a292799e4e26cc0d Mon Sep 17 00:00:00 2001 From: Kevin Codex Date: Mon, 20 Apr 2026 06:46:05 +0800 Subject: [PATCH] fix: allow provider recovery during startup (#765) --- src/entrypoints/cli.tsx | 4 +-- src/utils/providerValidation.test.ts | 47 +++++++++++++++++++++++++++- src/utils/providerValidation.ts | 41 ++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 3 deletions(-) diff --git a/src/entrypoints/cli.tsx b/src/entrypoints/cli.tsx index 457975f1..9536c266 100644 --- a/src/entrypoints/cli.tsx +++ b/src/entrypoints/cli.tsx @@ -5,7 +5,7 @@ import { } from '../utils/providerProfile.js' import { getProviderValidationError, - validateProviderEnvOrExit, + validateProviderEnvForStartupOrExit, } from '../utils/providerValidation.js' // OpenClaude: polyfill globalThis.File for Node < 20. @@ -132,7 +132,7 @@ async function main(): Promise { hydrateGithubModelsTokenFromSecureStorage() } - await validateProviderEnvOrExit() + await validateProviderEnvForStartupOrExit() // Print the gradient startup screen before the Ink UI loads const { printStartupScreen } = await import('../components/StartupScreen.js') diff --git a/src/utils/providerValidation.test.ts b/src/utils/providerValidation.test.ts index d88fef77..f5314251 100644 --- a/src/utils/providerValidation.test.ts +++ b/src/utils/providerValidation.test.ts @@ -1,6 +1,9 @@ import { afterEach, expect, test } from 'bun:test' -import { getProviderValidationError } from './providerValidation.ts' +import { + getProviderValidationError, + shouldExitForStartupProviderValidationError, +} from './providerValidation.ts' const originalEnv = { CLAUDE_CODE_USE_OPENAI: process.env.CLAUDE_CODE_USE_OPENAI, @@ -93,3 +96,45 @@ test('openai missing key error includes recovery guidance and config locations', expect(message).toContain('Saved startup settings can come from') expect(message).toContain('.openclaude-profile.json') }) + +test('startup provider validation allows interactive recovery', () => { + expect( + shouldExitForStartupProviderValidationError({ + args: [], + stdoutIsTTY: true, + }), + ).toBe(false) +}) + +test('startup provider validation stays strict for non-interactive launches', () => { + expect( + shouldExitForStartupProviderValidationError({ + args: ['-p', 'hello'], + stdoutIsTTY: true, + }), + ).toBe(true) + expect( + shouldExitForStartupProviderValidationError({ + args: ['--print', 'hello'], + stdoutIsTTY: true, + }), + ).toBe(true) + expect( + shouldExitForStartupProviderValidationError({ + args: [], + stdoutIsTTY: false, + }), + ).toBe(true) + expect( + shouldExitForStartupProviderValidationError({ + args: ['--sdk-url', 'ws://127.0.0.1:3000'], + stdoutIsTTY: true, + }), + ).toBe(true) + expect( + shouldExitForStartupProviderValidationError({ + args: ['--sdk-url=ws://127.0.0.1:3000'], + stdoutIsTTY: true, + }), + ).toBe(true) +}) diff --git a/src/utils/providerValidation.ts b/src/utils/providerValidation.ts index fa671388..b726ee9d 100644 --- a/src/utils/providerValidation.ts +++ b/src/utils/providerValidation.ts @@ -169,3 +169,44 @@ export async function validateProviderEnvOrExit( process.exit(1) } } + +export function shouldExitForStartupProviderValidationError(options: { + args?: string[] + stdoutIsTTY?: boolean +} = {}): boolean { + const args = options.args ?? process.argv.slice(2) + const stdoutIsTTY = options.stdoutIsTTY ?? process.stdout.isTTY + + if (!stdoutIsTTY) { + return true + } + + return ( + args.includes('-p') || + args.includes('--print') || + args.includes('--init-only') || + args.some(arg => arg.startsWith('--sdk-url')) + ) +} + +export async function validateProviderEnvForStartupOrExit( + env: NodeJS.ProcessEnv = process.env, + options?: { + args?: string[] + stdoutIsTTY?: boolean + }, +): Promise { + const error = await getProviderValidationError(env) + if (!error) { + return + } + + if (shouldExitForStartupProviderValidationError(options)) { + console.error(error) + process.exit(1) + } + + console.error( + `Warning: provider configuration is incomplete.\n${error}\nOpenClaude will continue starting so you can run /provider and repair the saved provider settings.`, + ) +}