feat(cli): add support for --prompt-interactive/-i flag (#1743)

This commit is contained in:
Daniel Lee
2025-07-11 16:52:56 -07:00
committed by GitHub
parent 5b5f496436
commit 5b6608ad84
6 changed files with 331 additions and 46 deletions

View File

@@ -14,9 +14,12 @@ import {
ToolRegistry,
AccessibilitySettings,
SandboxConfig,
GeminiClient,
} from '@google/gemini-cli-core';
import { LoadedSettings, SettingsFile, Settings } from '../config/settings.js';
import process from 'node:process';
import { useGeminiStream } from './hooks/useGeminiStream.js';
import { StreamingState } from './types.js';
import { Tips } from './components/Tips.js';
// Define a more complete mock server config based on actual Config
@@ -67,6 +70,7 @@ interface MockServerConfig {
getAccessibility: Mock<() => AccessibilitySettings>;
getProjectRoot: Mock<() => string | undefined>;
getAllGeminiMdFilenames: Mock<() => string[]>;
getGeminiClient: Mock<() => GeminiClient | undefined>;
getUserTier: Mock<() => Promise<string | undefined>>;
}
@@ -124,7 +128,7 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
getVertexAI: vi.fn(() => opts.vertexai),
getShowMemoryUsage: vi.fn(() => opts.showMemoryUsage ?? false),
getAccessibility: vi.fn(() => opts.accessibility ?? {}),
getProjectRoot: vi.fn(() => opts.projectRoot),
getProjectRoot: vi.fn(() => opts.targetDir),
getGeminiClient: vi.fn(() => ({})),
getCheckpointingEnabled: vi.fn(() => opts.checkpointing ?? true),
getAllGeminiMdFilenames: vi.fn(() => ['GEMINI.md']),
@@ -508,4 +512,48 @@ describe('App UI', () => {
expect(lastFrame()).not.toContain('Select Theme');
});
});
describe('with initial prompt from --prompt-interactive', () => {
it('should submit the initial prompt automatically', async () => {
const mockSubmitQuery = vi.fn();
mockConfig.getQuestion = vi.fn(() => 'hello from prompt-interactive');
vi.mocked(useGeminiStream).mockReturnValue({
streamingState: StreamingState.Idle,
submitQuery: mockSubmitQuery,
initError: null,
pendingHistoryItems: [],
thought: null,
});
mockConfig.getGeminiClient.mockReturnValue({
isInitialized: vi.fn(() => true),
} as unknown as GeminiClient);
const { unmount, rerender } = render(
<App
config={mockConfig as unknown as ServerConfig}
settings={mockSettings}
version={mockVersion}
/>,
);
currentUnmount = unmount;
// Force a re-render to trigger useEffect
rerender(
<App
config={mockConfig as unknown as ServerConfig}
settings={mockSettings}
version={mockVersion}
/>,
);
await new Promise((resolve) => setTimeout(resolve, 0));
expect(mockSubmitQuery).toHaveBeenCalledWith(
'hello from prompt-interactive',
);
});
});
});

View File

@@ -148,6 +148,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
const openPrivacyNotice = useCallback(() => {
setShowPrivacyNotice(true);
}, []);
const initialPromptSubmitted = useRef(false);
const errorCount = useMemo(
() => consoleMessages.filter((msg) => msg.type === 'error').length,
@@ -637,6 +638,34 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
return getAllGeminiMdFilenames();
}, [settings.merged.contextFileName]);
const initialPrompt = useMemo(() => config.getQuestion(), [config]);
const geminiClient = config.getGeminiClient();
useEffect(() => {
if (
initialPrompt &&
!initialPromptSubmitted.current &&
!isAuthenticating &&
!isAuthDialogOpen &&
!isThemeDialogOpen &&
!isEditorDialogOpen &&
!showPrivacyNotice &&
geminiClient?.isInitialized?.()
) {
submitQuery(initialPrompt);
initialPromptSubmitted.current = true;
}
}, [
initialPrompt,
submitQuery,
isAuthenticating,
isAuthDialogOpen,
isThemeDialogOpen,
isEditorDialogOpen,
showPrivacyNotice,
geminiClient,
]);
if (quittingMessages) {
return (
<Box flexDirection="column" marginBottom={1}>