fix(tui): only offer auth_mode prompt after successful credential storage

Introduce a `credentialStored` flag in all 4 credential paths (OpenAI
API key, OpenAI OAuth, Anthropic auth token, Anthropic API key). The
auth_mode prompt is now gated on `credentialStored`, so a failed store
call no longer falls through to prompt the user for an auth mode that
was never set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
William Valentin
2026-02-26 09:40:58 -08:00
parent 7d0c59b16f
commit 7004a1a805
+12 -4
View File
@@ -1178,12 +1178,14 @@ export class MinimalTui {
console.log(`${colors.gray}Create a key at:${colors.reset} https://platform.openai.com/api-keys`); console.log(`${colors.gray}Create a key at:${colors.reset} https://platform.openai.com/api-keys`);
console.log(''); console.log('');
let credentialStored = false;
try { try {
this.rl.pause(); this.rl.pause();
const apiKey = await promptHidden('Enter OpenAI API key: '); const apiKey = await promptHidden('Enter OpenAI API key: ');
storeOpenAIApiKey(apiKey); storeOpenAIApiKey(apiKey);
console.log(''); console.log('');
console.log(`${colors.gray}OpenAI API key stored in ~/.config/flynn/auth.json${colors.reset}\n`); console.log(`${colors.gray}OpenAI API key stored in ~/.config/flynn/auth.json${colors.reset}\n`);
credentialStored = true;
} catch (error) { } catch (error) {
const message = error instanceof Error ? error.message : String(error); const message = error instanceof Error ? error.message : String(error);
console.log(`${colors.gray}OpenAI API key storage failed:${colors.reset} ${message}\n`); console.log(`${colors.gray}OpenAI API key storage failed:${colors.reset} ${message}\n`);
@@ -1192,7 +1194,7 @@ export class MinimalTui {
} }
// Offer to set auth_mode if config is available // Offer to set auth_mode if config is available
if (this.config.currentConfig && this.config.configPath) { if (credentialStored && this.config.currentConfig && this.config.configPath) {
const modeInput = (await this.prompt( const modeInput = (await this.prompt(
`${colors.orange}Set active auth mode?${colors.reset} ${colors.gray}[api_key/oauth/auto/skip] (default: skip):${colors.reset} `, `${colors.orange}Set active auth mode?${colors.reset} ${colors.gray}[api_key/oauth/auto/skip] (default: skip):${colors.reset} `,
)).trim().toLowerCase(); )).trim().toLowerCase();
@@ -1218,6 +1220,7 @@ export class MinimalTui {
console.log(`${colors.gray}Starting OpenAI OAuth device flow...${colors.reset}`); console.log(`${colors.gray}Starting OpenAI OAuth device flow...${colors.reset}`);
let credentialStored = false;
try { try {
await loginOpenAI((userCode, verificationUri) => { await loginOpenAI((userCode, verificationUri) => {
console.log(''); console.log('');
@@ -1228,13 +1231,14 @@ export class MinimalTui {
}); });
console.log(`${colors.gray}OpenAI authentication successful! Token stored.${colors.reset}\n`); console.log(`${colors.gray}OpenAI authentication successful! Token stored.${colors.reset}\n`);
credentialStored = true;
} catch (error) { } catch (error) {
const message = error instanceof Error ? error.message : String(error); const message = error instanceof Error ? error.message : String(error);
console.log(`${colors.gray}OpenAI login failed:${colors.reset} ${message}\n`); console.log(`${colors.gray}OpenAI login failed:${colors.reset} ${message}\n`);
} }
// Offer to set auth_mode if config is available // Offer to set auth_mode if config is available
if (this.config.currentConfig && this.config.configPath) { if (credentialStored && this.config.currentConfig && this.config.configPath) {
const modeInput = (await this.prompt( const modeInput = (await this.prompt(
`${colors.orange}Set active auth mode?${colors.reset} ${colors.gray}[api_key/oauth/auto/skip] (default: skip):${colors.reset} `, `${colors.orange}Set active auth mode?${colors.reset} ${colors.gray}[api_key/oauth/auto/skip] (default: skip):${colors.reset} `,
)).trim().toLowerCase(); )).trim().toLowerCase();
@@ -1270,12 +1274,14 @@ export class MinimalTui {
console.log(`${colors.gray}Anthropic supports token-style auth (provider-specific).${colors.reset}`); console.log(`${colors.gray}Anthropic supports token-style auth (provider-specific).${colors.reset}`);
console.log(''); console.log('');
let credentialStored = false;
try { try {
this.rl.pause(); this.rl.pause();
const token = await promptHidden('Enter Anthropic auth token: '); const token = await promptHidden('Enter Anthropic auth token: ');
storeAnthropicAuthToken(token); storeAnthropicAuthToken(token);
console.log(''); console.log('');
console.log(`${colors.gray}Anthropic auth token stored in ~/.config/flynn/auth.json${colors.reset}\n`); console.log(`${colors.gray}Anthropic auth token stored in ~/.config/flynn/auth.json${colors.reset}\n`);
credentialStored = true;
} catch (error) { } catch (error) {
const message = error instanceof Error ? error.message : String(error); const message = error instanceof Error ? error.message : String(error);
console.log(`${colors.gray}Anthropic auth failed:${colors.reset} ${message}\n`); console.log(`${colors.gray}Anthropic auth failed:${colors.reset} ${message}\n`);
@@ -1284,7 +1290,7 @@ export class MinimalTui {
} }
// Offer to set auth_mode if config is available // Offer to set auth_mode if config is available
if (this.config.currentConfig && this.config.configPath) { if (credentialStored && this.config.currentConfig && this.config.configPath) {
const modeInput = (await this.prompt( const modeInput = (await this.prompt(
`${colors.orange}Set active auth mode?${colors.reset} ${colors.gray}[api_key/oauth/auto/skip] (default: skip):${colors.reset} `, `${colors.orange}Set active auth mode?${colors.reset} ${colors.gray}[api_key/oauth/auto/skip] (default: skip):${colors.reset} `,
)).trim().toLowerCase(); )).trim().toLowerCase();
@@ -1311,12 +1317,14 @@ export class MinimalTui {
console.log(`${colors.gray}Create a key at:${colors.reset} https://console.anthropic.com/settings/keys`); console.log(`${colors.gray}Create a key at:${colors.reset} https://console.anthropic.com/settings/keys`);
console.log(''); console.log('');
let credentialStored = false;
try { try {
this.rl.pause(); this.rl.pause();
const apiKey = await promptHidden('Enter Anthropic API key: '); const apiKey = await promptHidden('Enter Anthropic API key: ');
storeAnthropicAuth(apiKey); storeAnthropicAuth(apiKey);
console.log(''); console.log('');
console.log(`${colors.gray}Anthropic API key stored in ~/.config/flynn/auth.json${colors.reset}\n`); console.log(`${colors.gray}Anthropic API key stored in ~/.config/flynn/auth.json${colors.reset}\n`);
credentialStored = true;
} catch (error) { } catch (error) {
const message = error instanceof Error ? error.message : String(error); const message = error instanceof Error ? error.message : String(error);
console.log(`${colors.gray}Anthropic auth failed:${colors.reset} ${message}\n`); console.log(`${colors.gray}Anthropic auth failed:${colors.reset} ${message}\n`);
@@ -1325,7 +1333,7 @@ export class MinimalTui {
} }
// Offer to set auth_mode if config is available // Offer to set auth_mode if config is available
if (this.config.currentConfig && this.config.configPath) { if (credentialStored && this.config.currentConfig && this.config.configPath) {
const modeInput = (await this.prompt( const modeInput = (await this.prompt(
`${colors.orange}Set active auth mode?${colors.reset} ${colors.gray}[api_key/oauth/auto/skip] (default: skip):${colors.reset} `, `${colors.orange}Set active auth mode?${colors.reset} ${colors.gray}[api_key/oauth/auto/skip] (default: skip):${colors.reset} `,
)).trim().toLowerCase(); )).trim().toLowerCase();