diff --git a/packages/cli/src/ui/auth/AuthDialog.test.tsx b/packages/cli/src/ui/auth/AuthDialog.test.tsx index 1de5f7236..561d5b0b2 100644 --- a/packages/cli/src/ui/auth/AuthDialog.test.tsx +++ b/packages/cli/src/ui/auth/AuthDialog.test.tsx @@ -558,121 +558,4 @@ describe('AuthDialog', () => { expect(handleAuthSelect).toHaveBeenCalledWith(undefined); unmount(); }); - - it('shows API Key subtype menu and opens custom info', async () => { - const settings: LoadedSettings = new LoadedSettings( - { - settings: { ui: { customThemes: {} }, mcpServers: {} }, - originalSettings: { ui: { customThemes: {} }, mcpServers: {} }, - path: '', - }, - { - settings: {}, - originalSettings: {}, - path: '', - }, - { - settings: { - security: { auth: { selectedType: undefined } }, - ui: { customThemes: {} }, - mcpServers: {}, - }, - originalSettings: { - security: { auth: { selectedType: undefined } }, - ui: { customThemes: {} }, - mcpServers: {}, - }, - path: '', - }, - { - settings: { ui: { customThemes: {} }, mcpServers: {} }, - originalSettings: { ui: { customThemes: {} }, mcpServers: {} }, - path: '', - }, - true, - new Set(), - ); - - const { stdin, lastFrame, unmount } = renderAuthDialog(settings); - await wait(); - - // Move from Qwen OAuth -> Coding Plan -> API Key, then enter - stdin.write('\u001B[B'); - stdin.write('\u001B[B'); - stdin.write('\r'); - await wait(); - - expect(lastFrame()).toContain('Select API Key Type'); - expect(lastFrame()).toContain('Alibaba Cloud ModelStudio Standard API Key'); - expect(lastFrame()).toContain('Custom API Key'); - - // Move to Custom API Key and enter - stdin.write('\u001B[B'); - stdin.write('\r'); - await wait(); - - expect(lastFrame()).toContain('Custom Configuration'); - unmount(); - }); - - it('shows Alibaba Cloud ModelStudio Standard API Key region endpoint', async () => { - const settings: LoadedSettings = new LoadedSettings( - { - settings: { ui: { customThemes: {} }, mcpServers: {} }, - originalSettings: { ui: { customThemes: {} }, mcpServers: {} }, - path: '', - }, - { - settings: {}, - originalSettings: {}, - path: '', - }, - { - settings: { - security: { auth: { selectedType: undefined } }, - ui: { customThemes: {} }, - mcpServers: {}, - }, - originalSettings: { - security: { auth: { selectedType: undefined } }, - ui: { customThemes: {} }, - mcpServers: {}, - }, - path: '', - }, - { - settings: { ui: { customThemes: {} }, mcpServers: {} }, - originalSettings: { ui: { customThemes: {} }, mcpServers: {} }, - path: '', - }, - true, - new Set(), - ); - - const { stdin, lastFrame, unmount } = renderAuthDialog(settings, {}, {}); - await wait(); - - // Main -> API Key - stdin.write('\u001B[B'); - stdin.write('\u001B[B'); - stdin.write('\r'); - await wait(); - - // API Key type -> Alibaba Cloud ModelStudio Standard API Key (default) - stdin.write('\r'); - await wait(); - - // Region -> Singapore - stdin.write('\u001B[B'); - stdin.write('\r'); - await wait(); - - expect(lastFrame()).toContain( - 'Enter Alibaba Cloud ModelStudio Standard API Key', - ); - expect(lastFrame()).toContain( - 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1', - ); - unmount(); - }); }); diff --git a/packages/cli/src/ui/contexts/KeypressContext.tsx b/packages/cli/src/ui/contexts/KeypressContext.tsx index 97db27563..e81747957 100644 --- a/packages/cli/src/ui/contexts/KeypressContext.tsx +++ b/packages/cli/src/ui/contexts/KeypressContext.tsx @@ -540,7 +540,16 @@ export function KeypressProvider({ } }; + // Matches terminal query responses (DA1, DA2, Kitty protocol query) + // that may arrive late from startup detection in kittyProtocolDetector. + // These are never valid user input. + // eslint-disable-next-line no-control-regex + const TERMINAL_RESPONSE_RE = /^\x1b\[[?>][\d;]*[uc]$/; + const handleKeypress = async (_: unknown, key: Key) => { + if (TERMINAL_RESPONSE_RE.test(key.sequence)) { + return; + } if (key.sequence === FOCUS_IN || key.sequence === FOCUS_OUT) { return; } diff --git a/packages/cli/src/ui/utils/kittyProtocolDetector.ts b/packages/cli/src/ui/utils/kittyProtocolDetector.ts index 3355330a6..a46390603 100644 --- a/packages/cli/src/ui/utils/kittyProtocolDetector.ts +++ b/packages/cli/src/ui/utils/kittyProtocolDetector.ts @@ -37,11 +37,20 @@ export async function detectAndEnableKittyProtocol(): Promise { const onTimeout = () => { timeoutId = undefined; process.stdin.removeListener('data', handleData); - if (!originalRawMode) { - process.stdin.setRawMode(false); - } - detectionComplete = true; - resolve(false); + + // Keep a drain handler briefly to consume any late-arriving terminal + // responses that would otherwise leak into the application input. + const drainHandler = () => {}; + process.stdin.on('data', drainHandler); + + setTimeout(() => { + process.stdin.removeListener('data', drainHandler); + if (!originalRawMode) { + process.stdin.setRawMode(false); + } + detectionComplete = true; + resolve(false); + }, 100); }; const handleData = (data: Buffer) => {