diff --git a/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts b/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts index 718d68030..4d45fa725 100644 --- a/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +++ b/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts @@ -43,6 +43,7 @@ export class ProviderManagerComponent extends Container implements Focusable { private modelsJsonWriter: ModelsJsonWriter; private onDone: () => void; private onDiscover: (provider: string) => void; + private onSetupAuth: (provider: string) => void; private confirmingRemove = false; private hintsContainer: Container; @@ -52,6 +53,7 @@ export class ProviderManagerComponent extends Container implements Focusable { modelRegistry: ModelRegistry, onDone: () => void, onDiscover: (provider: string) => void, + onSetupAuth?: (provider: string) => void, ) { super(); @@ -61,6 +63,7 @@ export class ProviderManagerComponent extends Container implements Focusable { this.modelsJsonWriter = new ModelsJsonWriter(this.modelRegistry.modelsJsonPath); this.onDone = onDone; this.onDiscover = onDiscover; + this.onSetupAuth = onSetupAuth ?? (() => {}); // Header this.addChild(new Text(theme.fg("accent", "Provider Manager"), 0, 0)); @@ -125,6 +128,7 @@ export class ProviderManagerComponent extends Container implements Focusable { this.hintsContainer.addChild(new Text(hints, 0, 0)); } else { const hints = [ + rawKeyHint("enter", "setup auth"), rawKeyHint("d", "discover"), rawKeyHint("r", "remove auth"), rawKeyHint("esc", "close"), @@ -203,6 +207,12 @@ export class ProviderManagerComponent extends Container implements Focusable { this.tui.requestRender(); } } + } else if (kb.matches(keyData, "selectConfirm")) { + // Enter key → initiate auth setup for the selected provider (#3579) + const provider = this.providers[this.selectedIndex]; + if (provider) { + this.onSetupAuth(provider.name); + } } } } diff --git a/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts b/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts index ca98db678..80255d8de 100644 --- a/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +++ b/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts @@ -3411,6 +3411,11 @@ export class InteractiveMode { done(); this.ui.requestRender(); }, + async (provider: string) => { + // Enter key → auth setup for selected provider (#3579) + done(); + await this.showLoginDialog(provider); + }, ); return { component, focus: component }; }); diff --git a/src/tests/provider-manager-enter-key.test.ts b/src/tests/provider-manager-enter-key.test.ts new file mode 100644 index 000000000..ada68f245 --- /dev/null +++ b/src/tests/provider-manager-enter-key.test.ts @@ -0,0 +1,46 @@ +/** + * Regression test for #3579 — Enter key initiates auth setup in provider manager + * + * The provider manager component did not handle the Enter key, leaving users + * unable to initiate auth setup without knowing the 'd' keyboard shortcut. + * The fix adds a selectConfirm handler that calls onSetupAuth. + * + * Structural verification test — reads source to confirm selectConfirm handler + * and onSetupAuth callback exist in provider-manager.ts. + */ + +import { describe, test } from 'node:test'; +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const source = readFileSync( + join(__dirname, '..', '..', 'packages', 'pi-coding-agent', 'src', 'modes', 'interactive', 'components', 'provider-manager.ts'), + 'utf-8', +); + +describe('provider manager Enter key handler (#3579)', () => { + test('onSetupAuth callback property exists', () => { + assert.match(source, /onSetupAuth/, + 'onSetupAuth callback should be defined'); + }); + + test('selectConfirm key handler exists', () => { + assert.match(source, /selectConfirm/, + 'selectConfirm key binding should be handled'); + }); + + test('onSetupAuth is called with provider name', () => { + assert.match(source, /this\.onSetupAuth\(provider\.name\)/, + 'onSetupAuth should be called with provider.name'); + }); + + test('setup auth hint is shown', () => { + assert.match(source, /setup auth/, + 'enter key hint should mention "setup auth"'); + }); +});