/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import type React from 'react'; import { useRef, useEffect } from 'react'; import { Box, Text } from 'ink'; import { theme } from '../semantic-colors.js'; import { TextInput } from '../components/shared/TextInput.js'; import { useTextBuffer } from '../components/shared/text-buffer.js'; import { useUIState } from '../contexts/UIStateContext.js'; import { clearApiKey, debugLogger } from '@google/gemini-cli-core'; import { useKeypress } from '../hooks/useKeypress.js'; import { keyMatchers, Command } from '../keyMatchers.js'; interface ApiAuthDialogProps { onSubmit: (apiKey: string) => void; onCancel: () => void; error?: string | null; defaultValue?: string; } export function ApiAuthDialog({ onSubmit, onCancel, error, defaultValue = '', }: ApiAuthDialogProps): React.JSX.Element { const { mainAreaWidth } = useUIState(); const viewportWidth = mainAreaWidth - 8; const pendingPromise = useRef<{ cancel: () => void } | null>(null); useEffect( () => () => { pendingPromise.current?.cancel(); }, [], ); const initialApiKey = defaultValue; const buffer = useTextBuffer({ initialText: initialApiKey || '', initialCursorOffset: initialApiKey?.length || 0, viewport: { width: viewportWidth, height: 4, }, isValidPath: () => false, // No path validation needed for API key inputFilter: (text) => text.replace(/[^a-zA-Z0-9_-]/g, '').replace(/[\r\n]/g, ''), singleLine: true, }); const handleSubmit = (value: string) => { onSubmit(value); }; const handleClear = () => { pendingPromise.current?.cancel(); let isCancelled = false; const wrappedPromise = new Promise((resolve, reject) => { clearApiKey().then( () => !isCancelled && resolve(), (error) => !isCancelled && reject(error), ); }); pendingPromise.current = { cancel: () => { isCancelled = true; }, }; return wrappedPromise .then(() => { buffer.setText(''); }) .catch((err) => { debugLogger.debug('Failed to clear API key:', err); }); }; useKeypress( async (key) => { if (keyMatchers[Command.CLEAR_INPUT](key)) { await handleClear(); } }, { isActive: true }, ); return ( Enter Gemini API Key Please enter your Gemini API key. It will be securely stored in your system keychain. You can get an API key from{' '} https://aistudio.google.com/app/apikey {error && ( {error} )} (Press Enter to submit, Esc to cancel, Ctrl+C to clear stored key) ); }