@google/gemini-cli 0.4.0-preview.2 → 0.5.0-nightly.20250908.4693137b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/google-gemini-cli-0.3.4.tgz +0 -0
- package/dist/package.json +2 -2
- package/dist/src/commands/extensions/install.js +3 -3
- package/dist/src/commands/extensions/install.js.map +1 -1
- package/dist/src/commands/extensions/install.test.js +2 -2
- package/dist/src/commands/extensions/install.test.js.map +1 -1
- package/dist/src/config/config.js +13 -11
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/extension.js +2 -1
- package/dist/src/config/extension.js.map +1 -1
- package/dist/src/config/settings.js +2 -13
- package/dist/src/config/settings.js.map +1 -1
- package/dist/src/config/settingsSchema.d.ts +19 -1
- package/dist/src/config/settingsSchema.js +20 -1
- package/dist/src/config/settingsSchema.js.map +1 -1
- package/dist/src/core/auth.d.ts +13 -0
- package/dist/src/core/auth.js +27 -0
- package/dist/src/core/auth.js.map +1 -0
- package/dist/src/core/initializer.d.ts +21 -0
- package/dist/src/core/initializer.js +28 -0
- package/dist/src/core/initializer.js.map +1 -0
- package/dist/src/core/theme.d.ts +12 -0
- package/dist/src/core/theme.js +20 -0
- package/dist/src/core/theme.js.map +1 -0
- package/dist/src/gemini.d.ts +2 -1
- package/dist/src/gemini.js +37 -7
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/gemini.test.js +91 -14
- package/dist/src/gemini.test.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/services/BuiltinCommandLoader.test.js +16 -17
- package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -1
- package/dist/src/ui/App.d.ts +1 -10
- package/dist/src/ui/App.js +13 -729
- package/dist/src/ui/App.js.map +1 -1
- package/dist/src/ui/AppContainer.d.ts +17 -0
- package/dist/src/ui/AppContainer.js +932 -0
- package/dist/src/ui/AppContainer.js.map +1 -0
- package/dist/src/ui/AppContainer.test.js +195 -0
- package/dist/src/ui/AppContainer.test.js.map +1 -0
- package/dist/src/ui/auth/AuthDialog.d.ts +18 -0
- package/dist/src/ui/{components → auth}/AuthDialog.js +35 -34
- package/dist/src/ui/auth/AuthDialog.js.map +1 -0
- package/dist/src/ui/auth/AuthDialog.test.d.ts +6 -0
- package/dist/src/ui/auth/AuthDialog.test.js +184 -0
- package/dist/src/ui/auth/AuthDialog.test.js.map +1 -0
- package/dist/src/ui/auth/AuthInProgress.js.map +1 -0
- package/dist/src/ui/auth/useAuth.d.ts +15 -0
- package/dist/src/ui/auth/useAuth.js +73 -0
- package/dist/src/ui/auth/useAuth.js.map +1 -0
- package/dist/src/ui/commands/corgiCommand.js +1 -0
- package/dist/src/ui/commands/corgiCommand.js.map +1 -1
- package/dist/src/ui/commands/mcpCommand.js +1 -1
- package/dist/src/ui/commands/mcpCommand.js.map +1 -1
- package/dist/src/ui/commands/types.d.ts +1 -0
- package/dist/src/ui/components/AppHeader.d.ts +10 -0
- package/dist/src/ui/components/AppHeader.js +19 -0
- package/dist/src/ui/components/AppHeader.js.map +1 -0
- package/dist/src/ui/components/Composer.d.ts +6 -0
- package/dist/src/ui/components/Composer.js +68 -0
- package/dist/src/ui/components/Composer.js.map +1 -0
- package/dist/src/ui/components/Composer.test.d.ts +6 -0
- package/dist/src/ui/components/Composer.test.js +340 -0
- package/dist/src/ui/components/Composer.test.js.map +1 -0
- package/dist/src/ui/components/DialogManager.d.ts +6 -0
- package/dist/src/ui/components/DialogManager.js +82 -0
- package/dist/src/ui/components/DialogManager.js.map +1 -0
- package/dist/src/ui/components/Footer.d.ts +1 -5
- package/dist/src/ui/components/Footer.js +3 -4
- package/dist/src/ui/components/Footer.js.map +1 -1
- package/dist/src/ui/components/Help.d.ts +1 -1
- package/dist/src/ui/components/Help.js +6 -3
- package/dist/src/ui/components/Help.js.map +1 -1
- package/dist/src/ui/components/Help.test.d.ts +6 -0
- package/dist/src/ui/components/Help.test.js +57 -0
- package/dist/src/ui/components/Help.test.js.map +1 -0
- package/dist/src/ui/components/HistoryItemDisplay.d.ts +0 -2
- package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.js +25 -3
- package/dist/src/ui/components/InputPrompt.js.map +1 -1
- package/dist/src/ui/components/MainContent.d.ts +6 -0
- package/dist/src/ui/components/MainContent.js +23 -0
- package/dist/src/ui/components/MainContent.js.map +1 -0
- package/dist/src/ui/components/Notifications.d.ts +6 -0
- package/dist/src/ui/components/Notifications.js +23 -0
- package/dist/src/ui/components/Notifications.js.map +1 -0
- package/dist/src/ui/components/QuittingDisplay.d.ts +6 -0
- package/dist/src/ui/components/QuittingDisplay.js +20 -0
- package/dist/src/ui/components/QuittingDisplay.js.map +1 -0
- package/dist/src/ui/components/SuggestionsDisplay.d.ts +2 -0
- package/dist/src/ui/components/SuggestionsDisplay.js +6 -12
- package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.d.ts +0 -2
- package/dist/src/ui/components/messages/ToolGroupMessage.js +7 -5
- package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js +17 -15
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
- package/dist/src/ui/contexts/AppContext.d.ts +11 -0
- package/dist/src/ui/contexts/AppContext.js +15 -0
- package/dist/src/ui/contexts/AppContext.js.map +1 -0
- package/dist/src/ui/contexts/ConfigContext.d.ts +9 -0
- package/dist/src/ui/contexts/ConfigContext.js +16 -0
- package/dist/src/ui/contexts/ConfigContext.js.map +1 -0
- package/dist/src/ui/contexts/KeypressContext.d.ts +3 -0
- package/dist/src/ui/contexts/KeypressContext.js +51 -2
- package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
- package/dist/src/ui/contexts/KeypressContext.test.js +173 -1
- package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
- package/dist/src/ui/contexts/UIActionsContext.d.ts +36 -0
- package/dist/src/ui/contexts/UIActionsContext.js +20 -0
- package/dist/src/ui/contexts/UIActionsContext.js.map +1 -0
- package/dist/src/ui/contexts/UIStateContext.d.ts +85 -0
- package/dist/src/ui/contexts/UIStateContext.js +15 -0
- package/dist/src/ui/contexts/UIStateContext.js.map +1 -0
- package/dist/src/ui/hooks/atCommandProcessor.test.js +7 -5
- package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.d.ts +13 -2
- package/dist/src/ui/hooks/slashCommandProcessor.js +13 -25
- package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/useFolderTrust.d.ts +2 -1
- package/dist/src/ui/hooks/useFolderTrust.js +10 -24
- package/dist/src/ui/hooks/useFolderTrust.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.d.ts +1 -1
- package/dist/src/ui/hooks/useGeminiStream.js +1 -1
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useReactToolScheduler.js +2 -0
- package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
- package/dist/src/ui/hooks/useSlashCompletion.js +4 -2
- package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
- package/dist/src/ui/hooks/useSlashCompletion.test.js +155 -268
- package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useThemeCommand.d.ts +1 -1
- package/dist/src/ui/hooks/useThemeCommand.js +3 -14
- package/dist/src/ui/hooks/useThemeCommand.js.map +1 -1
- package/dist/src/ui/hooks/useToolScheduler.test.js +6 -1
- package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
- package/dist/src/ui/hooks/useWorkspaceMigration.js +2 -1
- package/dist/src/ui/hooks/useWorkspaceMigration.js.map +1 -1
- package/dist/src/ui/types.d.ts +17 -1
- package/dist/src/ui/types.js +10 -0
- package/dist/src/ui/types.js.map +1 -1
- package/dist/src/ui/utils/highlight.d.ts +1 -1
- package/dist/src/ui/utils/highlight.js +15 -6
- package/dist/src/ui/utils/highlight.js.map +1 -1
- package/dist/src/ui/utils/highlight.test.js +56 -29
- package/dist/src/ui/utils/highlight.test.js.map +1 -1
- package/dist/src/ui/utils/kittyProtocolDetector.js +39 -29
- package/dist/src/ui/utils/kittyProtocolDetector.js.map +1 -1
- package/dist/src/zed-integration/schema.d.ts +592 -592
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/dist/google-gemini-cli-0.4.0-preview.1.tgz +0 -0
- package/dist/src/ui/components/AuthDialog.d.ts +0 -16
- package/dist/src/ui/components/AuthDialog.js.map +0 -1
- package/dist/src/ui/components/AuthDialog.test.js +0 -307
- package/dist/src/ui/components/AuthDialog.test.js.map +0 -1
- package/dist/src/ui/components/AuthInProgress.js.map +0 -1
- package/dist/src/ui/hooks/useAuthCommand.d.ts +0 -14
- package/dist/src/ui/hooks/useAuthCommand.js +0 -66
- package/dist/src/ui/hooks/useAuthCommand.js.map +0 -1
- /package/dist/src/ui/{components/AuthDialog.test.d.ts → AppContainer.test.d.ts} +0 -0
- /package/dist/src/ui/{components → auth}/AuthInProgress.d.ts +0 -0
- /package/dist/src/ui/{components → auth}/AuthInProgress.js +0 -0
package/dist/src/ui/App.js
CHANGED
|
@@ -1,738 +1,22 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* @license
|
|
4
4
|
* Copyright 2025 Google LLC
|
|
5
5
|
* SPDX-License-Identifier: Apache-2.0
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import { Box, measureElement, Static, Text, useStdin, useStdout, } from 'ink';
|
|
9
|
-
import { StreamingState, MessageType, ToolCallStatus, } from './types.js';
|
|
10
|
-
import { useTerminalSize } from './hooks/useTerminalSize.js';
|
|
11
|
-
import { useGeminiStream } from './hooks/useGeminiStream.js';
|
|
12
|
-
import { useLoadingIndicator } from './hooks/useLoadingIndicator.js';
|
|
13
|
-
import { useThemeCommand } from './hooks/useThemeCommand.js';
|
|
14
|
-
import { useAuthCommand } from './hooks/useAuthCommand.js';
|
|
15
|
-
import { useFolderTrust } from './hooks/useFolderTrust.js';
|
|
16
|
-
import { useIdeTrustListener } from './hooks/useIdeTrustListener.js';
|
|
17
|
-
import { useEditorSettings } from './hooks/useEditorSettings.js';
|
|
18
|
-
import { useSlashCommandProcessor } from './hooks/slashCommandProcessor.js';
|
|
19
|
-
import { useAutoAcceptIndicator } from './hooks/useAutoAcceptIndicator.js';
|
|
20
|
-
import { useMessageQueue } from './hooks/useMessageQueue.js';
|
|
21
|
-
import { useConsoleMessages } from './hooks/useConsoleMessages.js';
|
|
22
|
-
import { Header } from './components/Header.js';
|
|
23
|
-
import { LoadingIndicator } from './components/LoadingIndicator.js';
|
|
24
|
-
import { AutoAcceptIndicator } from './components/AutoAcceptIndicator.js';
|
|
25
|
-
import { ShellModeIndicator } from './components/ShellModeIndicator.js';
|
|
26
|
-
import { InputPrompt } from './components/InputPrompt.js';
|
|
27
|
-
import { Footer } from './components/Footer.js';
|
|
28
|
-
import { ThemeDialog } from './components/ThemeDialog.js';
|
|
29
|
-
import { AuthDialog } from './components/AuthDialog.js';
|
|
30
|
-
import { AuthInProgress } from './components/AuthInProgress.js';
|
|
31
|
-
import { EditorSettingsDialog } from './components/EditorSettingsDialog.js';
|
|
32
|
-
import { FolderTrustDialog } from './components/FolderTrustDialog.js';
|
|
33
|
-
import { ShellConfirmationDialog } from './components/ShellConfirmationDialog.js';
|
|
34
|
-
import { RadioButtonSelect } from './components/shared/RadioButtonSelect.js';
|
|
35
|
-
import { Colors } from './colors.js';
|
|
36
|
-
import { loadHierarchicalGeminiMemory } from '../config/config.js';
|
|
37
|
-
import { SettingScope } from '../config/settings.js';
|
|
38
|
-
import { Tips } from './components/Tips.js';
|
|
39
|
-
import { ConsolePatcher } from './utils/ConsolePatcher.js';
|
|
40
|
-
import { registerCleanup } from '../utils/cleanup.js';
|
|
41
|
-
import { DetailedMessagesDisplay } from './components/DetailedMessagesDisplay.js';
|
|
42
|
-
import { HistoryItemDisplay } from './components/HistoryItemDisplay.js';
|
|
43
|
-
import { ContextSummaryDisplay } from './components/ContextSummaryDisplay.js';
|
|
44
|
-
import { useHistory } from './hooks/useHistoryManager.js';
|
|
45
|
-
import { useInputHistoryStore } from './hooks/useInputHistoryStore.js';
|
|
46
|
-
import process from 'node:process';
|
|
47
|
-
import { ApprovalMode, getAllGeminiMdFilenames, isEditorAvailable, getErrorMessage, AuthType, logFlashFallback, FlashFallbackEvent, ideContext, isProQuotaExceededError, isGenericQuotaExceededError, UserTierId, DEFAULT_GEMINI_FLASH_MODEL, IdeClient, } from '@google/gemini-cli-core';
|
|
48
|
-
import { IdeIntegrationNudge } from './IdeIntegrationNudge.js';
|
|
49
|
-
import { validateAuthMethod } from '../config/auth.js';
|
|
50
|
-
import { useLogger } from './hooks/useLogger.js';
|
|
7
|
+
import { Box } from 'ink';
|
|
51
8
|
import { StreamingContext } from './contexts/StreamingContext.js';
|
|
52
|
-
import {
|
|
53
|
-
import {
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
-
import {
|
|
57
|
-
import {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
import { keyMatchers, Command } from './keyMatchers.js';
|
|
63
|
-
import * as fs from 'node:fs';
|
|
64
|
-
import { UpdateNotification } from './components/UpdateNotification.js';
|
|
65
|
-
import ansiEscapes from 'ansi-escapes';
|
|
66
|
-
import { OverflowProvider } from './contexts/OverflowContext.js';
|
|
67
|
-
import { ShowMoreLines } from './components/ShowMoreLines.js';
|
|
68
|
-
import { PrivacyNotice } from './privacy/PrivacyNotice.js';
|
|
69
|
-
import { useSettingsCommand } from './hooks/useSettingsCommand.js';
|
|
70
|
-
import { SettingsDialog } from './components/SettingsDialog.js';
|
|
71
|
-
import { ProQuotaDialog } from './components/ProQuotaDialog.js';
|
|
72
|
-
import { setUpdateHandler } from '../utils/handleAutoUpdate.js';
|
|
73
|
-
import { appEvents, AppEvent } from '../utils/events.js';
|
|
74
|
-
import { isNarrowWidth } from './utils/isNarrowWidth.js';
|
|
75
|
-
import { useWorkspaceMigration } from './hooks/useWorkspaceMigration.js';
|
|
76
|
-
import { WorkspaceMigrationDialog } from './components/WorkspaceMigrationDialog.js';
|
|
77
|
-
import { isWorkspaceTrusted } from '../config/trustedFolders.js';
|
|
78
|
-
const CTRL_EXIT_PROMPT_DURATION_MS = 1000;
|
|
79
|
-
// Maximum number of queued messages to display in UI to prevent performance issues
|
|
80
|
-
const MAX_DISPLAYED_QUEUED_MESSAGES = 3;
|
|
81
|
-
function isToolExecuting(pendingHistoryItems) {
|
|
82
|
-
return pendingHistoryItems.some((item) => {
|
|
83
|
-
if (item && item.type === 'tool_group') {
|
|
84
|
-
return item.tools.some((tool) => ToolCallStatus.Executing === tool.status);
|
|
85
|
-
}
|
|
86
|
-
return false;
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
export const AppWrapper = (props) => {
|
|
90
|
-
const kittyProtocolStatus = useKittyKeyboardProtocol();
|
|
91
|
-
return (_jsx(KeypressProvider, { kittyProtocolEnabled: kittyProtocolStatus.enabled, config: props.config, debugKeystrokeLogging: props.settings.merged.general?.debugKeystrokeLogging, children: _jsx(SessionStatsProvider, { children: _jsx(VimModeProvider, { settings: props.settings, children: _jsx(App, { ...props }) }) }) }));
|
|
92
|
-
};
|
|
93
|
-
const App = ({ config, settings, startupWarnings = [], version }) => {
|
|
94
|
-
const isFocused = useFocus();
|
|
95
|
-
useBracketedPaste();
|
|
96
|
-
const [updateInfo, setUpdateInfo] = useState(null);
|
|
97
|
-
const { stdout } = useStdout();
|
|
98
|
-
const nightly = version.includes('nightly');
|
|
99
|
-
const { history, addItem, clearItems, loadHistory } = useHistory();
|
|
100
|
-
const [idePromptAnswered, setIdePromptAnswered] = useState(false);
|
|
101
|
-
const [currentIDE, setCurrentIDE] = useState();
|
|
102
|
-
useEffect(() => {
|
|
103
|
-
(async () => {
|
|
104
|
-
const ideClient = await IdeClient.getInstance();
|
|
105
|
-
setCurrentIDE(ideClient.getCurrentIde());
|
|
106
|
-
})();
|
|
107
|
-
registerCleanup(async () => {
|
|
108
|
-
const ideClient = await IdeClient.getInstance();
|
|
109
|
-
ideClient.disconnect();
|
|
110
|
-
});
|
|
111
|
-
}, [config]);
|
|
112
|
-
const shouldShowIdePrompt = currentIDE &&
|
|
113
|
-
!config.getIdeMode() &&
|
|
114
|
-
!settings.merged.ide?.hasSeenNudge &&
|
|
115
|
-
!idePromptAnswered;
|
|
116
|
-
useEffect(() => {
|
|
117
|
-
const cleanup = setUpdateHandler(addItem, setUpdateInfo);
|
|
118
|
-
return cleanup;
|
|
119
|
-
}, [addItem]);
|
|
120
|
-
const { consoleMessages, handleNewMessage, clearConsoleMessages: clearConsoleMessagesState, } = useConsoleMessages();
|
|
121
|
-
useEffect(() => {
|
|
122
|
-
const consolePatcher = new ConsolePatcher({
|
|
123
|
-
onNewMessage: handleNewMessage,
|
|
124
|
-
debugMode: config.getDebugMode(),
|
|
125
|
-
});
|
|
126
|
-
consolePatcher.patch();
|
|
127
|
-
registerCleanup(consolePatcher.cleanup);
|
|
128
|
-
}, [handleNewMessage, config]);
|
|
129
|
-
const { stats: sessionStats } = useSessionStats();
|
|
130
|
-
const [staticNeedsRefresh, setStaticNeedsRefresh] = useState(false);
|
|
131
|
-
const [staticKey, setStaticKey] = useState(0);
|
|
132
|
-
const refreshStatic = useCallback(() => {
|
|
133
|
-
stdout.write(ansiEscapes.clearTerminal);
|
|
134
|
-
setStaticKey((prev) => prev + 1);
|
|
135
|
-
}, [setStaticKey, stdout]);
|
|
136
|
-
const [geminiMdFileCount, setGeminiMdFileCount] = useState(0);
|
|
137
|
-
const [debugMessage, setDebugMessage] = useState('');
|
|
138
|
-
const [themeError, setThemeError] = useState(null);
|
|
139
|
-
const [authError, setAuthError] = useState(null);
|
|
140
|
-
const [editorError, setEditorError] = useState(null);
|
|
141
|
-
const [footerHeight, setFooterHeight] = useState(0);
|
|
142
|
-
const [corgiMode, setCorgiMode] = useState(false);
|
|
143
|
-
const [isTrustedFolderState, setIsTrustedFolder] = useState(isWorkspaceTrusted(settings.merged));
|
|
144
|
-
const [currentModel, setCurrentModel] = useState(config.getModel());
|
|
145
|
-
const [shellModeActive, setShellModeActive] = useState(false);
|
|
146
|
-
const [showErrorDetails, setShowErrorDetails] = useState(false);
|
|
147
|
-
const [showToolDescriptions, setShowToolDescriptions] = useState(false);
|
|
148
|
-
const [ctrlCPressedOnce, setCtrlCPressedOnce] = useState(false);
|
|
149
|
-
const [quittingMessages, setQuittingMessages] = useState(null);
|
|
150
|
-
const ctrlCTimerRef = useRef(null);
|
|
151
|
-
const [ctrlDPressedOnce, setCtrlDPressedOnce] = useState(false);
|
|
152
|
-
const ctrlDTimerRef = useRef(null);
|
|
153
|
-
const [constrainHeight, setConstrainHeight] = useState(true);
|
|
154
|
-
const [showPrivacyNotice, setShowPrivacyNotice] = useState(false);
|
|
155
|
-
const [modelSwitchedFromQuotaError, setModelSwitchedFromQuotaError] = useState(false);
|
|
156
|
-
const [userTier, setUserTier] = useState(undefined);
|
|
157
|
-
const [ideContextState, setIdeContextState] = useState();
|
|
158
|
-
const [showEscapePrompt, setShowEscapePrompt] = useState(false);
|
|
159
|
-
const [showIdeRestartPrompt, setShowIdeRestartPrompt] = useState(false);
|
|
160
|
-
const [isProcessing, setIsProcessing] = useState(false);
|
|
161
|
-
const { showWorkspaceMigrationDialog, workspaceExtensions, onWorkspaceMigrationDialogOpen, onWorkspaceMigrationDialogClose, } = useWorkspaceMigration(settings);
|
|
162
|
-
const [isProQuotaDialogOpen, setIsProQuotaDialogOpen] = useState(false);
|
|
163
|
-
const [proQuotaDialogResolver, setProQuotaDialogResolver] = useState(null);
|
|
164
|
-
useEffect(() => {
|
|
165
|
-
const unsubscribe = ideContext.subscribeToIdeContext(setIdeContextState);
|
|
166
|
-
// Set the initial value
|
|
167
|
-
setIdeContextState(ideContext.getIdeContext());
|
|
168
|
-
return unsubscribe;
|
|
169
|
-
}, []);
|
|
170
|
-
useEffect(() => {
|
|
171
|
-
const openDebugConsole = () => {
|
|
172
|
-
setShowErrorDetails(true);
|
|
173
|
-
setConstrainHeight(false); // Make sure the user sees the full message.
|
|
174
|
-
};
|
|
175
|
-
appEvents.on(AppEvent.OpenDebugConsole, openDebugConsole);
|
|
176
|
-
const logErrorHandler = (errorMessage) => {
|
|
177
|
-
handleNewMessage({
|
|
178
|
-
type: 'error',
|
|
179
|
-
content: String(errorMessage),
|
|
180
|
-
count: 1,
|
|
181
|
-
});
|
|
182
|
-
};
|
|
183
|
-
appEvents.on(AppEvent.LogError, logErrorHandler);
|
|
184
|
-
return () => {
|
|
185
|
-
appEvents.off(AppEvent.OpenDebugConsole, openDebugConsole);
|
|
186
|
-
appEvents.off(AppEvent.LogError, logErrorHandler);
|
|
187
|
-
};
|
|
188
|
-
}, [handleNewMessage]);
|
|
189
|
-
const openPrivacyNotice = useCallback(() => {
|
|
190
|
-
setShowPrivacyNotice(true);
|
|
191
|
-
}, []);
|
|
192
|
-
const handleEscapePromptChange = useCallback((showPrompt) => {
|
|
193
|
-
setShowEscapePrompt(showPrompt);
|
|
194
|
-
}, []);
|
|
195
|
-
const initialPromptSubmitted = useRef(false);
|
|
196
|
-
const errorCount = useMemo(() => consoleMessages
|
|
197
|
-
.filter((msg) => msg.type === 'error')
|
|
198
|
-
.reduce((total, msg) => total + msg.count, 0), [consoleMessages]);
|
|
199
|
-
const { isThemeDialogOpen, openThemeDialog, handleThemeSelect, handleThemeHighlight, } = useThemeCommand(settings, setThemeError, addItem);
|
|
200
|
-
const { isSettingsDialogOpen, openSettingsDialog, closeSettingsDialog } = useSettingsCommand();
|
|
201
|
-
const { isFolderTrustDialogOpen, handleFolderTrustSelect, isRestarting } = useFolderTrust(settings, setIsTrustedFolder);
|
|
202
|
-
const { needsRestart: ideNeedsRestart } = useIdeTrustListener();
|
|
203
|
-
useEffect(() => {
|
|
204
|
-
if (ideNeedsRestart) {
|
|
205
|
-
// IDE trust changed, force a restart.
|
|
206
|
-
setShowIdeRestartPrompt(true);
|
|
207
|
-
}
|
|
208
|
-
}, [ideNeedsRestart]);
|
|
209
|
-
useKeypress((key) => {
|
|
210
|
-
if (key.name === 'r' || key.name === 'R') {
|
|
211
|
-
process.exit(0);
|
|
212
|
-
}
|
|
213
|
-
}, { isActive: showIdeRestartPrompt });
|
|
214
|
-
const { isAuthDialogOpen, openAuthDialog, handleAuthSelect, isAuthenticating, cancelAuthentication, } = useAuthCommand(settings, setAuthError, config);
|
|
215
|
-
useEffect(() => {
|
|
216
|
-
if (settings.merged.security?.auth?.enforcedType &&
|
|
217
|
-
settings.merged.security?.auth.selectedType &&
|
|
218
|
-
settings.merged.security?.auth.enforcedType !==
|
|
219
|
-
settings.merged.security?.auth.selectedType) {
|
|
220
|
-
setAuthError(`Authentication is enforced to be ${settings.merged.security?.auth.enforcedType}, but you are currently using ${settings.merged.security?.auth.selectedType}.`);
|
|
221
|
-
openAuthDialog();
|
|
222
|
-
}
|
|
223
|
-
else if (settings.merged.security?.auth?.selectedType &&
|
|
224
|
-
!settings.merged.security?.auth?.useExternal) {
|
|
225
|
-
const error = validateAuthMethod(settings.merged.security.auth.selectedType);
|
|
226
|
-
if (error) {
|
|
227
|
-
setAuthError(error);
|
|
228
|
-
openAuthDialog();
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}, [
|
|
232
|
-
settings.merged.security?.auth?.selectedType,
|
|
233
|
-
settings.merged.security?.auth?.enforcedType,
|
|
234
|
-
settings.merged.security?.auth?.useExternal,
|
|
235
|
-
openAuthDialog,
|
|
236
|
-
setAuthError,
|
|
237
|
-
]);
|
|
238
|
-
// Sync user tier from config when authentication changes
|
|
239
|
-
useEffect(() => {
|
|
240
|
-
// Only sync when not currently authenticating
|
|
241
|
-
if (!isAuthenticating) {
|
|
242
|
-
setUserTier(config.getGeminiClient()?.getUserTier());
|
|
243
|
-
}
|
|
244
|
-
}, [config, isAuthenticating]);
|
|
245
|
-
const { isEditorDialogOpen, openEditorDialog, handleEditorSelect, exitEditorDialog, } = useEditorSettings(settings, setEditorError, addItem);
|
|
246
|
-
const toggleCorgiMode = useCallback(() => {
|
|
247
|
-
setCorgiMode((prev) => !prev);
|
|
248
|
-
}, []);
|
|
249
|
-
const performMemoryRefresh = useCallback(async () => {
|
|
250
|
-
addItem({
|
|
251
|
-
type: MessageType.INFO,
|
|
252
|
-
text: 'Refreshing hierarchical memory (GEMINI.md or other context files)...',
|
|
253
|
-
}, Date.now());
|
|
254
|
-
try {
|
|
255
|
-
const { memoryContent, fileCount } = await loadHierarchicalGeminiMemory(process.cwd(), settings.merged.context?.loadMemoryFromIncludeDirectories
|
|
256
|
-
? config.getWorkspaceContext().getDirectories()
|
|
257
|
-
: [], config.getDebugMode(), config.getFileService(), settings.merged, config.getExtensionContextFilePaths(), config.getFolderTrust(), settings.merged.context?.importFormat || 'tree', // Use setting or default to 'tree'
|
|
258
|
-
config.getFileFilteringOptions());
|
|
259
|
-
config.setUserMemory(memoryContent);
|
|
260
|
-
config.setGeminiMdFileCount(fileCount);
|
|
261
|
-
setGeminiMdFileCount(fileCount);
|
|
262
|
-
addItem({
|
|
263
|
-
type: MessageType.INFO,
|
|
264
|
-
text: `Memory refreshed successfully. ${memoryContent.length > 0 ? `Loaded ${memoryContent.length} characters from ${fileCount} file(s).` : 'No memory content found.'}`,
|
|
265
|
-
}, Date.now());
|
|
266
|
-
if (config.getDebugMode()) {
|
|
267
|
-
console.log(`[DEBUG] Refreshed memory content in config: ${memoryContent.substring(0, 200)}...`);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
catch (error) {
|
|
271
|
-
const errorMessage = getErrorMessage(error);
|
|
272
|
-
addItem({
|
|
273
|
-
type: MessageType.ERROR,
|
|
274
|
-
text: `Error refreshing memory: ${errorMessage}`,
|
|
275
|
-
}, Date.now());
|
|
276
|
-
console.error('Error refreshing memory:', error);
|
|
277
|
-
}
|
|
278
|
-
}, [config, addItem, settings.merged]);
|
|
279
|
-
// Watch for model changes (e.g., from Flash fallback)
|
|
280
|
-
useEffect(() => {
|
|
281
|
-
const checkModelChange = () => {
|
|
282
|
-
const configModel = config.getModel();
|
|
283
|
-
if (configModel !== currentModel) {
|
|
284
|
-
setCurrentModel(configModel);
|
|
285
|
-
}
|
|
286
|
-
};
|
|
287
|
-
// Check immediately and then periodically
|
|
288
|
-
checkModelChange();
|
|
289
|
-
const interval = setInterval(checkModelChange, 1000); // Check every second
|
|
290
|
-
return () => clearInterval(interval);
|
|
291
|
-
}, [config, currentModel]);
|
|
292
|
-
// Set up Flash fallback handler
|
|
293
|
-
useEffect(() => {
|
|
294
|
-
const flashFallbackHandler = async (currentModel, fallbackModel, error) => {
|
|
295
|
-
// Check if we've already switched to the fallback model
|
|
296
|
-
if (config.isInFallbackMode()) {
|
|
297
|
-
// If we're already in fallback mode, don't show the dialog again
|
|
298
|
-
return false;
|
|
299
|
-
}
|
|
300
|
-
let message;
|
|
301
|
-
if (config.getContentGeneratorConfig().authType ===
|
|
302
|
-
AuthType.LOGIN_WITH_GOOGLE) {
|
|
303
|
-
// Use actual user tier if available; otherwise, default to FREE tier behavior (safe default)
|
|
304
|
-
const isPaidTier = userTier === UserTierId.LEGACY || userTier === UserTierId.STANDARD;
|
|
305
|
-
// Check if this is a Pro quota exceeded error
|
|
306
|
-
if (error && isProQuotaExceededError(error)) {
|
|
307
|
-
if (isPaidTier) {
|
|
308
|
-
message = `⚡ You have reached your daily ${currentModel} quota limit.
|
|
309
|
-
⚡ You can choose to authenticate with a paid API key or continue with the fallback model.
|
|
310
|
-
⚡ To continue accessing the ${currentModel} model today, consider using /auth to switch to using a paid API key from AI Studio at https://aistudio.google.com/apikey`;
|
|
311
|
-
}
|
|
312
|
-
else {
|
|
313
|
-
message = `⚡ You have reached your daily ${currentModel} quota limit.
|
|
314
|
-
⚡ You can choose to authenticate with a paid API key or continue with the fallback model.
|
|
315
|
-
⚡ To increase your limits, upgrade to a Gemini Code Assist Standard or Enterprise plan with higher limits at https://goo.gle/set-up-gemini-code-assist
|
|
316
|
-
⚡ Or you can utilize a Gemini API Key. See: https://goo.gle/gemini-cli-docs-auth#gemini-api-key
|
|
317
|
-
⚡ You can switch authentication methods by typing /auth`;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
else if (error && isGenericQuotaExceededError(error)) {
|
|
321
|
-
if (isPaidTier) {
|
|
322
|
-
message = `⚡ You have reached your daily quota limit.
|
|
323
|
-
⚡ Automatically switching from ${currentModel} to ${fallbackModel} for the remainder of this session.
|
|
324
|
-
⚡ To continue accessing the ${currentModel} model today, consider using /auth to switch to using a paid API key from AI Studio at https://aistudio.google.com/apikey`;
|
|
325
|
-
}
|
|
326
|
-
else {
|
|
327
|
-
message = `⚡ You have reached your daily quota limit.
|
|
328
|
-
⚡ Automatically switching from ${currentModel} to ${fallbackModel} for the remainder of this session.
|
|
329
|
-
⚡ To increase your limits, upgrade to a Gemini Code Assist Standard or Enterprise plan with higher limits at https://goo.gle/set-up-gemini-code-assist
|
|
330
|
-
⚡ Or you can utilize a Gemini API Key. See: https://goo.gle/gemini-cli-docs-auth#gemini-api-key
|
|
331
|
-
⚡ You can switch authentication methods by typing /auth`;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
else {
|
|
335
|
-
if (isPaidTier) {
|
|
336
|
-
// Default fallback message for other cases (like consecutive 429s)
|
|
337
|
-
message = `⚡ Automatically switching from ${currentModel} to ${fallbackModel} for faster responses for the remainder of this session.
|
|
338
|
-
⚡ Possible reasons for this are that you have received multiple consecutive capacity errors or you have reached your daily ${currentModel} quota limit
|
|
339
|
-
⚡ To continue accessing the ${currentModel} model today, consider using /auth to switch to using a paid API key from AI Studio at https://aistudio.google.com/apikey`;
|
|
340
|
-
}
|
|
341
|
-
else {
|
|
342
|
-
// Default fallback message for other cases (like consecutive 429s)
|
|
343
|
-
message = `⚡ Automatically switching from ${currentModel} to ${fallbackModel} for faster responses for the remainder of this session.
|
|
344
|
-
⚡ Possible reasons for this are that you have received multiple consecutive capacity errors or you have reached your daily ${currentModel} quota limit
|
|
345
|
-
⚡ To increase your limits, upgrade to a Gemini Code Assist Standard or Enterprise plan with higher limits at https://goo.gle/set-up-gemini-code-assist
|
|
346
|
-
⚡ Or you can utilize a Gemini API Key. See: https://goo.gle/gemini-cli-docs-auth#gemini-api-key
|
|
347
|
-
⚡ You can switch authentication methods by typing /auth`;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
// Add message to UI history
|
|
351
|
-
addItem({
|
|
352
|
-
type: MessageType.INFO,
|
|
353
|
-
text: message,
|
|
354
|
-
}, Date.now());
|
|
355
|
-
// For Pro quota errors, show the dialog and wait for user's choice
|
|
356
|
-
if (error && isProQuotaExceededError(error)) {
|
|
357
|
-
// Set the flag to prevent tool continuation
|
|
358
|
-
setModelSwitchedFromQuotaError(true);
|
|
359
|
-
// Set global quota error flag to prevent Flash model calls
|
|
360
|
-
config.setQuotaErrorOccurred(true);
|
|
361
|
-
// Show the ProQuotaDialog and wait for user's choice
|
|
362
|
-
const shouldContinueWithFallback = await new Promise((resolve) => {
|
|
363
|
-
setIsProQuotaDialogOpen(true);
|
|
364
|
-
setProQuotaDialogResolver(() => resolve);
|
|
365
|
-
});
|
|
366
|
-
// If user chose to continue with fallback, we don't need to stop the current prompt
|
|
367
|
-
if (shouldContinueWithFallback) {
|
|
368
|
-
// Switch to fallback model for future use
|
|
369
|
-
config.setModel(fallbackModel);
|
|
370
|
-
config.setFallbackMode(true);
|
|
371
|
-
logFlashFallback(config, new FlashFallbackEvent(config.getContentGeneratorConfig().authType));
|
|
372
|
-
return true; // Continue with current prompt using fallback model
|
|
373
|
-
}
|
|
374
|
-
// If user chose to authenticate, stop current prompt
|
|
375
|
-
return false;
|
|
376
|
-
}
|
|
377
|
-
// For other quota errors, automatically switch to fallback model
|
|
378
|
-
// Set the flag to prevent tool continuation
|
|
379
|
-
setModelSwitchedFromQuotaError(true);
|
|
380
|
-
// Set global quota error flag to prevent Flash model calls
|
|
381
|
-
config.setQuotaErrorOccurred(true);
|
|
382
|
-
}
|
|
383
|
-
// Switch model for future use but return false to stop current retry
|
|
384
|
-
config.setModel(fallbackModel);
|
|
385
|
-
config.setFallbackMode(true);
|
|
386
|
-
logFlashFallback(config, new FlashFallbackEvent(config.getContentGeneratorConfig().authType));
|
|
387
|
-
return false; // Don't continue with current prompt
|
|
388
|
-
};
|
|
389
|
-
config.setFlashFallbackHandler(flashFallbackHandler);
|
|
390
|
-
}, [config, addItem, userTier]);
|
|
391
|
-
// Terminal and UI setup
|
|
392
|
-
const { rows: terminalHeight, columns: terminalWidth } = useTerminalSize();
|
|
393
|
-
const isNarrow = isNarrowWidth(terminalWidth);
|
|
394
|
-
const { stdin, setRawMode } = useStdin();
|
|
395
|
-
const isInitialMount = useRef(true);
|
|
396
|
-
const widthFraction = 0.9;
|
|
397
|
-
const inputWidth = Math.max(20, Math.floor(terminalWidth * widthFraction) - 3);
|
|
398
|
-
const suggestionsWidth = Math.max(20, Math.floor(terminalWidth * 0.8));
|
|
399
|
-
// Utility callbacks
|
|
400
|
-
const isValidPath = useCallback((filePath) => {
|
|
401
|
-
try {
|
|
402
|
-
return fs.existsSync(filePath) && fs.statSync(filePath).isFile();
|
|
403
|
-
}
|
|
404
|
-
catch (_e) {
|
|
405
|
-
return false;
|
|
406
|
-
}
|
|
407
|
-
}, []);
|
|
408
|
-
const getPreferredEditor = useCallback(() => {
|
|
409
|
-
const editorType = settings.merged.general?.preferredEditor;
|
|
410
|
-
const isValidEditor = isEditorAvailable(editorType);
|
|
411
|
-
if (!isValidEditor) {
|
|
412
|
-
openEditorDialog();
|
|
413
|
-
return;
|
|
414
|
-
}
|
|
415
|
-
return editorType;
|
|
416
|
-
}, [settings, openEditorDialog]);
|
|
417
|
-
const onAuthError = useCallback(() => {
|
|
418
|
-
setAuthError('reauth required');
|
|
419
|
-
openAuthDialog();
|
|
420
|
-
}, [openAuthDialog, setAuthError]);
|
|
421
|
-
// Core hooks and processors
|
|
422
|
-
const { vimEnabled: vimModeEnabled, vimMode, toggleVimEnabled, } = useVimMode();
|
|
423
|
-
const { handleSlashCommand, slashCommands, pendingHistoryItems: pendingSlashCommandHistoryItems, commandContext, shellConfirmationRequest, confirmationRequest, } = useSlashCommandProcessor(config, settings, addItem, clearItems, loadHistory, refreshStatic, setDebugMessage, openThemeDialog, openAuthDialog, openEditorDialog, toggleCorgiMode, setQuittingMessages, openPrivacyNotice, openSettingsDialog, toggleVimEnabled, setIsProcessing, setGeminiMdFileCount);
|
|
424
|
-
const buffer = useTextBuffer({
|
|
425
|
-
initialText: '',
|
|
426
|
-
viewport: { height: 10, width: inputWidth },
|
|
427
|
-
stdin,
|
|
428
|
-
setRawMode,
|
|
429
|
-
isValidPath,
|
|
430
|
-
shellModeActive,
|
|
431
|
-
});
|
|
432
|
-
// Independent input history management (unaffected by /clear)
|
|
433
|
-
const inputHistoryStore = useInputHistoryStore();
|
|
434
|
-
// Stable reference for cancel handler to avoid circular dependency
|
|
435
|
-
const cancelHandlerRef = useRef(() => { });
|
|
436
|
-
const { streamingState, submitQuery, initError, pendingHistoryItems: pendingGeminiHistoryItems, thought, cancelOngoingRequest, } = useGeminiStream(config.getGeminiClient(), history, addItem, config, settings, setDebugMessage, handleSlashCommand, shellModeActive, getPreferredEditor, onAuthError, performMemoryRefresh, modelSwitchedFromQuotaError, setModelSwitchedFromQuotaError, refreshStatic, () => cancelHandlerRef.current());
|
|
437
|
-
const pendingHistoryItems = useMemo(() => [...pendingSlashCommandHistoryItems, ...pendingGeminiHistoryItems], [pendingSlashCommandHistoryItems, pendingGeminiHistoryItems]);
|
|
438
|
-
// Message queue for handling input during streaming
|
|
439
|
-
const { messageQueue, addMessage, clearQueue, getQueuedMessagesText } = useMessageQueue({
|
|
440
|
-
streamingState,
|
|
441
|
-
submitQuery,
|
|
442
|
-
});
|
|
443
|
-
// Update the cancel handler with message queue support
|
|
444
|
-
cancelHandlerRef.current = useCallback(() => {
|
|
445
|
-
if (isToolExecuting(pendingHistoryItems)) {
|
|
446
|
-
buffer.setText(''); // Just clear the prompt
|
|
447
|
-
return;
|
|
448
|
-
}
|
|
449
|
-
const lastUserMessage = inputHistoryStore.inputHistory.at(-1);
|
|
450
|
-
let textToSet = lastUserMessage || '';
|
|
451
|
-
// Append queued messages if any exist
|
|
452
|
-
const queuedText = getQueuedMessagesText();
|
|
453
|
-
if (queuedText) {
|
|
454
|
-
textToSet = textToSet ? `${textToSet}\n\n${queuedText}` : queuedText;
|
|
455
|
-
clearQueue();
|
|
456
|
-
}
|
|
457
|
-
if (textToSet) {
|
|
458
|
-
buffer.setText(textToSet);
|
|
459
|
-
}
|
|
460
|
-
}, [
|
|
461
|
-
buffer,
|
|
462
|
-
inputHistoryStore.inputHistory,
|
|
463
|
-
getQueuedMessagesText,
|
|
464
|
-
clearQueue,
|
|
465
|
-
pendingHistoryItems,
|
|
466
|
-
]);
|
|
467
|
-
// Input handling - queue messages for processing
|
|
468
|
-
const handleFinalSubmit = useCallback((submittedValue) => {
|
|
469
|
-
const trimmedValue = submittedValue.trim();
|
|
470
|
-
if (trimmedValue.length > 0) {
|
|
471
|
-
// Add to independent input history
|
|
472
|
-
inputHistoryStore.addInput(trimmedValue);
|
|
473
|
-
}
|
|
474
|
-
// Always add to message queue
|
|
475
|
-
addMessage(submittedValue);
|
|
476
|
-
}, [addMessage, inputHistoryStore]);
|
|
477
|
-
const handleIdePromptComplete = useCallback((result) => {
|
|
478
|
-
if (result.userSelection === 'yes') {
|
|
479
|
-
if (result.isExtensionPreInstalled) {
|
|
480
|
-
handleSlashCommand('/ide enable');
|
|
481
|
-
}
|
|
482
|
-
else {
|
|
483
|
-
handleSlashCommand('/ide install');
|
|
484
|
-
}
|
|
485
|
-
settings.setValue(SettingScope.User, 'hasSeenIdeIntegrationNudge', true);
|
|
486
|
-
}
|
|
487
|
-
else if (result.userSelection === 'dismiss') {
|
|
488
|
-
settings.setValue(SettingScope.User, 'hasSeenIdeIntegrationNudge', true);
|
|
489
|
-
}
|
|
490
|
-
setIdePromptAnswered(true);
|
|
491
|
-
}, [handleSlashCommand, settings]);
|
|
492
|
-
const { handleInput: vimHandleInput } = useVim(buffer, handleFinalSubmit);
|
|
493
|
-
const { elapsedTime, currentLoadingPhrase } = useLoadingIndicator(streamingState, settings.merged.ui?.customWittyPhrases);
|
|
494
|
-
const showAutoAcceptIndicator = useAutoAcceptIndicator({ config, addItem });
|
|
495
|
-
const handleExit = useCallback((pressedOnce, setPressedOnce, timerRef) => {
|
|
496
|
-
if (pressedOnce) {
|
|
497
|
-
if (timerRef.current) {
|
|
498
|
-
clearTimeout(timerRef.current);
|
|
499
|
-
}
|
|
500
|
-
// Directly invoke the central command handler.
|
|
501
|
-
handleSlashCommand('/quit');
|
|
502
|
-
}
|
|
503
|
-
else {
|
|
504
|
-
setPressedOnce(true);
|
|
505
|
-
timerRef.current = setTimeout(() => {
|
|
506
|
-
setPressedOnce(false);
|
|
507
|
-
timerRef.current = null;
|
|
508
|
-
}, CTRL_EXIT_PROMPT_DURATION_MS);
|
|
509
|
-
}
|
|
510
|
-
}, [handleSlashCommand]);
|
|
511
|
-
const handleGlobalKeypress = useCallback((key) => {
|
|
512
|
-
// Debug log keystrokes if enabled
|
|
513
|
-
if (settings.merged.general?.debugKeystrokeLogging) {
|
|
514
|
-
console.log('[DEBUG] Keystroke:', JSON.stringify(key));
|
|
515
|
-
}
|
|
516
|
-
let enteringConstrainHeightMode = false;
|
|
517
|
-
if (!constrainHeight) {
|
|
518
|
-
enteringConstrainHeightMode = true;
|
|
519
|
-
setConstrainHeight(true);
|
|
520
|
-
}
|
|
521
|
-
if (keyMatchers[Command.SHOW_ERROR_DETAILS](key)) {
|
|
522
|
-
setShowErrorDetails((prev) => !prev);
|
|
523
|
-
}
|
|
524
|
-
else if (keyMatchers[Command.TOGGLE_TOOL_DESCRIPTIONS](key)) {
|
|
525
|
-
const newValue = !showToolDescriptions;
|
|
526
|
-
setShowToolDescriptions(newValue);
|
|
527
|
-
const mcpServers = config.getMcpServers();
|
|
528
|
-
if (Object.keys(mcpServers || {}).length > 0) {
|
|
529
|
-
handleSlashCommand(newValue ? '/mcp desc' : '/mcp nodesc');
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
else if (keyMatchers[Command.TOGGLE_IDE_CONTEXT_DETAIL](key) &&
|
|
533
|
-
config.getIdeMode() &&
|
|
534
|
-
ideContextState) {
|
|
535
|
-
// Show IDE status when in IDE mode and context is available.
|
|
536
|
-
handleSlashCommand('/ide status');
|
|
537
|
-
}
|
|
538
|
-
else if (keyMatchers[Command.QUIT](key)) {
|
|
539
|
-
// When authenticating, let AuthInProgress component handle Ctrl+C.
|
|
540
|
-
if (isAuthenticating) {
|
|
541
|
-
return;
|
|
542
|
-
}
|
|
543
|
-
if (!ctrlCPressedOnce) {
|
|
544
|
-
cancelOngoingRequest?.();
|
|
545
|
-
}
|
|
546
|
-
handleExit(ctrlCPressedOnce, setCtrlCPressedOnce, ctrlCTimerRef);
|
|
547
|
-
}
|
|
548
|
-
else if (keyMatchers[Command.EXIT](key)) {
|
|
549
|
-
if (buffer.text.length > 0) {
|
|
550
|
-
return;
|
|
551
|
-
}
|
|
552
|
-
handleExit(ctrlDPressedOnce, setCtrlDPressedOnce, ctrlDTimerRef);
|
|
553
|
-
}
|
|
554
|
-
else if (keyMatchers[Command.SHOW_MORE_LINES](key) &&
|
|
555
|
-
!enteringConstrainHeightMode) {
|
|
556
|
-
setConstrainHeight(false);
|
|
557
|
-
}
|
|
558
|
-
}, [
|
|
559
|
-
constrainHeight,
|
|
560
|
-
setConstrainHeight,
|
|
561
|
-
setShowErrorDetails,
|
|
562
|
-
showToolDescriptions,
|
|
563
|
-
setShowToolDescriptions,
|
|
564
|
-
config,
|
|
565
|
-
ideContextState,
|
|
566
|
-
handleExit,
|
|
567
|
-
ctrlCPressedOnce,
|
|
568
|
-
setCtrlCPressedOnce,
|
|
569
|
-
ctrlCTimerRef,
|
|
570
|
-
buffer.text.length,
|
|
571
|
-
ctrlDPressedOnce,
|
|
572
|
-
setCtrlDPressedOnce,
|
|
573
|
-
ctrlDTimerRef,
|
|
574
|
-
handleSlashCommand,
|
|
575
|
-
isAuthenticating,
|
|
576
|
-
cancelOngoingRequest,
|
|
577
|
-
settings.merged.general?.debugKeystrokeLogging,
|
|
578
|
-
]);
|
|
579
|
-
useKeypress(handleGlobalKeypress, {
|
|
580
|
-
isActive: true,
|
|
581
|
-
});
|
|
582
|
-
useEffect(() => {
|
|
583
|
-
if (config) {
|
|
584
|
-
setGeminiMdFileCount(config.getGeminiMdFileCount());
|
|
585
|
-
}
|
|
586
|
-
}, [config, config.getGeminiMdFileCount]);
|
|
587
|
-
const logger = useLogger(config.storage);
|
|
588
|
-
// Initialize independent input history from logger
|
|
589
|
-
useEffect(() => {
|
|
590
|
-
inputHistoryStore.initializeFromLogger(logger);
|
|
591
|
-
}, [logger, inputHistoryStore]);
|
|
592
|
-
const isInputActive = (streamingState === StreamingState.Idle ||
|
|
593
|
-
streamingState === StreamingState.Responding) &&
|
|
594
|
-
!initError &&
|
|
595
|
-
!isProcessing &&
|
|
596
|
-
!isProQuotaDialogOpen;
|
|
597
|
-
const handleClearScreen = useCallback(() => {
|
|
598
|
-
clearItems();
|
|
599
|
-
clearConsoleMessagesState();
|
|
600
|
-
console.clear();
|
|
601
|
-
refreshStatic();
|
|
602
|
-
}, [clearItems, clearConsoleMessagesState, refreshStatic]);
|
|
603
|
-
const mainControlsRef = useRef(null);
|
|
604
|
-
const pendingHistoryItemRef = useRef(null);
|
|
605
|
-
useEffect(() => {
|
|
606
|
-
if (mainControlsRef.current) {
|
|
607
|
-
const fullFooterMeasurement = measureElement(mainControlsRef.current);
|
|
608
|
-
setFooterHeight(fullFooterMeasurement.height);
|
|
609
|
-
}
|
|
610
|
-
}, [terminalHeight, consoleMessages, showErrorDetails]);
|
|
611
|
-
const staticExtraHeight = /* margins and padding */ 3;
|
|
612
|
-
const availableTerminalHeight = useMemo(() => terminalHeight - footerHeight - staticExtraHeight, [terminalHeight, footerHeight]);
|
|
613
|
-
useEffect(() => {
|
|
614
|
-
// skip refreshing Static during first mount
|
|
615
|
-
if (isInitialMount.current) {
|
|
616
|
-
isInitialMount.current = false;
|
|
617
|
-
return;
|
|
618
|
-
}
|
|
619
|
-
// debounce so it doesn't fire up too often during resize
|
|
620
|
-
const handler = setTimeout(() => {
|
|
621
|
-
setStaticNeedsRefresh(false);
|
|
622
|
-
refreshStatic();
|
|
623
|
-
}, 300);
|
|
624
|
-
return () => {
|
|
625
|
-
clearTimeout(handler);
|
|
626
|
-
};
|
|
627
|
-
}, [terminalWidth, terminalHeight, refreshStatic]);
|
|
628
|
-
useEffect(() => {
|
|
629
|
-
if (streamingState === StreamingState.Idle && staticNeedsRefresh) {
|
|
630
|
-
setStaticNeedsRefresh(false);
|
|
631
|
-
refreshStatic();
|
|
632
|
-
}
|
|
633
|
-
}, [streamingState, refreshStatic, staticNeedsRefresh]);
|
|
634
|
-
const filteredConsoleMessages = useMemo(() => {
|
|
635
|
-
if (config.getDebugMode()) {
|
|
636
|
-
return consoleMessages;
|
|
637
|
-
}
|
|
638
|
-
return consoleMessages.filter((msg) => msg.type !== 'debug');
|
|
639
|
-
}, [consoleMessages, config]);
|
|
640
|
-
const branchName = useGitBranchName(config.getTargetDir());
|
|
641
|
-
const contextFileNames = useMemo(() => {
|
|
642
|
-
const fromSettings = settings.merged.context?.fileName;
|
|
643
|
-
if (fromSettings) {
|
|
644
|
-
return Array.isArray(fromSettings) ? fromSettings : [fromSettings];
|
|
645
|
-
}
|
|
646
|
-
return getAllGeminiMdFilenames();
|
|
647
|
-
}, [settings.merged.context?.fileName]);
|
|
648
|
-
const initialPrompt = useMemo(() => config.getQuestion(), [config]);
|
|
649
|
-
const geminiClient = config.getGeminiClient();
|
|
650
|
-
useEffect(() => {
|
|
651
|
-
if (initialPrompt &&
|
|
652
|
-
!initialPromptSubmitted.current &&
|
|
653
|
-
!isAuthenticating &&
|
|
654
|
-
!isAuthDialogOpen &&
|
|
655
|
-
!isThemeDialogOpen &&
|
|
656
|
-
!isEditorDialogOpen &&
|
|
657
|
-
!showPrivacyNotice &&
|
|
658
|
-
geminiClient?.isInitialized?.()) {
|
|
659
|
-
submitQuery(initialPrompt);
|
|
660
|
-
initialPromptSubmitted.current = true;
|
|
661
|
-
}
|
|
662
|
-
}, [
|
|
663
|
-
initialPrompt,
|
|
664
|
-
submitQuery,
|
|
665
|
-
isAuthenticating,
|
|
666
|
-
isAuthDialogOpen,
|
|
667
|
-
isThemeDialogOpen,
|
|
668
|
-
isEditorDialogOpen,
|
|
669
|
-
showPrivacyNotice,
|
|
670
|
-
geminiClient,
|
|
671
|
-
]);
|
|
672
|
-
if (quittingMessages) {
|
|
673
|
-
return (_jsx(Box, { flexDirection: "column", marginBottom: 1, children: quittingMessages.map((item) => (_jsx(HistoryItemDisplay, { availableTerminalHeight: constrainHeight ? availableTerminalHeight : undefined, terminalWidth: terminalWidth, item: item, isPending: false, config: config }, item.id))) }));
|
|
9
|
+
import { Notifications } from './components/Notifications.js';
|
|
10
|
+
import { MainContent } from './components/MainContent.js';
|
|
11
|
+
import { DialogManager } from './components/DialogManager.js';
|
|
12
|
+
import { Composer } from './components/Composer.js';
|
|
13
|
+
import { useUIState } from './contexts/UIStateContext.js';
|
|
14
|
+
import { QuittingDisplay } from './components/QuittingDisplay.js';
|
|
15
|
+
export const App = () => {
|
|
16
|
+
const uiState = useUIState();
|
|
17
|
+
if (uiState.quittingMessages) {
|
|
18
|
+
return _jsx(QuittingDisplay, {});
|
|
674
19
|
}
|
|
675
|
-
|
|
676
|
-
const debugConsoleMaxHeight = Math.floor(Math.max(terminalHeight * 0.2, 5));
|
|
677
|
-
// Arbitrary threshold to ensure that items in the static area are large
|
|
678
|
-
// enough but not too large to make the terminal hard to use.
|
|
679
|
-
const staticAreaMaxItemHeight = Math.max(terminalHeight * 4, 100);
|
|
680
|
-
const placeholder = vimModeEnabled
|
|
681
|
-
? " Press 'i' for INSERT mode and 'Esc' for NORMAL mode."
|
|
682
|
-
: ' Type your message or @path/to/file';
|
|
683
|
-
const hideContextSummary = settings.merged.ui?.hideContextSummary ?? false;
|
|
684
|
-
return (_jsx(StreamingContext.Provider, { value: streamingState, children: _jsxs(Box, { flexDirection: "column", width: "90%", children: [_jsx(Static, { items: [
|
|
685
|
-
_jsxs(Box, { flexDirection: "column", children: [!(settings.merged.ui?.hideBanner || config.getScreenReader()) && _jsx(Header, { version: version, nightly: nightly }), !(settings.merged.ui?.hideTips || config.getScreenReader()) && (_jsx(Tips, { config: config }))] }, "header"),
|
|
686
|
-
...history.map((h) => (_jsx(HistoryItemDisplay, { terminalWidth: mainAreaWidth, availableTerminalHeight: staticAreaMaxItemHeight, item: h, isPending: false, config: config, commands: slashCommands }, h.id))),
|
|
687
|
-
], children: (item) => item }, staticKey), _jsx(OverflowProvider, { children: _jsxs(Box, { ref: pendingHistoryItemRef, flexDirection: "column", children: [pendingHistoryItems.map((item, i) => (_jsx(HistoryItemDisplay, { availableTerminalHeight: constrainHeight ? availableTerminalHeight : undefined, terminalWidth: mainAreaWidth,
|
|
688
|
-
// TODO(taehykim): It seems like references to ids aren't necessary in
|
|
689
|
-
// HistoryItemDisplay. Refactor later. Use a fake id for now.
|
|
690
|
-
item: { ...item, id: 0 }, isPending: true, config: config, isFocused: !isEditorDialogOpen }, i))), _jsx(ShowMoreLines, { constrainHeight: constrainHeight })] }) }), _jsxs(Box, { flexDirection: "column", ref: mainControlsRef, children: [updateInfo && _jsx(UpdateNotification, { message: updateInfo.message }), startupWarnings.length > 0 && (_jsx(Box, { borderStyle: "round", borderColor: Colors.AccentYellow, paddingX: 1, marginY: 1, flexDirection: "column", children: startupWarnings.map((warning, index) => (_jsx(Text, { color: Colors.AccentYellow, children: warning }, index))) })), showWorkspaceMigrationDialog ? (_jsx(WorkspaceMigrationDialog, { workspaceExtensions: workspaceExtensions, onOpen: onWorkspaceMigrationDialogOpen, onClose: onWorkspaceMigrationDialogClose })) : shouldShowIdePrompt && currentIDE ? (_jsx(IdeIntegrationNudge, { ide: currentIDE, onComplete: handleIdePromptComplete })) : isProQuotaDialogOpen ? (_jsx(ProQuotaDialog, { currentModel: config.getModel(), fallbackModel: DEFAULT_GEMINI_FLASH_MODEL, onChoice: (choice) => {
|
|
691
|
-
setIsProQuotaDialogOpen(false);
|
|
692
|
-
if (!proQuotaDialogResolver)
|
|
693
|
-
return;
|
|
694
|
-
const resolveValue = choice !== 'auth';
|
|
695
|
-
proQuotaDialogResolver(resolveValue);
|
|
696
|
-
setProQuotaDialogResolver(null);
|
|
697
|
-
if (choice === 'auth') {
|
|
698
|
-
openAuthDialog();
|
|
699
|
-
}
|
|
700
|
-
else {
|
|
701
|
-
addItem({
|
|
702
|
-
type: MessageType.INFO,
|
|
703
|
-
text: 'Switched to fallback model. Tip: Press Ctrl+P to recall your previous prompt and submit it again if you wish.',
|
|
704
|
-
}, Date.now());
|
|
705
|
-
}
|
|
706
|
-
} })) : showIdeRestartPrompt ? (_jsx(Box, { borderStyle: "round", borderColor: Colors.AccentYellow, paddingX: 1, children: _jsx(Text, { color: Colors.AccentYellow, children: "Workspace trust has changed. Press 'r' to restart Gemini to apply the changes." }) })) : isFolderTrustDialogOpen ? (_jsx(FolderTrustDialog, { onSelect: handleFolderTrustSelect, isRestarting: isRestarting })) : shellConfirmationRequest ? (_jsx(ShellConfirmationDialog, { request: shellConfirmationRequest })) : confirmationRequest ? (_jsxs(Box, { flexDirection: "column", children: [confirmationRequest.prompt, _jsx(Box, { paddingY: 1, children: _jsx(RadioButtonSelect, { isFocused: !!confirmationRequest, items: [
|
|
707
|
-
{ label: 'Yes', value: true },
|
|
708
|
-
{ label: 'No', value: false },
|
|
709
|
-
], onSelect: (value) => {
|
|
710
|
-
confirmationRequest.onConfirm(value);
|
|
711
|
-
} }) })] })) : isThemeDialogOpen ? (_jsxs(Box, { flexDirection: "column", children: [themeError && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: Colors.AccentRed, children: themeError }) })), _jsx(ThemeDialog, { onSelect: handleThemeSelect, onHighlight: handleThemeHighlight, settings: settings, availableTerminalHeight: constrainHeight
|
|
712
|
-
? terminalHeight - staticExtraHeight
|
|
713
|
-
: undefined, terminalWidth: mainAreaWidth })] })) : isSettingsDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(SettingsDialog, { settings: settings, onSelect: () => closeSettingsDialog(), onRestartRequest: () => process.exit(0) }) })) : isAuthenticating ? (_jsxs(_Fragment, { children: [_jsx(AuthInProgress, { onTimeout: () => {
|
|
714
|
-
setAuthError('Authentication timed out. Please try again.');
|
|
715
|
-
cancelAuthentication();
|
|
716
|
-
openAuthDialog();
|
|
717
|
-
} }), showErrorDetails && (_jsx(OverflowProvider, { children: _jsxs(Box, { flexDirection: "column", children: [_jsx(DetailedMessagesDisplay, { messages: filteredConsoleMessages, maxHeight: constrainHeight ? debugConsoleMaxHeight : undefined, width: inputWidth }), _jsx(ShowMoreLines, { constrainHeight: constrainHeight })] }) }))] })) : isAuthDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(AuthDialog, { onSelect: handleAuthSelect, settings: settings, initialErrorMessage: authError }) })) : isEditorDialogOpen ? (_jsxs(Box, { flexDirection: "column", children: [editorError && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: Colors.AccentRed, children: editorError }) })), _jsx(EditorSettingsDialog, { onSelect: handleEditorSelect, settings: settings, onExit: exitEditorDialog })] })) : showPrivacyNotice ? (_jsx(PrivacyNotice, { onExit: () => setShowPrivacyNotice(false), config: config })) : (_jsxs(_Fragment, { children: [_jsx(LoadingIndicator, { thought: streamingState === StreamingState.WaitingForConfirmation ||
|
|
718
|
-
config.getAccessibility()?.disableLoadingPhrases ||
|
|
719
|
-
config.getScreenReader()
|
|
720
|
-
? undefined
|
|
721
|
-
: thought, currentLoadingPhrase: config.getAccessibility()?.disableLoadingPhrases ||
|
|
722
|
-
config.getScreenReader()
|
|
723
|
-
? undefined
|
|
724
|
-
: currentLoadingPhrase, elapsedTime: elapsedTime }), messageQueue.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [messageQueue
|
|
725
|
-
.slice(0, MAX_DISPLAYED_QUEUED_MESSAGES)
|
|
726
|
-
.map((message, index) => {
|
|
727
|
-
// Ensure multi-line messages are collapsed for the preview.
|
|
728
|
-
// Replace all whitespace (including newlines) with a single space.
|
|
729
|
-
const preview = message.replace(/\s+/g, ' ');
|
|
730
|
-
return (
|
|
731
|
-
// Ensure the Box takes full width so truncation calculates correctly
|
|
732
|
-
_jsx(Box, { paddingLeft: 2, width: "100%", children: _jsx(Text, { dimColor: true, wrap: "truncate", children: preview }) }, index));
|
|
733
|
-
}), messageQueue.length > MAX_DISPLAYED_QUEUED_MESSAGES && (_jsx(Box, { paddingLeft: 2, children: _jsxs(Text, { dimColor: true, children: ["... (+", messageQueue.length - MAX_DISPLAYED_QUEUED_MESSAGES, "more)"] }) }))] })), _jsxs(Box, { marginTop: 1, justifyContent: hideContextSummary ? 'flex-start' : 'space-between', width: "100%", flexDirection: isNarrow ? 'column' : 'row', alignItems: isNarrow ? 'flex-start' : 'center', children: [_jsxs(Box, { children: [process.env['GEMINI_SYSTEM_MD'] && (_jsx(Text, { color: Colors.AccentRed, children: "|\u2310\u25A0_\u25A0| " })), ctrlCPressedOnce ? (_jsx(Text, { color: Colors.AccentYellow, children: "Press Ctrl+C again to exit." })) : ctrlDPressedOnce ? (_jsx(Text, { color: Colors.AccentYellow, children: "Press Ctrl+D again to exit." })) : showEscapePrompt ? (_jsx(Text, { color: Colors.Gray, children: "Press Esc again to clear." })) : !hideContextSummary ? (_jsx(ContextSummaryDisplay, { ideContext: ideContextState, geminiMdFileCount: geminiMdFileCount, contextFileNames: contextFileNames, mcpServers: config.getMcpServers(), blockedMcpServers: config.getBlockedMcpServers(), showToolDescriptions: showToolDescriptions })) : null] }), _jsxs(Box, { paddingTop: isNarrow ? 1 : 0, marginLeft: hideContextSummary ? 1 : 2, children: [showAutoAcceptIndicator !== ApprovalMode.DEFAULT &&
|
|
734
|
-
!shellModeActive && (_jsx(AutoAcceptIndicator, { approvalMode: showAutoAcceptIndicator })), shellModeActive && _jsx(ShellModeIndicator, {})] })] }), showErrorDetails && (_jsx(OverflowProvider, { children: _jsxs(Box, { flexDirection: "column", children: [_jsx(DetailedMessagesDisplay, { messages: filteredConsoleMessages, maxHeight: constrainHeight ? debugConsoleMaxHeight : undefined, width: inputWidth }), _jsx(ShowMoreLines, { constrainHeight: constrainHeight })] }) })), isInputActive && (_jsx(InputPrompt, { buffer: buffer, inputWidth: inputWidth, suggestionsWidth: suggestionsWidth, onSubmit: handleFinalSubmit, userMessages: inputHistoryStore.inputHistory, onClearScreen: handleClearScreen, config: config, slashCommands: slashCommands, commandContext: commandContext, shellModeActive: shellModeActive, setShellModeActive: setShellModeActive, onEscapePromptChange: handleEscapePromptChange, focus: isFocused, vimHandleInput: vimHandleInput, placeholder: placeholder }))] })), initError && streamingState !== StreamingState.Responding && (_jsx(Box, { borderStyle: "round", borderColor: Colors.AccentRed, paddingX: 1, marginBottom: 1, children: history.find((item) => item.type === 'error' && item.text?.includes(initError))?.text ? (_jsx(Text, { color: Colors.AccentRed, children: history.find((item) => item.type === 'error' && item.text?.includes(initError))?.text })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { color: Colors.AccentRed, children: ["Initialization Error: ", initError] }), _jsxs(Text, { color: Colors.AccentRed, children: [' ', "Please check API key and configuration."] })] })) })), !settings.merged.ui?.hideFooter && (_jsx(Footer, { model: currentModel, targetDir: config.getTargetDir(), debugMode: config.getDebugMode(), branchName: branchName, debugMessage: debugMessage, corgiMode: corgiMode, errorCount: errorCount, showErrorDetails: showErrorDetails, showMemoryUsage: config.getDebugMode() ||
|
|
735
|
-
settings.merged.ui?.showMemoryUsage ||
|
|
736
|
-
false, promptTokenCount: sessionStats.lastPromptTokenCount, nightly: nightly, vimMode: vimModeEnabled ? vimMode : undefined, isTrustedFolder: isTrustedFolderState, hideCWD: settings.merged.ui?.footer?.hideCWD, hideSandboxStatus: settings.merged.ui?.footer?.hideSandboxStatus, hideModelInfo: settings.merged.ui?.footer?.hideModelInfo }))] })] }) }));
|
|
20
|
+
return (_jsx(StreamingContext.Provider, { value: uiState.streamingState, children: _jsxs(Box, { flexDirection: "column", width: "90%", children: [_jsx(MainContent, {}), _jsxs(Box, { flexDirection: "column", ref: uiState.mainControlsRef, children: [_jsx(Notifications, {}), uiState.dialogsVisible ? _jsx(DialogManager, {}) : _jsx(Composer, {})] })] }) }));
|
|
737
21
|
};
|
|
738
22
|
//# sourceMappingURL=App.js.map
|