@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
|
@@ -0,0 +1,932 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2025 Google LLC
|
|
5
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
6
|
+
*/
|
|
7
|
+
import { useMemo, useState, useCallback, useEffect, useRef } from 'react';
|
|
8
|
+
import { measureElement } from 'ink';
|
|
9
|
+
import { App } from './App.js';
|
|
10
|
+
import { AppContext } from './contexts/AppContext.js';
|
|
11
|
+
import { UIStateContext } from './contexts/UIStateContext.js';
|
|
12
|
+
import { UIActionsContext, } from './contexts/UIActionsContext.js';
|
|
13
|
+
import { ConfigContext } from './contexts/ConfigContext.js';
|
|
14
|
+
import { ToolCallStatus, AuthState, } from './types.js';
|
|
15
|
+
import { MessageType, StreamingState } from './types.js';
|
|
16
|
+
import { IdeClient, ideContext, getErrorMessage, getAllGeminiMdFilenames, UserTierId, AuthType, isProQuotaExceededError, isGenericQuotaExceededError, logFlashFallback, FlashFallbackEvent, clearCachedCredentialFile, } from '@google/gemini-cli-core';
|
|
17
|
+
import { validateAuthMethod } from '../config/auth.js';
|
|
18
|
+
import { loadHierarchicalGeminiMemory } from '../config/config.js';
|
|
19
|
+
import process from 'node:process';
|
|
20
|
+
import { useHistory } from './hooks/useHistoryManager.js';
|
|
21
|
+
import { useThemeCommand } from './hooks/useThemeCommand.js';
|
|
22
|
+
import { useAuthCommand } from './auth/useAuth.js';
|
|
23
|
+
import { useEditorSettings } from './hooks/useEditorSettings.js';
|
|
24
|
+
import { useSettingsCommand } from './hooks/useSettingsCommand.js';
|
|
25
|
+
import { useSlashCommandProcessor } from './hooks/slashCommandProcessor.js';
|
|
26
|
+
import { useVimMode } from './contexts/VimModeContext.js';
|
|
27
|
+
import { useConsoleMessages } from './hooks/useConsoleMessages.js';
|
|
28
|
+
import { useTerminalSize } from './hooks/useTerminalSize.js';
|
|
29
|
+
import { useStdin, useStdout } from 'ink';
|
|
30
|
+
import ansiEscapes from 'ansi-escapes';
|
|
31
|
+
import * as fs from 'node:fs';
|
|
32
|
+
import { useTextBuffer } from './components/shared/text-buffer.js';
|
|
33
|
+
import { useLogger } from './hooks/useLogger.js';
|
|
34
|
+
import { useGeminiStream } from './hooks/useGeminiStream.js';
|
|
35
|
+
import { useVim } from './hooks/vim.js';
|
|
36
|
+
import { SettingScope } from '../config/settings.js';
|
|
37
|
+
import {} from '../core/initializer.js';
|
|
38
|
+
import { useFocus } from './hooks/useFocus.js';
|
|
39
|
+
import { useBracketedPaste } from './hooks/useBracketedPaste.js';
|
|
40
|
+
import { useKeypress } from './hooks/useKeypress.js';
|
|
41
|
+
import { keyMatchers, Command } from './keyMatchers.js';
|
|
42
|
+
import { useLoadingIndicator } from './hooks/useLoadingIndicator.js';
|
|
43
|
+
import { useFolderTrust } from './hooks/useFolderTrust.js';
|
|
44
|
+
import { useIdeTrustListener } from './hooks/useIdeTrustListener.js';
|
|
45
|
+
import {} from './IdeIntegrationNudge.js';
|
|
46
|
+
import { appEvents, AppEvent } from '../utils/events.js';
|
|
47
|
+
import {} from './utils/updateCheck.js';
|
|
48
|
+
import { setUpdateHandler } from '../utils/handleAutoUpdate.js';
|
|
49
|
+
import { ConsolePatcher } from './utils/ConsolePatcher.js';
|
|
50
|
+
import { registerCleanup, runExitCleanup } from '../utils/cleanup.js';
|
|
51
|
+
import { useMessageQueue } from './hooks/useMessageQueue.js';
|
|
52
|
+
import { useAutoAcceptIndicator } from './hooks/useAutoAcceptIndicator.js';
|
|
53
|
+
import { useWorkspaceMigration } from './hooks/useWorkspaceMigration.js';
|
|
54
|
+
import { useSessionStats } from './contexts/SessionContext.js';
|
|
55
|
+
import { useGitBranchName } from './hooks/useGitBranchName.js';
|
|
56
|
+
const CTRL_EXIT_PROMPT_DURATION_MS = 1000;
|
|
57
|
+
function isToolExecuting(pendingHistoryItems) {
|
|
58
|
+
return pendingHistoryItems.some((item) => {
|
|
59
|
+
if (item && item.type === 'tool_group') {
|
|
60
|
+
return item.tools.some((tool) => ToolCallStatus.Executing === tool.status);
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
export const AppContainer = (props) => {
|
|
66
|
+
const { settings, config, initializationResult } = props;
|
|
67
|
+
const historyManager = useHistory();
|
|
68
|
+
const [corgiMode, setCorgiMode] = useState(false);
|
|
69
|
+
const [debugMessage, setDebugMessage] = useState('');
|
|
70
|
+
const [quittingMessages, setQuittingMessages] = useState(null);
|
|
71
|
+
const [showPrivacyNotice, setShowPrivacyNotice] = useState(false);
|
|
72
|
+
const [themeError, setThemeError] = useState(initializationResult.themeError);
|
|
73
|
+
const [isProcessing, setIsProcessing] = useState(false);
|
|
74
|
+
const [geminiMdFileCount, setGeminiMdFileCount] = useState(initializationResult.geminiMdFileCount);
|
|
75
|
+
const [shellModeActive, setShellModeActive] = useState(false);
|
|
76
|
+
const [modelSwitchedFromQuotaError, setModelSwitchedFromQuotaError] = useState(false);
|
|
77
|
+
const [historyRemountKey, setHistoryRemountKey] = useState(0);
|
|
78
|
+
const [updateInfo, setUpdateInfo] = useState(null);
|
|
79
|
+
const [isTrustedFolder, setIsTrustedFolder] = useState(config.isTrustedFolder());
|
|
80
|
+
const [currentModel, setCurrentModel] = useState(config.getModel());
|
|
81
|
+
const [userTier, setUserTier] = useState(undefined);
|
|
82
|
+
const [isProQuotaDialogOpen, setIsProQuotaDialogOpen] = useState(false);
|
|
83
|
+
const [proQuotaDialogResolver, setProQuotaDialogResolver] = useState(null);
|
|
84
|
+
// Auto-accept indicator
|
|
85
|
+
const showAutoAcceptIndicator = useAutoAcceptIndicator({
|
|
86
|
+
config,
|
|
87
|
+
addItem: historyManager.addItem,
|
|
88
|
+
});
|
|
89
|
+
const logger = useLogger(config.storage);
|
|
90
|
+
const [userMessages, setUserMessages] = useState([]);
|
|
91
|
+
// Terminal and layout hooks
|
|
92
|
+
const { columns: terminalWidth, rows: terminalHeight } = useTerminalSize();
|
|
93
|
+
const { stdin, setRawMode } = useStdin();
|
|
94
|
+
const { stdout } = useStdout();
|
|
95
|
+
// Additional hooks moved from App.tsx
|
|
96
|
+
const { stats: sessionStats } = useSessionStats();
|
|
97
|
+
const branchName = useGitBranchName(config.getTargetDir());
|
|
98
|
+
// Layout measurements
|
|
99
|
+
const mainControlsRef = useRef(null);
|
|
100
|
+
const staticExtraHeight = 3;
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
registerCleanup(async () => {
|
|
103
|
+
const ideClient = await IdeClient.getInstance();
|
|
104
|
+
await ideClient.disconnect();
|
|
105
|
+
});
|
|
106
|
+
}, [config]);
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
const cleanup = setUpdateHandler(historyManager.addItem, setUpdateInfo);
|
|
109
|
+
return cleanup;
|
|
110
|
+
}, [historyManager.addItem]);
|
|
111
|
+
// Watch for model changes (e.g., from Flash fallback)
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
const checkModelChange = () => {
|
|
114
|
+
const configModel = config.getModel();
|
|
115
|
+
if (configModel !== currentModel) {
|
|
116
|
+
setCurrentModel(configModel);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
// Check immediately and then periodically
|
|
120
|
+
checkModelChange();
|
|
121
|
+
const interval = setInterval(checkModelChange, 1000); // Check every second
|
|
122
|
+
return () => clearInterval(interval);
|
|
123
|
+
}, [config, currentModel]);
|
|
124
|
+
const { consoleMessages, handleNewMessage, clearConsoleMessages: clearConsoleMessagesState, } = useConsoleMessages();
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
const consolePatcher = new ConsolePatcher({
|
|
127
|
+
onNewMessage: handleNewMessage,
|
|
128
|
+
debugMode: config.getDebugMode(),
|
|
129
|
+
});
|
|
130
|
+
consolePatcher.patch();
|
|
131
|
+
registerCleanup(consolePatcher.cleanup);
|
|
132
|
+
}, [handleNewMessage, config]);
|
|
133
|
+
const widthFraction = 0.9;
|
|
134
|
+
const inputWidth = Math.max(20, Math.floor(terminalWidth * widthFraction) - 3);
|
|
135
|
+
const suggestionsWidth = Math.max(20, Math.floor(terminalWidth * 0.8));
|
|
136
|
+
const mainAreaWidth = Math.floor(terminalWidth * 0.9);
|
|
137
|
+
const staticAreaMaxItemHeight = Math.max(terminalHeight * 4, 100);
|
|
138
|
+
const isValidPath = useCallback((filePath) => {
|
|
139
|
+
try {
|
|
140
|
+
return fs.existsSync(filePath) && fs.statSync(filePath).isFile();
|
|
141
|
+
}
|
|
142
|
+
catch (_e) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}, []);
|
|
146
|
+
const buffer = useTextBuffer({
|
|
147
|
+
initialText: '',
|
|
148
|
+
viewport: { height: 10, width: inputWidth },
|
|
149
|
+
stdin,
|
|
150
|
+
setRawMode,
|
|
151
|
+
isValidPath,
|
|
152
|
+
shellModeActive,
|
|
153
|
+
});
|
|
154
|
+
useEffect(() => {
|
|
155
|
+
const fetchUserMessages = async () => {
|
|
156
|
+
const pastMessagesRaw = (await logger?.getPreviousUserMessages()) || [];
|
|
157
|
+
const currentSessionUserMessages = historyManager.history
|
|
158
|
+
.filter((item) => item.type === 'user' &&
|
|
159
|
+
typeof item.text === 'string' &&
|
|
160
|
+
item.text.trim() !== '')
|
|
161
|
+
.map((item) => item.text)
|
|
162
|
+
.reverse();
|
|
163
|
+
const combinedMessages = [
|
|
164
|
+
...currentSessionUserMessages,
|
|
165
|
+
...pastMessagesRaw,
|
|
166
|
+
];
|
|
167
|
+
const deduplicatedMessages = [];
|
|
168
|
+
if (combinedMessages.length > 0) {
|
|
169
|
+
deduplicatedMessages.push(combinedMessages[0]);
|
|
170
|
+
for (let i = 1; i < combinedMessages.length; i++) {
|
|
171
|
+
if (combinedMessages[i] !== combinedMessages[i - 1]) {
|
|
172
|
+
deduplicatedMessages.push(combinedMessages[i]);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
setUserMessages(deduplicatedMessages.reverse());
|
|
177
|
+
};
|
|
178
|
+
fetchUserMessages();
|
|
179
|
+
}, [historyManager.history, logger]);
|
|
180
|
+
const refreshStatic = useCallback(() => {
|
|
181
|
+
stdout.write(ansiEscapes.clearTerminal);
|
|
182
|
+
setHistoryRemountKey((prev) => prev + 1);
|
|
183
|
+
}, [setHistoryRemountKey, stdout]);
|
|
184
|
+
const { isThemeDialogOpen, openThemeDialog, handleThemeSelect, handleThemeHighlight, } = useThemeCommand(settings, setThemeError, historyManager.addItem, initializationResult.themeError);
|
|
185
|
+
const { authState, setAuthState, authError, onAuthError } = useAuthCommand(settings, config);
|
|
186
|
+
// Derive auth state variables for backward compatibility with UIStateContext
|
|
187
|
+
const isAuthDialogOpen = authState === AuthState.Updating;
|
|
188
|
+
const isAuthenticating = authState === AuthState.Unauthenticated;
|
|
189
|
+
// Create handleAuthSelect wrapper for backward compatibility
|
|
190
|
+
const handleAuthSelect = useCallback(async (authType, scope) => {
|
|
191
|
+
if (authType) {
|
|
192
|
+
await clearCachedCredentialFile();
|
|
193
|
+
settings.setValue(scope, 'security.auth.selectedType', authType);
|
|
194
|
+
try {
|
|
195
|
+
await config.refreshAuth(authType);
|
|
196
|
+
setAuthState(AuthState.Authenticated);
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
onAuthError(`Failed to authenticate: ${e instanceof Error ? e.message : String(e)}`);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (authType === AuthType.LOGIN_WITH_GOOGLE &&
|
|
203
|
+
config.isBrowserLaunchSuppressed()) {
|
|
204
|
+
await runExitCleanup();
|
|
205
|
+
console.log(`
|
|
206
|
+
----------------------------------------------------------------
|
|
207
|
+
Logging in with Google... Please restart Gemini CLI to continue.
|
|
208
|
+
----------------------------------------------------------------
|
|
209
|
+
`);
|
|
210
|
+
process.exit(0);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
setAuthState(AuthState.Authenticated);
|
|
214
|
+
}, [settings, config, setAuthState, onAuthError]);
|
|
215
|
+
// Sync user tier from config when authentication changes
|
|
216
|
+
useEffect(() => {
|
|
217
|
+
// Only sync when not currently authenticating
|
|
218
|
+
if (authState === AuthState.Authenticated) {
|
|
219
|
+
setUserTier(config.getUserTier());
|
|
220
|
+
}
|
|
221
|
+
}, [config, authState]);
|
|
222
|
+
// Check for enforced auth type mismatch
|
|
223
|
+
useEffect(() => {
|
|
224
|
+
if (settings.merged.security?.auth?.enforcedType &&
|
|
225
|
+
settings.merged.security?.auth.selectedType &&
|
|
226
|
+
settings.merged.security?.auth.enforcedType !==
|
|
227
|
+
settings.merged.security?.auth.selectedType) {
|
|
228
|
+
onAuthError(`Authentication is enforced to be ${settings.merged.security?.auth.enforcedType}, but you are currently using ${settings.merged.security?.auth.selectedType}.`);
|
|
229
|
+
}
|
|
230
|
+
else if (settings.merged.security?.auth?.selectedType &&
|
|
231
|
+
!settings.merged.security?.auth?.useExternal) {
|
|
232
|
+
const error = validateAuthMethod(settings.merged.security.auth.selectedType);
|
|
233
|
+
if (error) {
|
|
234
|
+
onAuthError(error);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}, [
|
|
238
|
+
settings.merged.security?.auth?.selectedType,
|
|
239
|
+
settings.merged.security?.auth?.enforcedType,
|
|
240
|
+
settings.merged.security?.auth?.useExternal,
|
|
241
|
+
onAuthError,
|
|
242
|
+
]);
|
|
243
|
+
const [editorError, setEditorError] = useState(null);
|
|
244
|
+
const { isEditorDialogOpen, openEditorDialog, handleEditorSelect, exitEditorDialog, } = useEditorSettings(settings, setEditorError, historyManager.addItem);
|
|
245
|
+
const { isSettingsDialogOpen, openSettingsDialog, closeSettingsDialog } = useSettingsCommand();
|
|
246
|
+
const { showWorkspaceMigrationDialog, workspaceExtensions, onWorkspaceMigrationDialogOpen, onWorkspaceMigrationDialogClose, } = useWorkspaceMigration(settings);
|
|
247
|
+
const { toggleVimEnabled } = useVimMode();
|
|
248
|
+
const slashCommandActions = useMemo(() => ({
|
|
249
|
+
openAuthDialog: () => setAuthState(AuthState.Updating),
|
|
250
|
+
openThemeDialog,
|
|
251
|
+
openEditorDialog,
|
|
252
|
+
openPrivacyNotice: () => setShowPrivacyNotice(true),
|
|
253
|
+
openSettingsDialog,
|
|
254
|
+
quit: (messages) => {
|
|
255
|
+
setQuittingMessages(messages);
|
|
256
|
+
setTimeout(async () => {
|
|
257
|
+
await runExitCleanup();
|
|
258
|
+
process.exit(0);
|
|
259
|
+
}, 100);
|
|
260
|
+
},
|
|
261
|
+
setDebugMessage,
|
|
262
|
+
toggleCorgiMode: () => setCorgiMode((prev) => !prev),
|
|
263
|
+
}), [
|
|
264
|
+
setAuthState,
|
|
265
|
+
openThemeDialog,
|
|
266
|
+
openEditorDialog,
|
|
267
|
+
openSettingsDialog,
|
|
268
|
+
setQuittingMessages,
|
|
269
|
+
setDebugMessage,
|
|
270
|
+
setShowPrivacyNotice,
|
|
271
|
+
setCorgiMode,
|
|
272
|
+
]);
|
|
273
|
+
const { handleSlashCommand, slashCommands, pendingHistoryItems: pendingSlashCommandHistoryItems, commandContext, shellConfirmationRequest, confirmationRequest, } = useSlashCommandProcessor(config, settings, historyManager.addItem, historyManager.clearItems, historyManager.loadHistory, refreshStatic, toggleVimEnabled, setIsProcessing, setGeminiMdFileCount, slashCommandActions);
|
|
274
|
+
const performMemoryRefresh = useCallback(async () => {
|
|
275
|
+
historyManager.addItem({
|
|
276
|
+
type: MessageType.INFO,
|
|
277
|
+
text: 'Refreshing hierarchical memory (GEMINI.md or other context files)...',
|
|
278
|
+
}, Date.now());
|
|
279
|
+
try {
|
|
280
|
+
const { memoryContent, fileCount } = await loadHierarchicalGeminiMemory(process.cwd(), settings.merged.context?.loadMemoryFromIncludeDirectories
|
|
281
|
+
? config.getWorkspaceContext().getDirectories()
|
|
282
|
+
: [], config.getDebugMode(), config.getFileService(), settings.merged, config.getExtensionContextFilePaths(), config.isTrustedFolder(), settings.merged.context?.importFormat || 'tree', // Use setting or default to 'tree'
|
|
283
|
+
config.getFileFilteringOptions());
|
|
284
|
+
config.setUserMemory(memoryContent);
|
|
285
|
+
config.setGeminiMdFileCount(fileCount);
|
|
286
|
+
setGeminiMdFileCount(fileCount);
|
|
287
|
+
historyManager.addItem({
|
|
288
|
+
type: MessageType.INFO,
|
|
289
|
+
text: `Memory refreshed successfully. ${memoryContent.length > 0
|
|
290
|
+
? `Loaded ${memoryContent.length} characters from ${fileCount} file(s).`
|
|
291
|
+
: 'No memory content found.'}`,
|
|
292
|
+
}, Date.now());
|
|
293
|
+
if (config.getDebugMode()) {
|
|
294
|
+
console.log(`[DEBUG] Refreshed memory content in config: ${memoryContent.substring(0, 200)}...`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
const errorMessage = getErrorMessage(error);
|
|
299
|
+
historyManager.addItem({
|
|
300
|
+
type: MessageType.ERROR,
|
|
301
|
+
text: `Error refreshing memory: ${errorMessage}`,
|
|
302
|
+
}, Date.now());
|
|
303
|
+
console.error('Error refreshing memory:', error);
|
|
304
|
+
}
|
|
305
|
+
}, [config, historyManager, settings.merged]);
|
|
306
|
+
// Set up Flash fallback handler
|
|
307
|
+
useEffect(() => {
|
|
308
|
+
const flashFallbackHandler = async (currentModel, fallbackModel, error) => {
|
|
309
|
+
// Check if we've already switched to the fallback model
|
|
310
|
+
if (config.isInFallbackMode()) {
|
|
311
|
+
// If we're already in fallback mode, don't show the dialog again
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
let message;
|
|
315
|
+
if (config.getContentGeneratorConfig().authType ===
|
|
316
|
+
AuthType.LOGIN_WITH_GOOGLE) {
|
|
317
|
+
// Use actual user tier if available; otherwise, default to FREE tier behavior (safe default)
|
|
318
|
+
const isPaidTier = userTier === UserTierId.LEGACY || userTier === UserTierId.STANDARD;
|
|
319
|
+
// Check if this is a Pro quota exceeded error
|
|
320
|
+
if (error && isProQuotaExceededError(error)) {
|
|
321
|
+
if (isPaidTier) {
|
|
322
|
+
message = `⚡ You have reached your daily ${currentModel} quota limit.
|
|
323
|
+
⚡ You can choose to authenticate with a paid API key or continue with the fallback model.
|
|
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 ${currentModel} quota limit.
|
|
328
|
+
⚡ You can choose to authenticate with a paid API key or continue with the fallback model.
|
|
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 if (error && isGenericQuotaExceededError(error)) {
|
|
335
|
+
if (isPaidTier) {
|
|
336
|
+
message = `⚡ You have reached your daily quota limit.
|
|
337
|
+
⚡ Automatically switching from ${currentModel} to ${fallbackModel} for the remainder of this session.
|
|
338
|
+
⚡ 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`;
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
message = `⚡ You have reached your daily quota limit.
|
|
342
|
+
⚡ Automatically switching from ${currentModel} to ${fallbackModel} for the remainder of this session.
|
|
343
|
+
⚡ 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
|
|
344
|
+
⚡ Or you can utilize a Gemini API Key. See: https://goo.gle/gemini-cli-docs-auth#gemini-api-key
|
|
345
|
+
⚡ You can switch authentication methods by typing /auth`;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
if (isPaidTier) {
|
|
350
|
+
// Default fallback message for other cases (like consecutive 429s)
|
|
351
|
+
message = `⚡ Automatically switching from ${currentModel} to ${fallbackModel} for faster responses for the remainder of this session.
|
|
352
|
+
⚡ Possible reasons for this are that you have received multiple consecutive capacity errors or you have reached your daily ${currentModel} quota limit
|
|
353
|
+
⚡ 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`;
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
// Default fallback message for other cases (like consecutive 429s)
|
|
357
|
+
message = `⚡ Automatically switching from ${currentModel} to ${fallbackModel} for faster responses for the remainder of this session.
|
|
358
|
+
⚡ Possible reasons for this are that you have received multiple consecutive capacity errors or you have reached your daily ${currentModel} quota limit
|
|
359
|
+
⚡ 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
|
|
360
|
+
⚡ Or you can utilize a Gemini API Key. See: https://goo.gle/gemini-cli-docs-auth#gemini-api-key
|
|
361
|
+
⚡ You can switch authentication methods by typing /auth`;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
// Add message to UI history
|
|
365
|
+
historyManager.addItem({
|
|
366
|
+
type: MessageType.INFO,
|
|
367
|
+
text: message,
|
|
368
|
+
}, Date.now());
|
|
369
|
+
// For Pro quota errors, show the dialog and wait for user's choice
|
|
370
|
+
if (error && isProQuotaExceededError(error)) {
|
|
371
|
+
// Set the flag to prevent tool continuation
|
|
372
|
+
setModelSwitchedFromQuotaError(true);
|
|
373
|
+
// Set global quota error flag to prevent Flash model calls
|
|
374
|
+
config.setQuotaErrorOccurred(true);
|
|
375
|
+
// Show the ProQuotaDialog and wait for user's choice
|
|
376
|
+
const shouldContinueWithFallback = await new Promise((resolve) => {
|
|
377
|
+
setIsProQuotaDialogOpen(true);
|
|
378
|
+
setProQuotaDialogResolver(() => resolve);
|
|
379
|
+
});
|
|
380
|
+
// If user chose to continue with fallback, we don't need to stop the current prompt
|
|
381
|
+
if (shouldContinueWithFallback) {
|
|
382
|
+
// Switch to fallback model for future use
|
|
383
|
+
config.setModel(fallbackModel);
|
|
384
|
+
config.setFallbackMode(true);
|
|
385
|
+
logFlashFallback(config, new FlashFallbackEvent(config.getContentGeneratorConfig().authType));
|
|
386
|
+
return true; // Continue with current prompt using fallback model
|
|
387
|
+
}
|
|
388
|
+
// If user chose to authenticate, stop current prompt
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
// For other quota errors, automatically switch to fallback model
|
|
392
|
+
// Set the flag to prevent tool continuation
|
|
393
|
+
setModelSwitchedFromQuotaError(true);
|
|
394
|
+
// Set global quota error flag to prevent Flash model calls
|
|
395
|
+
config.setQuotaErrorOccurred(true);
|
|
396
|
+
}
|
|
397
|
+
// Switch model for future use but return false to stop current retry
|
|
398
|
+
config.setModel(fallbackModel);
|
|
399
|
+
config.setFallbackMode(true);
|
|
400
|
+
logFlashFallback(config, new FlashFallbackEvent(config.getContentGeneratorConfig().authType));
|
|
401
|
+
return false; // Don't continue with current prompt
|
|
402
|
+
};
|
|
403
|
+
config.setFlashFallbackHandler(flashFallbackHandler);
|
|
404
|
+
}, [config, historyManager, userTier]);
|
|
405
|
+
const cancelHandlerRef = useRef(() => { });
|
|
406
|
+
const { streamingState, submitQuery, initError, pendingHistoryItems: pendingGeminiHistoryItems, thought, cancelOngoingRequest, } = useGeminiStream(config.getGeminiClient(), historyManager.history, historyManager.addItem, config, settings, setDebugMessage, handleSlashCommand, shellModeActive, () => settings.merged.general?.preferredEditor, onAuthError, performMemoryRefresh, modelSwitchedFromQuotaError, setModelSwitchedFromQuotaError, refreshStatic, () => cancelHandlerRef.current());
|
|
407
|
+
const { messageQueue, addMessage, clearQueue, getQueuedMessagesText } = useMessageQueue({
|
|
408
|
+
streamingState,
|
|
409
|
+
submitQuery,
|
|
410
|
+
});
|
|
411
|
+
cancelHandlerRef.current = useCallback(() => {
|
|
412
|
+
const pendingHistoryItems = [
|
|
413
|
+
...pendingSlashCommandHistoryItems,
|
|
414
|
+
...pendingGeminiHistoryItems,
|
|
415
|
+
];
|
|
416
|
+
if (isToolExecuting(pendingHistoryItems)) {
|
|
417
|
+
buffer.setText(''); // Just clear the prompt
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
const lastUserMessage = userMessages.at(-1);
|
|
421
|
+
let textToSet = lastUserMessage || '';
|
|
422
|
+
const queuedText = getQueuedMessagesText();
|
|
423
|
+
if (queuedText) {
|
|
424
|
+
textToSet = textToSet ? `${textToSet}\n\n${queuedText}` : queuedText;
|
|
425
|
+
clearQueue();
|
|
426
|
+
}
|
|
427
|
+
if (textToSet) {
|
|
428
|
+
buffer.setText(textToSet);
|
|
429
|
+
}
|
|
430
|
+
}, [
|
|
431
|
+
buffer,
|
|
432
|
+
userMessages,
|
|
433
|
+
getQueuedMessagesText,
|
|
434
|
+
clearQueue,
|
|
435
|
+
pendingSlashCommandHistoryItems,
|
|
436
|
+
pendingGeminiHistoryItems,
|
|
437
|
+
]);
|
|
438
|
+
const handleFinalSubmit = useCallback((submittedValue) => {
|
|
439
|
+
addMessage(submittedValue);
|
|
440
|
+
}, [addMessage]);
|
|
441
|
+
const handleClearScreen = useCallback(() => {
|
|
442
|
+
historyManager.clearItems();
|
|
443
|
+
clearConsoleMessagesState();
|
|
444
|
+
console.clear();
|
|
445
|
+
refreshStatic();
|
|
446
|
+
}, [historyManager, clearConsoleMessagesState, refreshStatic]);
|
|
447
|
+
const handleProQuotaChoice = useCallback((choice) => {
|
|
448
|
+
setIsProQuotaDialogOpen(false);
|
|
449
|
+
if (proQuotaDialogResolver) {
|
|
450
|
+
if (choice === 'auth') {
|
|
451
|
+
proQuotaDialogResolver(false); // Don't continue with fallback, show auth dialog
|
|
452
|
+
setAuthState(AuthState.Updating);
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
proQuotaDialogResolver(true); // Continue with fallback model
|
|
456
|
+
}
|
|
457
|
+
setProQuotaDialogResolver(null);
|
|
458
|
+
}
|
|
459
|
+
}, [proQuotaDialogResolver, setAuthState]);
|
|
460
|
+
const { handleInput: vimHandleInput } = useVim(buffer, handleFinalSubmit);
|
|
461
|
+
/**
|
|
462
|
+
* Determines if the input prompt should be active and accept user input.
|
|
463
|
+
* Input is disabled during:
|
|
464
|
+
* - Initialization errors
|
|
465
|
+
* - Slash command processing
|
|
466
|
+
* - Tool confirmations (WaitingForConfirmation state)
|
|
467
|
+
* - Any future streaming states not explicitly allowed
|
|
468
|
+
*/
|
|
469
|
+
const isInputActive = !initError &&
|
|
470
|
+
!isProcessing &&
|
|
471
|
+
(streamingState === StreamingState.Idle ||
|
|
472
|
+
streamingState === StreamingState.Responding) &&
|
|
473
|
+
!isProQuotaDialogOpen;
|
|
474
|
+
// Compute available terminal height based on controls measurement
|
|
475
|
+
const availableTerminalHeight = useMemo(() => {
|
|
476
|
+
if (mainControlsRef.current) {
|
|
477
|
+
const fullFooterMeasurement = measureElement(mainControlsRef.current);
|
|
478
|
+
return terminalHeight - fullFooterMeasurement.height - staticExtraHeight;
|
|
479
|
+
}
|
|
480
|
+
return terminalHeight - staticExtraHeight;
|
|
481
|
+
}, [terminalHeight]);
|
|
482
|
+
const isFocused = useFocus();
|
|
483
|
+
useBracketedPaste();
|
|
484
|
+
// Context file names computation
|
|
485
|
+
const contextFileNames = useMemo(() => {
|
|
486
|
+
const fromSettings = settings.merged.context?.fileName;
|
|
487
|
+
return fromSettings
|
|
488
|
+
? Array.isArray(fromSettings)
|
|
489
|
+
? fromSettings
|
|
490
|
+
: [fromSettings]
|
|
491
|
+
: getAllGeminiMdFilenames();
|
|
492
|
+
}, [settings.merged.context?.fileName]);
|
|
493
|
+
// Initial prompt handling
|
|
494
|
+
const initialPrompt = useMemo(() => config.getQuestion(), [config]);
|
|
495
|
+
const initialPromptSubmitted = useRef(false);
|
|
496
|
+
const geminiClient = config.getGeminiClient();
|
|
497
|
+
useEffect(() => {
|
|
498
|
+
if (initialPrompt &&
|
|
499
|
+
!initialPromptSubmitted.current &&
|
|
500
|
+
!isAuthenticating &&
|
|
501
|
+
!isAuthDialogOpen &&
|
|
502
|
+
!isThemeDialogOpen &&
|
|
503
|
+
!isEditorDialogOpen &&
|
|
504
|
+
!showPrivacyNotice &&
|
|
505
|
+
geminiClient?.isInitialized?.()) {
|
|
506
|
+
handleFinalSubmit(initialPrompt);
|
|
507
|
+
initialPromptSubmitted.current = true;
|
|
508
|
+
}
|
|
509
|
+
}, [
|
|
510
|
+
initialPrompt,
|
|
511
|
+
handleFinalSubmit,
|
|
512
|
+
isAuthenticating,
|
|
513
|
+
isAuthDialogOpen,
|
|
514
|
+
isThemeDialogOpen,
|
|
515
|
+
isEditorDialogOpen,
|
|
516
|
+
showPrivacyNotice,
|
|
517
|
+
geminiClient,
|
|
518
|
+
]);
|
|
519
|
+
const [idePromptAnswered, setIdePromptAnswered] = useState(false);
|
|
520
|
+
const [currentIDE, setCurrentIDE] = useState(null);
|
|
521
|
+
useEffect(() => {
|
|
522
|
+
const getIde = async () => {
|
|
523
|
+
const ideClient = await IdeClient.getInstance();
|
|
524
|
+
const currentIde = ideClient.getCurrentIde();
|
|
525
|
+
setCurrentIDE(currentIde || null);
|
|
526
|
+
};
|
|
527
|
+
getIde();
|
|
528
|
+
}, []);
|
|
529
|
+
const shouldShowIdePrompt = Boolean(currentIDE &&
|
|
530
|
+
!config.getIdeMode() &&
|
|
531
|
+
!settings.merged.ide?.hasSeenNudge &&
|
|
532
|
+
!idePromptAnswered);
|
|
533
|
+
const [showErrorDetails, setShowErrorDetails] = useState(false);
|
|
534
|
+
const [showToolDescriptions, setShowToolDescriptions] = useState(false);
|
|
535
|
+
const [ctrlCPressedOnce, setCtrlCPressedOnce] = useState(false);
|
|
536
|
+
const ctrlCTimerRef = useRef(null);
|
|
537
|
+
const [ctrlDPressedOnce, setCtrlDPressedOnce] = useState(false);
|
|
538
|
+
const ctrlDTimerRef = useRef(null);
|
|
539
|
+
const [constrainHeight, setConstrainHeight] = useState(true);
|
|
540
|
+
const [ideContextState, setIdeContextState] = useState();
|
|
541
|
+
const [showEscapePrompt, setShowEscapePrompt] = useState(false);
|
|
542
|
+
const [showIdeRestartPrompt, setShowIdeRestartPrompt] = useState(false);
|
|
543
|
+
const { isFolderTrustDialogOpen, handleFolderTrustSelect, isRestarting } = useFolderTrust(settings, config, setIsTrustedFolder);
|
|
544
|
+
const { needsRestart: ideNeedsRestart } = useIdeTrustListener();
|
|
545
|
+
const isInitialMount = useRef(true);
|
|
546
|
+
useEffect(() => {
|
|
547
|
+
if (ideNeedsRestart) {
|
|
548
|
+
// IDE trust changed, force a restart.
|
|
549
|
+
setShowIdeRestartPrompt(true);
|
|
550
|
+
}
|
|
551
|
+
}, [ideNeedsRestart]);
|
|
552
|
+
useEffect(() => {
|
|
553
|
+
if (isInitialMount.current) {
|
|
554
|
+
isInitialMount.current = false;
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
const handler = setTimeout(() => {
|
|
558
|
+
refreshStatic();
|
|
559
|
+
}, 300);
|
|
560
|
+
return () => {
|
|
561
|
+
clearTimeout(handler);
|
|
562
|
+
};
|
|
563
|
+
}, [terminalWidth, refreshStatic]);
|
|
564
|
+
useEffect(() => {
|
|
565
|
+
const unsubscribe = ideContext.subscribeToIdeContext(setIdeContextState);
|
|
566
|
+
setIdeContextState(ideContext.getIdeContext());
|
|
567
|
+
return unsubscribe;
|
|
568
|
+
}, []);
|
|
569
|
+
useEffect(() => {
|
|
570
|
+
const openDebugConsole = () => {
|
|
571
|
+
setShowErrorDetails(true);
|
|
572
|
+
setConstrainHeight(false);
|
|
573
|
+
};
|
|
574
|
+
appEvents.on(AppEvent.OpenDebugConsole, openDebugConsole);
|
|
575
|
+
const logErrorHandler = (errorMessage) => {
|
|
576
|
+
handleNewMessage({
|
|
577
|
+
type: 'error',
|
|
578
|
+
content: String(errorMessage),
|
|
579
|
+
count: 1,
|
|
580
|
+
});
|
|
581
|
+
};
|
|
582
|
+
appEvents.on(AppEvent.LogError, logErrorHandler);
|
|
583
|
+
return () => {
|
|
584
|
+
appEvents.off(AppEvent.OpenDebugConsole, openDebugConsole);
|
|
585
|
+
appEvents.off(AppEvent.LogError, logErrorHandler);
|
|
586
|
+
};
|
|
587
|
+
}, [handleNewMessage]);
|
|
588
|
+
const handleEscapePromptChange = useCallback((showPrompt) => {
|
|
589
|
+
setShowEscapePrompt(showPrompt);
|
|
590
|
+
}, []);
|
|
591
|
+
const handleIdePromptComplete = useCallback((result) => {
|
|
592
|
+
if (result.userSelection === 'yes') {
|
|
593
|
+
handleSlashCommand('/ide install');
|
|
594
|
+
settings.setValue(SettingScope.User, 'hasSeenIdeIntegrationNudge', true);
|
|
595
|
+
}
|
|
596
|
+
else if (result.userSelection === 'dismiss') {
|
|
597
|
+
settings.setValue(SettingScope.User, 'hasSeenIdeIntegrationNudge', true);
|
|
598
|
+
}
|
|
599
|
+
setIdePromptAnswered(true);
|
|
600
|
+
}, [handleSlashCommand, settings]);
|
|
601
|
+
const { elapsedTime, currentLoadingPhrase } = useLoadingIndicator(streamingState);
|
|
602
|
+
const handleExit = useCallback((pressedOnce, setPressedOnce, timerRef) => {
|
|
603
|
+
if (pressedOnce) {
|
|
604
|
+
if (timerRef.current) {
|
|
605
|
+
clearTimeout(timerRef.current);
|
|
606
|
+
}
|
|
607
|
+
handleSlashCommand('/quit');
|
|
608
|
+
}
|
|
609
|
+
else {
|
|
610
|
+
setPressedOnce(true);
|
|
611
|
+
timerRef.current = setTimeout(() => {
|
|
612
|
+
setPressedOnce(false);
|
|
613
|
+
timerRef.current = null;
|
|
614
|
+
}, CTRL_EXIT_PROMPT_DURATION_MS);
|
|
615
|
+
}
|
|
616
|
+
}, [handleSlashCommand]);
|
|
617
|
+
const handleGlobalKeypress = useCallback((key) => {
|
|
618
|
+
// Debug log keystrokes if enabled
|
|
619
|
+
if (settings.merged.general?.debugKeystrokeLogging) {
|
|
620
|
+
console.log('[DEBUG] Keystroke:', JSON.stringify(key));
|
|
621
|
+
}
|
|
622
|
+
const anyDialogOpen = isThemeDialogOpen ||
|
|
623
|
+
isAuthDialogOpen ||
|
|
624
|
+
isEditorDialogOpen ||
|
|
625
|
+
isSettingsDialogOpen ||
|
|
626
|
+
isFolderTrustDialogOpen ||
|
|
627
|
+
showPrivacyNotice;
|
|
628
|
+
if (anyDialogOpen) {
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
let enteringConstrainHeightMode = false;
|
|
632
|
+
if (!constrainHeight) {
|
|
633
|
+
enteringConstrainHeightMode = true;
|
|
634
|
+
setConstrainHeight(true);
|
|
635
|
+
}
|
|
636
|
+
if (keyMatchers[Command.SHOW_ERROR_DETAILS](key)) {
|
|
637
|
+
setShowErrorDetails((prev) => !prev);
|
|
638
|
+
}
|
|
639
|
+
else if (keyMatchers[Command.TOGGLE_TOOL_DESCRIPTIONS](key)) {
|
|
640
|
+
const newValue = !showToolDescriptions;
|
|
641
|
+
setShowToolDescriptions(newValue);
|
|
642
|
+
const mcpServers = config.getMcpServers();
|
|
643
|
+
if (Object.keys(mcpServers || {}).length > 0) {
|
|
644
|
+
handleSlashCommand(newValue ? '/mcp desc' : '/mcp nodesc');
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
else if (keyMatchers[Command.TOGGLE_IDE_CONTEXT_DETAIL](key) &&
|
|
648
|
+
config.getIdeMode() &&
|
|
649
|
+
ideContextState) {
|
|
650
|
+
handleSlashCommand('/ide status');
|
|
651
|
+
}
|
|
652
|
+
else if (keyMatchers[Command.QUIT](key)) {
|
|
653
|
+
if (!ctrlCPressedOnce) {
|
|
654
|
+
cancelOngoingRequest?.();
|
|
655
|
+
}
|
|
656
|
+
handleExit(ctrlCPressedOnce, setCtrlCPressedOnce, ctrlCTimerRef);
|
|
657
|
+
}
|
|
658
|
+
else if (keyMatchers[Command.EXIT](key)) {
|
|
659
|
+
if (buffer.text.length > 0) {
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
handleExit(ctrlDPressedOnce, setCtrlDPressedOnce, ctrlDTimerRef);
|
|
663
|
+
}
|
|
664
|
+
else if (keyMatchers[Command.SHOW_MORE_LINES](key) &&
|
|
665
|
+
!enteringConstrainHeightMode) {
|
|
666
|
+
setConstrainHeight(false);
|
|
667
|
+
}
|
|
668
|
+
}, [
|
|
669
|
+
constrainHeight,
|
|
670
|
+
setConstrainHeight,
|
|
671
|
+
setShowErrorDetails,
|
|
672
|
+
showToolDescriptions,
|
|
673
|
+
setShowToolDescriptions,
|
|
674
|
+
config,
|
|
675
|
+
ideContextState,
|
|
676
|
+
handleExit,
|
|
677
|
+
ctrlCPressedOnce,
|
|
678
|
+
setCtrlCPressedOnce,
|
|
679
|
+
ctrlCTimerRef,
|
|
680
|
+
buffer.text.length,
|
|
681
|
+
ctrlDPressedOnce,
|
|
682
|
+
setCtrlDPressedOnce,
|
|
683
|
+
ctrlDTimerRef,
|
|
684
|
+
handleSlashCommand,
|
|
685
|
+
cancelOngoingRequest,
|
|
686
|
+
isThemeDialogOpen,
|
|
687
|
+
isAuthDialogOpen,
|
|
688
|
+
isEditorDialogOpen,
|
|
689
|
+
isSettingsDialogOpen,
|
|
690
|
+
isFolderTrustDialogOpen,
|
|
691
|
+
showPrivacyNotice,
|
|
692
|
+
settings.merged.general?.debugKeystrokeLogging,
|
|
693
|
+
]);
|
|
694
|
+
useKeypress(handleGlobalKeypress, { isActive: true });
|
|
695
|
+
useKeypress((key) => {
|
|
696
|
+
if (key.name === 'r' || key.name === 'R') {
|
|
697
|
+
process.exit(0);
|
|
698
|
+
}
|
|
699
|
+
}, { isActive: showIdeRestartPrompt });
|
|
700
|
+
const filteredConsoleMessages = useMemo(() => {
|
|
701
|
+
if (config.getDebugMode()) {
|
|
702
|
+
return consoleMessages;
|
|
703
|
+
}
|
|
704
|
+
return consoleMessages.filter((msg) => msg.type !== 'debug');
|
|
705
|
+
}, [consoleMessages, config]);
|
|
706
|
+
// Computed values
|
|
707
|
+
const errorCount = useMemo(() => filteredConsoleMessages
|
|
708
|
+
.filter((msg) => msg.type === 'error')
|
|
709
|
+
.reduce((total, msg) => total + msg.count, 0), [filteredConsoleMessages]);
|
|
710
|
+
const nightly = props.version.includes('nightly');
|
|
711
|
+
const dialogsVisible = useMemo(() => showWorkspaceMigrationDialog ||
|
|
712
|
+
shouldShowIdePrompt ||
|
|
713
|
+
isFolderTrustDialogOpen ||
|
|
714
|
+
!!shellConfirmationRequest ||
|
|
715
|
+
!!confirmationRequest ||
|
|
716
|
+
isThemeDialogOpen ||
|
|
717
|
+
isSettingsDialogOpen ||
|
|
718
|
+
isAuthenticating ||
|
|
719
|
+
isAuthDialogOpen ||
|
|
720
|
+
isEditorDialogOpen ||
|
|
721
|
+
showPrivacyNotice ||
|
|
722
|
+
isProQuotaDialogOpen, [
|
|
723
|
+
showWorkspaceMigrationDialog,
|
|
724
|
+
shouldShowIdePrompt,
|
|
725
|
+
isFolderTrustDialogOpen,
|
|
726
|
+
shellConfirmationRequest,
|
|
727
|
+
confirmationRequest,
|
|
728
|
+
isThemeDialogOpen,
|
|
729
|
+
isSettingsDialogOpen,
|
|
730
|
+
isAuthenticating,
|
|
731
|
+
isAuthDialogOpen,
|
|
732
|
+
isEditorDialogOpen,
|
|
733
|
+
showPrivacyNotice,
|
|
734
|
+
isProQuotaDialogOpen,
|
|
735
|
+
]);
|
|
736
|
+
const pendingHistoryItems = useMemo(() => [...pendingSlashCommandHistoryItems, ...pendingGeminiHistoryItems], [pendingSlashCommandHistoryItems, pendingGeminiHistoryItems]);
|
|
737
|
+
const uiState = useMemo(() => ({
|
|
738
|
+
history: historyManager.history,
|
|
739
|
+
isThemeDialogOpen,
|
|
740
|
+
themeError,
|
|
741
|
+
isAuthenticating,
|
|
742
|
+
authError,
|
|
743
|
+
isAuthDialogOpen,
|
|
744
|
+
editorError,
|
|
745
|
+
isEditorDialogOpen,
|
|
746
|
+
showPrivacyNotice,
|
|
747
|
+
corgiMode,
|
|
748
|
+
debugMessage,
|
|
749
|
+
quittingMessages,
|
|
750
|
+
isSettingsDialogOpen,
|
|
751
|
+
slashCommands,
|
|
752
|
+
pendingSlashCommandHistoryItems,
|
|
753
|
+
commandContext,
|
|
754
|
+
shellConfirmationRequest,
|
|
755
|
+
confirmationRequest,
|
|
756
|
+
geminiMdFileCount,
|
|
757
|
+
streamingState,
|
|
758
|
+
initError,
|
|
759
|
+
pendingGeminiHistoryItems,
|
|
760
|
+
thought,
|
|
761
|
+
shellModeActive,
|
|
762
|
+
userMessages,
|
|
763
|
+
buffer,
|
|
764
|
+
inputWidth,
|
|
765
|
+
suggestionsWidth,
|
|
766
|
+
isInputActive,
|
|
767
|
+
shouldShowIdePrompt,
|
|
768
|
+
isFolderTrustDialogOpen: isFolderTrustDialogOpen ?? false,
|
|
769
|
+
isTrustedFolder,
|
|
770
|
+
constrainHeight,
|
|
771
|
+
showErrorDetails,
|
|
772
|
+
filteredConsoleMessages,
|
|
773
|
+
ideContextState,
|
|
774
|
+
showToolDescriptions,
|
|
775
|
+
ctrlCPressedOnce,
|
|
776
|
+
ctrlDPressedOnce,
|
|
777
|
+
showEscapePrompt,
|
|
778
|
+
isFocused,
|
|
779
|
+
elapsedTime,
|
|
780
|
+
currentLoadingPhrase,
|
|
781
|
+
historyRemountKey,
|
|
782
|
+
messageQueue,
|
|
783
|
+
showAutoAcceptIndicator,
|
|
784
|
+
showWorkspaceMigrationDialog,
|
|
785
|
+
workspaceExtensions,
|
|
786
|
+
// Use current state values instead of config.getModel()
|
|
787
|
+
currentModel,
|
|
788
|
+
userTier,
|
|
789
|
+
isProQuotaDialogOpen,
|
|
790
|
+
// New fields
|
|
791
|
+
contextFileNames,
|
|
792
|
+
errorCount,
|
|
793
|
+
availableTerminalHeight,
|
|
794
|
+
mainAreaWidth,
|
|
795
|
+
staticAreaMaxItemHeight,
|
|
796
|
+
staticExtraHeight,
|
|
797
|
+
dialogsVisible,
|
|
798
|
+
pendingHistoryItems,
|
|
799
|
+
nightly,
|
|
800
|
+
branchName,
|
|
801
|
+
sessionStats,
|
|
802
|
+
terminalWidth,
|
|
803
|
+
terminalHeight,
|
|
804
|
+
mainControlsRef,
|
|
805
|
+
currentIDE,
|
|
806
|
+
updateInfo,
|
|
807
|
+
showIdeRestartPrompt,
|
|
808
|
+
isRestarting,
|
|
809
|
+
}), [
|
|
810
|
+
historyManager.history,
|
|
811
|
+
isThemeDialogOpen,
|
|
812
|
+
themeError,
|
|
813
|
+
isAuthenticating,
|
|
814
|
+
authError,
|
|
815
|
+
isAuthDialogOpen,
|
|
816
|
+
editorError,
|
|
817
|
+
isEditorDialogOpen,
|
|
818
|
+
showPrivacyNotice,
|
|
819
|
+
corgiMode,
|
|
820
|
+
debugMessage,
|
|
821
|
+
quittingMessages,
|
|
822
|
+
isSettingsDialogOpen,
|
|
823
|
+
slashCommands,
|
|
824
|
+
pendingSlashCommandHistoryItems,
|
|
825
|
+
commandContext,
|
|
826
|
+
shellConfirmationRequest,
|
|
827
|
+
confirmationRequest,
|
|
828
|
+
geminiMdFileCount,
|
|
829
|
+
streamingState,
|
|
830
|
+
initError,
|
|
831
|
+
pendingGeminiHistoryItems,
|
|
832
|
+
thought,
|
|
833
|
+
shellModeActive,
|
|
834
|
+
userMessages,
|
|
835
|
+
buffer,
|
|
836
|
+
inputWidth,
|
|
837
|
+
suggestionsWidth,
|
|
838
|
+
isInputActive,
|
|
839
|
+
shouldShowIdePrompt,
|
|
840
|
+
isFolderTrustDialogOpen,
|
|
841
|
+
isTrustedFolder,
|
|
842
|
+
constrainHeight,
|
|
843
|
+
showErrorDetails,
|
|
844
|
+
filteredConsoleMessages,
|
|
845
|
+
ideContextState,
|
|
846
|
+
showToolDescriptions,
|
|
847
|
+
ctrlCPressedOnce,
|
|
848
|
+
ctrlDPressedOnce,
|
|
849
|
+
showEscapePrompt,
|
|
850
|
+
isFocused,
|
|
851
|
+
elapsedTime,
|
|
852
|
+
currentLoadingPhrase,
|
|
853
|
+
historyRemountKey,
|
|
854
|
+
messageQueue,
|
|
855
|
+
showAutoAcceptIndicator,
|
|
856
|
+
showWorkspaceMigrationDialog,
|
|
857
|
+
workspaceExtensions,
|
|
858
|
+
// Quota-related state dependencies
|
|
859
|
+
userTier,
|
|
860
|
+
isProQuotaDialogOpen,
|
|
861
|
+
// New fields dependencies
|
|
862
|
+
contextFileNames,
|
|
863
|
+
errorCount,
|
|
864
|
+
availableTerminalHeight,
|
|
865
|
+
mainAreaWidth,
|
|
866
|
+
staticAreaMaxItemHeight,
|
|
867
|
+
staticExtraHeight,
|
|
868
|
+
dialogsVisible,
|
|
869
|
+
pendingHistoryItems,
|
|
870
|
+
nightly,
|
|
871
|
+
branchName,
|
|
872
|
+
sessionStats,
|
|
873
|
+
terminalWidth,
|
|
874
|
+
terminalHeight,
|
|
875
|
+
mainControlsRef,
|
|
876
|
+
currentIDE,
|
|
877
|
+
updateInfo,
|
|
878
|
+
showIdeRestartPrompt,
|
|
879
|
+
isRestarting,
|
|
880
|
+
// Quota-related dependencies
|
|
881
|
+
currentModel,
|
|
882
|
+
]);
|
|
883
|
+
const uiActions = useMemo(() => ({
|
|
884
|
+
handleThemeSelect,
|
|
885
|
+
handleThemeHighlight,
|
|
886
|
+
handleAuthSelect,
|
|
887
|
+
setAuthState,
|
|
888
|
+
onAuthError,
|
|
889
|
+
handleEditorSelect,
|
|
890
|
+
exitEditorDialog,
|
|
891
|
+
exitPrivacyNotice: () => setShowPrivacyNotice(false),
|
|
892
|
+
closeSettingsDialog,
|
|
893
|
+
setShellModeActive,
|
|
894
|
+
vimHandleInput,
|
|
895
|
+
handleIdePromptComplete,
|
|
896
|
+
handleFolderTrustSelect,
|
|
897
|
+
setConstrainHeight,
|
|
898
|
+
onEscapePromptChange: handleEscapePromptChange,
|
|
899
|
+
refreshStatic,
|
|
900
|
+
handleFinalSubmit,
|
|
901
|
+
handleClearScreen,
|
|
902
|
+
onWorkspaceMigrationDialogOpen,
|
|
903
|
+
onWorkspaceMigrationDialogClose,
|
|
904
|
+
handleProQuotaChoice,
|
|
905
|
+
}), [
|
|
906
|
+
handleThemeSelect,
|
|
907
|
+
handleThemeHighlight,
|
|
908
|
+
handleAuthSelect,
|
|
909
|
+
setAuthState,
|
|
910
|
+
onAuthError,
|
|
911
|
+
handleEditorSelect,
|
|
912
|
+
exitEditorDialog,
|
|
913
|
+
closeSettingsDialog,
|
|
914
|
+
setShellModeActive,
|
|
915
|
+
vimHandleInput,
|
|
916
|
+
handleIdePromptComplete,
|
|
917
|
+
handleFolderTrustSelect,
|
|
918
|
+
setConstrainHeight,
|
|
919
|
+
handleEscapePromptChange,
|
|
920
|
+
refreshStatic,
|
|
921
|
+
handleFinalSubmit,
|
|
922
|
+
handleClearScreen,
|
|
923
|
+
onWorkspaceMigrationDialogOpen,
|
|
924
|
+
onWorkspaceMigrationDialogClose,
|
|
925
|
+
handleProQuotaChoice,
|
|
926
|
+
]);
|
|
927
|
+
return (_jsx(UIStateContext.Provider, { value: uiState, children: _jsx(UIActionsContext.Provider, { value: uiActions, children: _jsx(ConfigContext.Provider, { value: config, children: _jsx(AppContext.Provider, { value: {
|
|
928
|
+
version: props.version,
|
|
929
|
+
startupWarnings: props.startupWarnings || [],
|
|
930
|
+
}, children: _jsx(App, {}) }) }) }) }));
|
|
931
|
+
};
|
|
932
|
+
//# sourceMappingURL=AppContainer.js.map
|