@vybestack/llxprt-code 0.1.14 → 0.1.16
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/README.md +90 -2
- package/dist/package.json +4 -5
- package/dist/src/config/config.d.ts +4 -1
- package/dist/src/config/config.js +151 -54
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/extension.d.ts +1 -0
- package/dist/src/config/extension.js +4 -0
- package/dist/src/config/extension.js.map +1 -1
- package/dist/src/config/settings.d.ts +13 -3
- package/dist/src/config/settings.js +84 -23
- package/dist/src/config/settings.js.map +1 -1
- package/dist/src/gemini.d.ts +3 -0
- package/dist/src/gemini.js +212 -36
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +1 -1
- package/dist/src/generated/git-commit.js +1 -1
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/integration-tests/GITHUB_ACTIONS_README.md +41 -0
- package/dist/src/integration-tests/test-utils.d.ts +68 -0
- package/dist/src/integration-tests/test-utils.js +167 -0
- package/dist/src/integration-tests/test-utils.js.map +1 -0
- package/dist/src/nonInteractiveCli.js +24 -66
- package/dist/src/nonInteractiveCli.js.map +1 -1
- package/dist/src/providers/IFileSystem.d.ts +42 -0
- package/dist/src/providers/IFileSystem.js +46 -0
- package/dist/src/providers/IFileSystem.js.map +1 -0
- package/dist/src/providers/providerConfigUtils.d.ts +0 -4
- package/dist/src/providers/providerConfigUtils.js +21 -52
- package/dist/src/providers/providerConfigUtils.js.map +1 -1
- package/dist/src/providers/providerManagerInstance.d.ts +6 -1
- package/dist/src/providers/providerManagerInstance.js +117 -82
- package/dist/src/providers/providerManagerInstance.js.map +1 -1
- package/dist/src/services/BuiltinCommandLoader.js +13 -0
- package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
- package/dist/src/services/CommandService.d.ts +8 -4
- package/dist/src/services/CommandService.js +24 -8
- package/dist/src/services/CommandService.js.map +1 -1
- package/dist/src/services/FileCommandLoader.d.ts +15 -3
- package/dist/src/services/FileCommandLoader.js +94 -42
- package/dist/src/services/FileCommandLoader.js.map +1 -1
- package/dist/src/services/McpPromptLoader.d.ts +25 -0
- package/dist/src/services/McpPromptLoader.js +192 -0
- package/dist/src/services/McpPromptLoader.js.map +1 -0
- package/dist/src/services/prompt-processors/shellProcessor.d.ts +32 -0
- package/dist/src/services/prompt-processors/shellProcessor.js +77 -0
- package/dist/src/services/prompt-processors/shellProcessor.js.map +1 -0
- package/dist/src/services/prompt-processors/types.d.ts +4 -0
- package/dist/src/services/prompt-processors/types.js +4 -0
- package/dist/src/services/prompt-processors/types.js.map +1 -1
- package/dist/src/ui/App.js +325 -195
- package/dist/src/ui/App.js.map +1 -1
- package/dist/src/ui/commands/aboutCommand.js +2 -5
- package/dist/src/ui/commands/aboutCommand.js.map +1 -1
- package/dist/src/ui/commands/baseurlCommand.js +54 -9
- package/dist/src/ui/commands/baseurlCommand.js.map +1 -1
- package/dist/src/ui/commands/chatCommand.js +39 -1
- package/dist/src/ui/commands/chatCommand.js.map +1 -1
- package/dist/src/ui/commands/diagnosticsCommand.d.ts +10 -0
- package/dist/src/ui/commands/diagnosticsCommand.js +122 -0
- package/dist/src/ui/commands/diagnosticsCommand.js.map +1 -0
- package/dist/src/ui/commands/directoryCommand.d.ts +8 -0
- package/dist/src/ui/commands/directoryCommand.js +116 -0
- package/dist/src/ui/commands/directoryCommand.js.map +1 -0
- package/dist/src/ui/commands/ideCommand.js +101 -105
- package/dist/src/ui/commands/ideCommand.js.map +1 -1
- package/dist/src/ui/commands/initCommand.d.ts +7 -0
- package/dist/src/ui/commands/initCommand.js +108 -0
- package/dist/src/ui/commands/initCommand.js.map +1 -0
- package/dist/src/ui/commands/keyCommand.js +75 -11
- package/dist/src/ui/commands/keyCommand.js.map +1 -1
- package/dist/src/ui/commands/keyfileCommand.js +54 -13
- package/dist/src/ui/commands/keyfileCommand.js.map +1 -1
- package/dist/src/ui/commands/mcpCommand.js +53 -8
- package/dist/src/ui/commands/mcpCommand.js.map +1 -1
- package/dist/src/ui/commands/memoryCommand.js +2 -1
- package/dist/src/ui/commands/memoryCommand.js.map +1 -1
- package/dist/src/ui/commands/modelCommand.js +2 -5
- package/dist/src/ui/commands/modelCommand.js.map +1 -1
- package/dist/src/ui/commands/profileCommand.d.ts +10 -0
- package/dist/src/ui/commands/profileCommand.js +592 -0
- package/dist/src/ui/commands/profileCommand.js.map +1 -0
- package/dist/src/ui/commands/providerCommand.js +46 -3
- package/dist/src/ui/commands/providerCommand.js.map +1 -1
- package/dist/src/ui/commands/setCommand.d.ts +7 -0
- package/dist/src/ui/commands/setCommand.js +431 -0
- package/dist/src/ui/commands/setCommand.js.map +1 -0
- package/dist/src/ui/commands/setupGithubCommand.d.ts +7 -0
- package/dist/src/ui/commands/setupGithubCommand.js +49 -0
- package/dist/src/ui/commands/setupGithubCommand.js.map +1 -0
- package/dist/src/ui/commands/types.d.ts +23 -4
- package/dist/src/ui/commands/types.js +1 -0
- package/dist/src/ui/commands/types.js.map +1 -1
- package/dist/src/ui/commands/vimCommand.js +0 -7
- package/dist/src/ui/commands/vimCommand.js.map +1 -1
- package/dist/src/ui/components/ContextSummaryDisplay.d.ts +3 -3
- package/dist/src/ui/components/ContextSummaryDisplay.js +8 -8
- package/dist/src/ui/components/ContextSummaryDisplay.js.map +1 -1
- package/dist/src/ui/components/DebugProfiler.d.ts +6 -0
- package/dist/src/ui/components/DebugProfiler.js +26 -0
- package/dist/src/ui/components/DebugProfiler.js.map +1 -0
- package/dist/src/ui/components/Footer.d.ts +2 -0
- package/dist/src/ui/components/Footer.js +5 -4
- package/dist/src/ui/components/Footer.js.map +1 -1
- package/dist/src/ui/components/Header.js +1 -1
- package/dist/src/ui/components/Header.js.map +1 -1
- package/dist/src/ui/components/Help.js +2 -2
- package/dist/src/ui/components/Help.js.map +1 -1
- package/dist/src/ui/components/IDEContextDetailDisplay.d.ts +5 -4
- package/dist/src/ui/components/IDEContextDetailDisplay.js +6 -8
- package/dist/src/ui/components/IDEContextDetailDisplay.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.d.ts +2 -0
- package/dist/src/ui/components/InputPrompt.js +128 -13
- package/dist/src/ui/components/InputPrompt.js.map +1 -1
- package/dist/src/ui/components/LoadProfileDialog.d.ts +13 -0
- package/dist/src/ui/components/LoadProfileDialog.js +57 -0
- package/dist/src/ui/components/LoadProfileDialog.js.map +1 -0
- package/dist/src/ui/components/PrepareLabel.d.ts +15 -0
- package/dist/src/ui/components/PrepareLabel.js +16 -0
- package/dist/src/ui/components/PrepareLabel.js.map +1 -0
- package/dist/src/ui/components/ProviderModelDialog.js +75 -28
- package/dist/src/ui/components/ProviderModelDialog.js.map +1 -1
- package/dist/src/ui/components/SecureKeyInput.d.ts +15 -0
- package/dist/src/ui/components/SecureKeyInput.js +58 -0
- package/dist/src/ui/components/SecureKeyInput.js.map +1 -0
- package/dist/src/ui/components/ShellConfirmationDialog.d.ts +15 -0
- package/dist/src/ui/components/ShellConfirmationDialog.js +45 -0
- package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -0
- package/dist/src/ui/components/SuggestionsDisplay.d.ts +1 -0
- package/dist/src/ui/components/SuggestionsDisplay.js +3 -3
- package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -1
- package/dist/src/ui/components/Tips.js +1 -1
- package/dist/src/ui/components/Tips.js.map +1 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js +15 -4
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
- package/dist/src/ui/components/messages/UserMessage.js +4 -1
- package/dist/src/ui/components/messages/UserMessage.js.map +1 -1
- package/dist/src/ui/components/shared/text-buffer.d.ts +270 -2
- package/dist/src/ui/components/shared/text-buffer.js +410 -70
- package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
- package/dist/src/ui/components/shared/vim-buffer-actions.d.ts +72 -0
- package/dist/src/ui/components/shared/vim-buffer-actions.js +565 -0
- package/dist/src/ui/components/shared/vim-buffer-actions.js.map +1 -0
- package/dist/src/ui/containers/SessionController.js +14 -15
- package/dist/src/ui/containers/SessionController.js.map +1 -1
- package/dist/src/ui/contexts/VimModeContext.js +2 -2
- package/dist/src/ui/contexts/VimModeContext.js.map +1 -1
- package/dist/src/ui/editors/editorSettingsManager.js +2 -0
- package/dist/src/ui/editors/editorSettingsManager.js.map +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.js +56 -48
- package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/shellCommandProcessor.d.ts +1 -0
- package/dist/src/ui/hooks/shellCommandProcessor.js +139 -200
- package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.d.ts +7 -3
- package/dist/src/ui/hooks/slashCommandProcessor.js +219 -130
- package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/useAuthCommand.js +9 -0
- package/dist/src/ui/hooks/useAuthCommand.js.map +1 -1
- package/dist/src/ui/hooks/useCompletion.d.ts +5 -5
- package/dist/src/ui/hooks/useCompletion.js +7 -402
- package/dist/src/ui/hooks/useCompletion.js.map +1 -1
- package/dist/src/ui/hooks/useConsoleMessages.js +53 -37
- package/dist/src/ui/hooks/useConsoleMessages.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.js +58 -12
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useKeypress.js +5 -2
- package/dist/src/ui/hooks/useKeypress.js.map +1 -1
- package/dist/src/ui/hooks/useLoadProfileDialog.d.ts +27 -0
- package/dist/src/ui/hooks/useLoadProfileDialog.js +138 -0
- package/dist/src/ui/hooks/useLoadProfileDialog.js.map +1 -0
- package/dist/src/ui/hooks/useReactToolScheduler.js +0 -1
- package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
- package/dist/src/ui/hooks/useReverseSearchCompletion.d.ts +19 -0
- package/dist/src/ui/hooks/useReverseSearchCompletion.js +54 -0
- package/dist/src/ui/hooks/useReverseSearchCompletion.js.map +1 -0
- package/dist/src/ui/hooks/useShellHistory.d.ts +1 -0
- package/dist/src/ui/hooks/useShellHistory.js +30 -7
- package/dist/src/ui/hooks/useShellHistory.js.map +1 -1
- package/dist/src/ui/hooks/useSlashCompletion.d.ts +24 -0
- package/dist/src/ui/hooks/useSlashCompletion.js +451 -0
- package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -0
- package/dist/src/ui/hooks/vim.d.ts +28 -0
- package/dist/src/ui/hooks/vim.js +630 -0
- package/dist/src/ui/hooks/vim.js.map +1 -0
- package/dist/src/ui/reducers/appReducer.d.ts +3 -2
- package/dist/src/ui/reducers/appReducer.js +1 -0
- package/dist/src/ui/reducers/appReducer.js.map +1 -1
- package/dist/src/ui/themes/theme-manager.js +10 -1
- package/dist/src/ui/themes/theme-manager.js.map +1 -1
- package/dist/src/ui/themes/theme.d.ts +1 -0
- package/dist/src/ui/themes/theme.js +19 -4
- package/dist/src/ui/themes/theme.js.map +1 -1
- package/dist/src/ui/utils/renderLoopDetector.js +3 -3
- package/dist/src/ui/utils/renderLoopDetector.js.map +1 -1
- package/dist/src/ui/utils/secureInputHandler.d.ts +46 -0
- package/dist/src/ui/utils/secureInputHandler.js +128 -0
- package/dist/src/ui/utils/secureInputHandler.js.map +1 -0
- package/dist/src/ui/utils/textUtils.d.ts +0 -8
- package/dist/src/ui/utils/textUtils.js +0 -22
- package/dist/src/ui/utils/textUtils.js.map +1 -1
- package/dist/src/ui/utils/updateCheck.d.ts +7 -1
- package/dist/src/ui/utils/updateCheck.js +59 -25
- package/dist/src/ui/utils/updateCheck.js.map +1 -1
- package/dist/src/utils/events.d.ts +11 -0
- package/dist/src/utils/events.js +13 -0
- package/dist/src/utils/events.js.map +1 -0
- package/dist/src/utils/gitUtils.d.ts +10 -0
- package/dist/src/utils/gitUtils.js +24 -0
- package/dist/src/utils/gitUtils.js.map +1 -0
- package/dist/src/utils/handleAutoUpdate.d.ts +11 -0
- package/dist/src/utils/handleAutoUpdate.js +101 -0
- package/dist/src/utils/handleAutoUpdate.js.map +1 -0
- package/dist/src/utils/installationInfo.d.ts +23 -0
- package/dist/src/utils/installationInfo.js +154 -0
- package/dist/src/utils/installationInfo.js.map +1 -0
- package/dist/src/utils/sandbox-macos-permissive-closed.sb +6 -0
- package/dist/src/utils/sandbox-macos-permissive-open.sb +6 -0
- package/dist/src/utils/sandbox-macos-permissive-proxied.sb +6 -0
- package/dist/src/utils/sandbox-macos-restrictive-closed.sb +6 -0
- package/dist/src/utils/sandbox-macos-restrictive-open.sb +6 -0
- package/dist/src/utils/sandbox-macos-restrictive-proxied.sb +6 -0
- package/dist/src/utils/sandbox.d.ts +2 -2
- package/dist/src/utils/sandbox.js +35 -11
- package/dist/src/utils/sandbox.js.map +1 -1
- package/dist/src/utils/spawnWrapper.d.ts +7 -0
- package/dist/src/utils/spawnWrapper.js +8 -0
- package/dist/src/utils/spawnWrapper.js.map +1 -0
- package/dist/src/utils/updateEventEmitter.d.ts +11 -0
- package/dist/src/utils/updateEventEmitter.js +12 -0
- package/dist/src/utils/updateEventEmitter.js.map +1 -0
- package/dist/src/validateNonInterActiveAuth.d.ts +2 -1
- package/dist/src/validateNonInterActiveAuth.js +31 -5
- package/dist/src/validateNonInterActiveAuth.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -5
- package/dist/src/providers/enhanceConfigWithProviders.d.ts +0 -12
- package/dist/src/providers/enhanceConfigWithProviders.js +0 -16
- package/dist/src/providers/enhanceConfigWithProviders.js.map +0 -1
package/dist/src/ui/App.js
CHANGED
@@ -4,18 +4,15 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
4
4
|
* Copyright 2025 Google LLC
|
5
5
|
* SPDX-License-Identifier: Apache-2.0
|
6
6
|
*/
|
7
|
-
import { useCallback, useEffect, useMemo, useState, useRef } from 'react';
|
8
|
-
import { Box, Static, Text, useStdin, useStdout, useInput, } from 'ink';
|
9
|
-
import { StreamingState } from './types.js';
|
7
|
+
import { useCallback, useEffect, useMemo, useState, useRef, useReducer, } from 'react';
|
8
|
+
import { Box, measureElement, Static, Text, useStdin, useStdout, useInput, } from 'ink';
|
9
|
+
import { StreamingState, MessageType } from './types.js';
|
10
|
+
import { useTerminalSize } from './hooks/useTerminalSize.js';
|
10
11
|
import { useGeminiStream } from './hooks/useGeminiStream.js';
|
11
12
|
import { useLoadingIndicator } from './hooks/useLoadingIndicator.js';
|
12
13
|
import { useThemeCommand } from './hooks/useThemeCommand.js';
|
13
14
|
import { useAuthCommand } from './hooks/useAuthCommand.js';
|
14
15
|
import { useEditorSettings } from './hooks/useEditorSettings.js';
|
15
|
-
import { useProviderModelDialog } from './hooks/useProviderModelDialog.js';
|
16
|
-
import { useProviderDialog } from './hooks/useProviderDialog.js';
|
17
|
-
import { ProviderModelDialog } from './components/ProviderModelDialog.js';
|
18
|
-
import { ProviderDialog } from './components/ProviderDialog.js';
|
19
16
|
import { useSlashCommandProcessor } from './hooks/slashCommandProcessor.js';
|
20
17
|
import { useAutoAcceptIndicator } from './hooks/useAutoAcceptIndicator.js';
|
21
18
|
import { useConsoleMessages } from './hooks/useConsoleMessages.js';
|
@@ -29,8 +26,10 @@ import { ThemeDialog } from './components/ThemeDialog.js';
|
|
29
26
|
import { AuthDialog } from './components/AuthDialog.js';
|
30
27
|
import { AuthInProgress } from './components/AuthInProgress.js';
|
31
28
|
import { EditorSettingsDialog } from './components/EditorSettingsDialog.js';
|
29
|
+
import { ShellConfirmationDialog } from './components/ShellConfirmationDialog.js';
|
32
30
|
import { Colors } from './colors.js';
|
33
31
|
import { Help } from './components/Help.js';
|
32
|
+
import { loadHierarchicalLlxprtMemory } from '../config/config.js';
|
34
33
|
import { Tips } from './components/Tips.js';
|
35
34
|
import { ConsolePatcher } from './utils/ConsolePatcher.js';
|
36
35
|
import { registerCleanup } from '../utils/cleanup.js';
|
@@ -38,9 +37,9 @@ import { DetailedMessagesDisplay } from './components/DetailedMessagesDisplay.js
|
|
38
37
|
import { HistoryItemDisplay } from './components/HistoryItemDisplay.js';
|
39
38
|
import { ContextSummaryDisplay } from './components/ContextSummaryDisplay.js';
|
40
39
|
import { IDEContextDetailDisplay } from './components/IDEContextDetailDisplay.js';
|
41
|
-
|
40
|
+
import { useHistory } from './hooks/useHistoryManager.js';
|
42
41
|
import process from 'node:process';
|
43
|
-
import { getAllLlxprtMdFilenames, ApprovalMode, isEditorAvailable, ideContext, } from '@vybestack/llxprt-code-core';
|
42
|
+
import { getErrorMessage, getAllLlxprtMdFilenames, ApprovalMode, isEditorAvailable, FlashFallbackEvent, logFlashFallback, AuthType, ideContext, } from '@vybestack/llxprt-code-core';
|
44
43
|
import { validateAuthMethod } from '../config/auth.js';
|
45
44
|
import { useLogger } from './hooks/useLogger.js';
|
46
45
|
import { StreamingContext } from './contexts/StreamingContext.js';
|
@@ -49,32 +48,45 @@ import { useGitBranchName } from './hooks/useGitBranchName.js';
|
|
49
48
|
import { useFocus } from './hooks/useFocus.js';
|
50
49
|
import { useBracketedPaste } from './hooks/useBracketedPaste.js';
|
51
50
|
import { useTextBuffer } from './components/shared/text-buffer.js';
|
51
|
+
import { useVimMode, VimModeProvider } from './contexts/VimModeContext.js';
|
52
|
+
import { useVim } from './hooks/vim.js';
|
52
53
|
import * as fs from 'fs';
|
54
|
+
import { appReducer, initialAppState, } from './reducers/appReducer.js';
|
55
|
+
import { AppDispatchProvider } from './contexts/AppDispatchContext.js';
|
53
56
|
import { UpdateNotification } from './components/UpdateNotification.js';
|
54
|
-
|
55
|
-
import { checkForUpdates } from './utils/updateCheck.js';
|
57
|
+
import { isProQuotaExceededError, isGenericQuotaExceededError, UserTierId, } from '@vybestack/llxprt-code-core';
|
56
58
|
import ansiEscapes from 'ansi-escapes';
|
57
59
|
import { OverflowProvider } from './contexts/OverflowContext.js';
|
58
60
|
import { ShowMoreLines } from './components/ShowMoreLines.js';
|
59
61
|
import { PrivacyNotice } from './privacy/PrivacyNotice.js';
|
62
|
+
import { setUpdateHandler } from '../utils/handleAutoUpdate.js';
|
63
|
+
import { appEvents, AppEvent } from '../utils/events.js';
|
60
64
|
import { getProviderManager } from '../providers/providerManagerInstance.js';
|
61
|
-
import {
|
62
|
-
import {
|
63
|
-
import {
|
64
|
-
import {
|
65
|
+
import { useProviderModelDialog } from './hooks/useProviderModelDialog.js';
|
66
|
+
import { useProviderDialog } from './hooks/useProviderDialog.js';
|
67
|
+
import { useLoadProfileDialog } from './hooks/useLoadProfileDialog.js';
|
68
|
+
import { ProviderModelDialog } from './components/ProviderModelDialog.js';
|
69
|
+
import { ProviderDialog } from './components/ProviderDialog.js';
|
70
|
+
import { LoadProfileDialog } from './components/LoadProfileDialog.js';
|
65
71
|
const CTRL_EXIT_PROMPT_DURATION_MS = 1000;
|
66
|
-
export const AppWrapper = (props) => (_jsx(SessionStatsProvider, { children: _jsx(
|
67
|
-
//
|
68
|
-
const
|
72
|
+
export const AppWrapper = (props) => (_jsx(SessionStatsProvider, { children: _jsx(VimModeProvider, { settings: props.settings, children: _jsx(AppWithState, { ...props }) }) }));
|
73
|
+
// New intermediate component that manages state and provides context
|
74
|
+
const AppWithState = (props) => {
|
75
|
+
const [appState, appDispatch] = useReducer(appReducer, initialAppState);
|
76
|
+
return (_jsx(AppDispatchProvider, { value: appDispatch, children: _jsx(App, { ...props, appState: appState, appDispatch: appDispatch }) }));
|
77
|
+
};
|
78
|
+
const App = (props) => {
|
79
|
+
const { config, settings, startupWarnings = [], version, appState } = props;
|
69
80
|
const isFocused = useFocus();
|
70
81
|
useBracketedPaste();
|
71
|
-
const [
|
82
|
+
const [updateInfo, setUpdateInfo] = useState(null);
|
72
83
|
const { stdout } = useStdout();
|
73
84
|
const nightly = version.includes('nightly');
|
85
|
+
const { history, addItem, clearItems, loadHistory } = useHistory();
|
74
86
|
useEffect(() => {
|
75
|
-
|
76
|
-
|
77
|
-
|
87
|
+
const cleanup = setUpdateHandler(addItem, setUpdateInfo);
|
88
|
+
return cleanup;
|
89
|
+
}, [addItem]);
|
78
90
|
const { consoleMessages, handleNewMessage, clearConsoleMessages: clearConsoleMessagesState, } = useConsoleMessages();
|
79
91
|
useEffect(() => {
|
80
92
|
const consolePatcher = new ConsolePatcher({
|
@@ -85,37 +97,6 @@ const AppInner = ({ config, settings, startupWarnings = [], version, setIsAuthen
|
|
85
97
|
registerCleanup(consolePatcher.cleanup);
|
86
98
|
}, [handleNewMessage, config]);
|
87
99
|
const { stats: sessionStats } = useSessionStats();
|
88
|
-
// These are now managed by SessionController
|
89
|
-
const { currentModel, isPaidMode, transientWarnings: sessionTransientWarnings, modelSwitchedFromQuotaError, } = sessionState;
|
90
|
-
// Add payment mode warning to startup warnings only at startup
|
91
|
-
const allStartupWarnings = useMemo(() => {
|
92
|
-
const warnings = [...startupWarnings];
|
93
|
-
// Only show payment warnings at startup (when history is empty)
|
94
|
-
if (history.length === 0) {
|
95
|
-
try {
|
96
|
-
const providerManager = getProviderManager();
|
97
|
-
if (providerManager.hasActiveProvider()) {
|
98
|
-
const provider = providerManager.getActiveProvider();
|
99
|
-
const isPaidMode = provider.isPaidMode?.();
|
100
|
-
// Only show paid/free mode warnings for Gemini provider
|
101
|
-
if (isPaidMode !== undefined && provider.name === 'gemini') {
|
102
|
-
if (isPaidMode) {
|
103
|
-
warnings.push(`! PAID MODE: You are using Gemini with API credentials - usage will be charged to your account`);
|
104
|
-
}
|
105
|
-
else {
|
106
|
-
warnings.push(`FREE MODE: You are using Gemini with OAuth authentication - no charges will apply`);
|
107
|
-
}
|
108
|
-
}
|
109
|
-
}
|
110
|
-
}
|
111
|
-
catch (_e) {
|
112
|
-
// Ignore errors when checking payment mode
|
113
|
-
}
|
114
|
-
}
|
115
|
-
return warnings;
|
116
|
-
}, [startupWarnings, history]);
|
117
|
-
// Use transient warnings from session state
|
118
|
-
const transientWarnings = sessionTransientWarnings;
|
119
100
|
const [staticNeedsRefresh, setStaticNeedsRefresh] = useState(false);
|
120
101
|
const [staticKey, setStaticKey] = useState(0);
|
121
102
|
const refreshStatic = useCallback(() => {
|
@@ -125,6 +106,12 @@ const AppInner = ({ config, settings, startupWarnings = [], version, setIsAuthen
|
|
125
106
|
const [llxprtMdFileCount, setLlxprtMdFileCount] = useState(0);
|
126
107
|
const [debugMessage, setDebugMessage] = useState('');
|
127
108
|
const [showHelp, setShowHelp] = useState(false);
|
109
|
+
const [_themeError, _setThemeError] = useState(null);
|
110
|
+
const [authError, setAuthError] = useState(null);
|
111
|
+
const [_editorError, _setEditorError] = useState(null);
|
112
|
+
const [footerHeight, setFooterHeight] = useState(0);
|
113
|
+
const [_corgiMode, setCorgiMode] = useState(false);
|
114
|
+
const [currentModel, setCurrentModel] = useState(config.getModel());
|
128
115
|
const [shellModeActive, setShellModeActive] = useState(false);
|
129
116
|
const [showErrorDetails, setShowErrorDetails] = useState(false);
|
130
117
|
const [showToolDescriptions, setShowToolDescriptions] = useState(false);
|
@@ -134,92 +121,233 @@ const AppInner = ({ config, settings, startupWarnings = [], version, setIsAuthen
|
|
134
121
|
const ctrlCTimerRef = useRef(null);
|
135
122
|
const [ctrlDPressedOnce, setCtrlDPressedOnce] = useState(false);
|
136
123
|
const ctrlDTimerRef = useRef(null);
|
137
|
-
const
|
138
|
-
|
139
|
-
const [
|
140
|
-
const [
|
124
|
+
const [constrainHeight, setConstrainHeight] = useState(true);
|
125
|
+
const [showPrivacyNotice, setShowPrivacyNotice] = useState(false);
|
126
|
+
const [modelSwitchedFromQuotaError, setModelSwitchedFromQuotaError] = useState(false);
|
127
|
+
const [userTier, setUserTier] = useState(undefined);
|
128
|
+
const [ideContextState, setIdeContextState] = useState();
|
129
|
+
const [isProcessing, setIsProcessing] = useState(false);
|
130
|
+
const [providerModels, setProviderModels] = useState([]);
|
141
131
|
useEffect(() => {
|
142
|
-
const unsubscribe = ideContext.
|
132
|
+
const unsubscribe = ideContext.subscribeToIdeContext(setIdeContextState);
|
143
133
|
// Set the initial value
|
144
|
-
|
134
|
+
setIdeContextState(ideContext.getIdeContext());
|
145
135
|
return unsubscribe;
|
146
136
|
}, []);
|
137
|
+
useEffect(() => {
|
138
|
+
const openDebugConsole = () => {
|
139
|
+
setShowErrorDetails(true);
|
140
|
+
setConstrainHeight(false); // Make sure the user sees the full message.
|
141
|
+
};
|
142
|
+
appEvents.on(AppEvent.OpenDebugConsole, openDebugConsole);
|
143
|
+
const logErrorHandler = (errorMessage) => {
|
144
|
+
handleNewMessage({
|
145
|
+
type: 'error',
|
146
|
+
content: String(errorMessage),
|
147
|
+
count: 1,
|
148
|
+
});
|
149
|
+
};
|
150
|
+
appEvents.on(AppEvent.LogError, logErrorHandler);
|
151
|
+
return () => {
|
152
|
+
appEvents.off(AppEvent.OpenDebugConsole, openDebugConsole);
|
153
|
+
appEvents.off(AppEvent.LogError, logErrorHandler);
|
154
|
+
};
|
155
|
+
}, [handleNewMessage]);
|
147
156
|
const openPrivacyNotice = useCallback(() => {
|
148
|
-
|
149
|
-
}, [
|
150
|
-
const closePrivacyNotice = useCallback(() => {
|
151
|
-
appDispatch({ type: 'CLOSE_DIALOG', payload: 'privacy' });
|
152
|
-
}, [appDispatch]);
|
157
|
+
setShowPrivacyNotice(true);
|
158
|
+
}, []);
|
153
159
|
const initialPromptSubmitted = useRef(false);
|
154
|
-
const errorCount = useMemo(() => consoleMessages
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
payload: { itemData, baseTimestamp },
|
160
|
-
});
|
161
|
-
}, [appDispatch]);
|
162
|
-
const { isThemeDialogOpen, openThemeDialog, handleThemeSelect, handleThemeHighlight, } = useThemeCommand(settings, appState, addItemViaDispatch);
|
163
|
-
const { isAuthDialogOpen, openAuthDialog, handleAuthSelect, isAuthenticating: authIsAuthenticating, cancelAuthentication, } = useAuthCommand(settings, appState, config);
|
164
|
-
// Sync auth state with parent
|
165
|
-
useEffect(() => {
|
166
|
-
setIsAuthenticating(authIsAuthenticating);
|
167
|
-
}, [authIsAuthenticating, setIsAuthenticating]);
|
168
|
-
const onAuthTimeout = useCallback(() => {
|
169
|
-
appDispatch({
|
170
|
-
type: 'SET_AUTH_ERROR',
|
171
|
-
payload: 'Authentication timed out. Please try again.',
|
172
|
-
});
|
173
|
-
cancelAuthentication();
|
174
|
-
openAuthDialog();
|
175
|
-
}, [cancelAuthentication, openAuthDialog, appDispatch]);
|
160
|
+
const errorCount = useMemo(() => consoleMessages
|
161
|
+
.filter((msg) => msg.type === 'error')
|
162
|
+
.reduce((total, msg) => total + msg.count, 0), [consoleMessages]);
|
163
|
+
const { isThemeDialogOpen, openThemeDialog, handleThemeSelect, handleThemeHighlight, } = useThemeCommand(settings, appState, addItem);
|
164
|
+
const { isAuthDialogOpen, openAuthDialog, handleAuthSelect, isAuthenticating, cancelAuthentication, } = useAuthCommand(settings, appState, config);
|
176
165
|
useEffect(() => {
|
177
|
-
if (settings.merged.selectedAuthType) {
|
166
|
+
if (settings.merged.selectedAuthType && !settings.merged.useExternalAuth) {
|
178
167
|
const error = validateAuthMethod(settings.merged.selectedAuthType);
|
179
168
|
if (error) {
|
180
|
-
|
169
|
+
setAuthError(error);
|
181
170
|
openAuthDialog();
|
182
171
|
}
|
183
172
|
}
|
184
|
-
}, [
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
173
|
+
}, [
|
174
|
+
settings.merged.selectedAuthType,
|
175
|
+
settings.merged.useExternalAuth,
|
176
|
+
openAuthDialog,
|
177
|
+
setAuthError,
|
178
|
+
]);
|
179
|
+
// Sync user tier from config when authentication changes
|
180
|
+
useEffect(() => {
|
181
|
+
// Only sync when not currently authenticating
|
182
|
+
if (!isAuthenticating) {
|
183
|
+
setUserTier(config.getGeminiClient()?.getUserTier());
|
184
|
+
}
|
185
|
+
}, [config, isAuthenticating]);
|
186
|
+
const { isEditorDialogOpen, openEditorDialog, handleEditorSelect, exitEditorDialog, } = useEditorSettings(settings, appState, addItem);
|
187
|
+
const providerManager = getProviderManager(config);
|
188
|
+
const { showDialog: isProviderDialogOpen, openDialog: openProviderDialog, handleSelect: handleProviderSelect, closeDialog: exitProviderDialog, } = useProviderDialog({
|
189
|
+
addMessage: (msg) => addItem({ type: msg.type, text: msg.content }, msg.timestamp.getTime()),
|
193
190
|
appState,
|
191
|
+
config,
|
194
192
|
});
|
195
|
-
const
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
193
|
+
const { showDialog: isProviderModelDialogOpen, openDialog: openProviderModelDialogRaw, handleSelect: handleProviderModelChange, closeDialog: exitProviderModelDialog, } = useProviderModelDialog({
|
194
|
+
addMessage: (msg) => addItem({ type: msg.type, text: msg.content }, msg.timestamp.getTime()),
|
195
|
+
appState,
|
196
|
+
});
|
197
|
+
const openProviderModelDialog = useCallback(async () => {
|
198
|
+
try {
|
199
|
+
const activeProvider = providerManager.getActiveProvider();
|
200
|
+
if (activeProvider) {
|
201
|
+
const models = await activeProvider.getModels();
|
202
|
+
setProviderModels(models);
|
203
|
+
}
|
204
|
+
}
|
205
|
+
catch (e) {
|
206
|
+
console.error('Failed to load models:', e);
|
207
|
+
setProviderModels([]);
|
208
|
+
}
|
209
|
+
await openProviderModelDialogRaw();
|
210
|
+
}, [providerManager, openProviderModelDialogRaw]);
|
211
|
+
// Watch for model changes from config
|
212
|
+
useEffect(() => {
|
213
|
+
const checkModelChange = () => {
|
214
|
+
const configModel = config.getModel();
|
215
|
+
const activeProvider = providerManager.getActiveProvider();
|
216
|
+
// Get the actual current model from provider
|
217
|
+
const providerModel = activeProvider?.getCurrentModel?.() || configModel;
|
218
|
+
// Update UI if different from what we're showing
|
219
|
+
if (providerModel !== currentModel) {
|
220
|
+
console.debug(`[Model Update] Updating footer from ${currentModel} to ${providerModel}`);
|
221
|
+
setCurrentModel(providerModel);
|
222
|
+
}
|
223
|
+
};
|
224
|
+
// Check immediately
|
225
|
+
checkModelChange();
|
226
|
+
// Check periodically (every 500ms)
|
227
|
+
const interval = setInterval(checkModelChange, 500);
|
228
|
+
return () => clearInterval(interval);
|
229
|
+
}, [config, providerManager, currentModel]); // Include currentModel in dependencies
|
230
|
+
const toggleCorgiMode = useCallback(() => {
|
231
|
+
setCorgiMode((prev) => !prev);
|
232
|
+
}, []);
|
233
|
+
const { showDialog: isLoadProfileDialogOpen, openDialog: openLoadProfileDialog, handleSelect: handleProfileSelect, closeDialog: exitLoadProfileDialog, profiles, } = useLoadProfileDialog({
|
234
|
+
addMessage: (msg) => addItem({ type: msg.type, text: msg.content }, msg.timestamp.getTime()),
|
208
235
|
appState,
|
209
236
|
config,
|
210
|
-
|
237
|
+
settings,
|
211
238
|
});
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
239
|
+
const performMemoryRefresh = useCallback(async () => {
|
240
|
+
addItem({
|
241
|
+
type: MessageType.INFO,
|
242
|
+
text: 'Refreshing hierarchical memory (LLXPRT.md or other context files)...',
|
243
|
+
}, Date.now());
|
244
|
+
try {
|
245
|
+
const { memoryContent, fileCount } = await loadHierarchicalLlxprtMemory(process.cwd(), config.getDebugMode(), config.getFileService(), settings.merged, config.getExtensionContextFilePaths(), settings.merged.memoryImportFormat || 'tree', // Use setting or default to 'tree'
|
246
|
+
config.getFileFilteringOptions());
|
247
|
+
config.setUserMemory(memoryContent);
|
248
|
+
config.setLlxprtMdFileCount(fileCount);
|
249
|
+
setLlxprtMdFileCount(fileCount);
|
250
|
+
addItem({
|
251
|
+
type: MessageType.INFO,
|
252
|
+
text: `Memory refreshed successfully. ${memoryContent.length > 0 ? `Loaded ${memoryContent.length} characters from ${fileCount} file(s).` : 'No memory content found.'}`,
|
253
|
+
}, Date.now());
|
254
|
+
if (config.getDebugMode()) {
|
255
|
+
console.log(`[DEBUG] Refreshed memory content in config: ${memoryContent.substring(0, 200)}...`);
|
256
|
+
}
|
257
|
+
}
|
258
|
+
catch (error) {
|
259
|
+
const errorMessage = getErrorMessage(error);
|
260
|
+
addItem({
|
261
|
+
type: MessageType.ERROR,
|
262
|
+
text: `Error refreshing memory: ${errorMessage}`,
|
263
|
+
}, Date.now());
|
264
|
+
console.error('Error refreshing memory:', error);
|
265
|
+
}
|
266
|
+
}, [config, addItem, settings.merged]);
|
267
|
+
// Removed - consolidated into single useEffect above
|
268
|
+
// Set up Flash fallback handler
|
269
|
+
useEffect(() => {
|
270
|
+
const flashFallbackHandler = async (currentModel, fallbackModel, error) => {
|
271
|
+
let message;
|
272
|
+
const contentGenConfig = config.getContentGeneratorConfig();
|
273
|
+
const authType = contentGenConfig?.authType;
|
274
|
+
if (authType === AuthType.LOGIN_WITH_GOOGLE) {
|
275
|
+
// Use actual user tier if available; otherwise, default to FREE tier behavior (safe default)
|
276
|
+
const isPaidTier = userTier === UserTierId.LEGACY || userTier === UserTierId.STANDARD;
|
277
|
+
// Check if this is a Pro quota exceeded error
|
278
|
+
if (error && isProQuotaExceededError(error)) {
|
279
|
+
if (isPaidTier) {
|
280
|
+
message = `⚡ You have reached your daily ${currentModel} quota limit.
|
281
|
+
⚡ To continue using ${currentModel}, you can use /auth to switch to using a paid API key from AI Studio at https://aistudio.google.com/apikey
|
282
|
+
⚡ Or you can switch to a different model using the /model command`;
|
283
|
+
}
|
284
|
+
else {
|
285
|
+
message = `⚡ You have reached your daily ${currentModel} quota limit.
|
286
|
+
⚡ 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
|
287
|
+
⚡ Or you can utilize a Gemini API Key. See: https://goo.gle/gemini-cli-docs-auth#gemini-api-key
|
288
|
+
⚡ You can switch authentication methods by typing /auth or switch to a different model using /model`;
|
289
|
+
}
|
290
|
+
}
|
291
|
+
else if (error && isGenericQuotaExceededError(error)) {
|
292
|
+
if (isPaidTier) {
|
293
|
+
message = `⚡ You have reached your daily quota limit.
|
294
|
+
⚡ To continue, consider using /auth to switch to using a paid API key from AI Studio at https://aistudio.google.com/apikey
|
295
|
+
⚡ Or you can switch to a different model using the /model command`;
|
296
|
+
}
|
297
|
+
else {
|
298
|
+
message = `⚡ You have reached your daily quota limit.
|
299
|
+
⚡ 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
|
300
|
+
⚡ Or you can utilize a Gemini API Key. See: https://goo.gle/gemini-cli-docs-auth#gemini-api-key
|
301
|
+
⚡ You can switch authentication methods by typing /auth or switch to a different model using /model`;
|
302
|
+
}
|
303
|
+
}
|
304
|
+
else {
|
305
|
+
if (isPaidTier) {
|
306
|
+
// Default message for other cases (like consecutive 429s)
|
307
|
+
message = `⚡ You are experiencing capacity issues with ${currentModel}.
|
308
|
+
⚡ Possible reasons are consecutive capacity errors or reaching your daily ${currentModel} quota limit.
|
309
|
+
⚡ To continue, consider using /auth to switch to using a paid API key from AI Studio at https://aistudio.google.com/apikey
|
310
|
+
⚡ Or you can switch to a different model using the /model command`;
|
311
|
+
}
|
312
|
+
else {
|
313
|
+
// Default message for other cases (like consecutive 429s)
|
314
|
+
message = `⚡ You are experiencing capacity issues with ${currentModel}.
|
315
|
+
⚡ Possible reasons are consecutive capacity errors or reaching your daily ${currentModel} quota limit.
|
316
|
+
⚡ 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
|
317
|
+
⚡ Or you can utilize a Gemini API Key. See: https://goo.gle/gemini-cli-docs-auth#gemini-api-key
|
318
|
+
⚡ You can switch authentication methods by typing /auth or switch to a different model using /model`;
|
319
|
+
}
|
320
|
+
}
|
321
|
+
// Add message to UI history
|
322
|
+
if (message) {
|
323
|
+
addItem({
|
324
|
+
type: MessageType.INFO,
|
325
|
+
text: message,
|
326
|
+
}, Date.now());
|
327
|
+
}
|
328
|
+
// Set the flag to prevent tool continuation
|
329
|
+
setModelSwitchedFromQuotaError(true);
|
330
|
+
// Set global quota error flag to prevent Flash model calls
|
331
|
+
config.setQuotaErrorOccurred(true);
|
332
|
+
}
|
333
|
+
// Don't switch models - let the user decide
|
334
|
+
// Don't set fallback mode either
|
335
|
+
const contentGenConfigForEvent = config.getContentGeneratorConfig();
|
336
|
+
const authTypeForEvent = contentGenConfigForEvent?.authType || AuthType.USE_GEMINI;
|
337
|
+
// Still log the event for telemetry
|
338
|
+
logFlashFallback(config, new FlashFallbackEvent(authTypeForEvent));
|
339
|
+
return false; // Don't continue with current prompt
|
340
|
+
};
|
341
|
+
config.setFlashFallbackHandler(flashFallbackHandler);
|
342
|
+
}, [config, addItem, userTier]);
|
343
|
+
// Terminal and UI setup
|
344
|
+
const { rows: terminalHeight, columns: terminalWidth } = useTerminalSize();
|
222
345
|
const { stdin, setRawMode } = useStdin();
|
346
|
+
const isInitialMount = useRef(true);
|
347
|
+
const widthFraction = 0.9;
|
348
|
+
const inputWidth = Math.max(20, Math.floor(terminalWidth * widthFraction) - 3);
|
349
|
+
const suggestionsWidth = Math.max(60, Math.floor(terminalWidth * 0.8));
|
350
|
+
// Utility callbacks
|
223
351
|
const isValidPath = useCallback((filePath) => {
|
224
352
|
try {
|
225
353
|
return fs.existsSync(filePath) && fs.statSync(filePath).isFile();
|
@@ -228,17 +356,51 @@ const AppInner = ({ config, settings, startupWarnings = [], version, setIsAuthen
|
|
228
356
|
return false;
|
229
357
|
}
|
230
358
|
}, []);
|
231
|
-
const
|
232
|
-
|
233
|
-
|
359
|
+
const getPreferredEditor = useCallback(() => {
|
360
|
+
const editorType = settings.merged.preferredEditor;
|
361
|
+
const isValidEditor = isEditorAvailable(editorType);
|
362
|
+
if (!isValidEditor) {
|
363
|
+
openEditorDialog();
|
364
|
+
return;
|
365
|
+
}
|
366
|
+
return editorType;
|
367
|
+
}, [settings, openEditorDialog]);
|
368
|
+
const onAuthError = useCallback(() => {
|
369
|
+
setAuthError('reauth required');
|
370
|
+
openAuthDialog();
|
371
|
+
}, [openAuthDialog, setAuthError]);
|
372
|
+
const handleAuthTimeout = useCallback(() => {
|
373
|
+
setAuthError('Authentication timed out. Please try again.');
|
374
|
+
cancelAuthentication();
|
375
|
+
openAuthDialog();
|
376
|
+
}, [setAuthError, cancelAuthentication, openAuthDialog]);
|
377
|
+
const handlePrivacyNoticeExit = useCallback(() => {
|
378
|
+
setShowPrivacyNotice(false);
|
379
|
+
}, []);
|
380
|
+
// Core hooks and processors
|
381
|
+
const { vimEnabled: vimModeEnabled, vimMode, toggleVimEnabled, } = useVimMode();
|
382
|
+
const { handleSlashCommand, slashCommands, pendingHistoryItems: pendingSlashCommandHistoryItems, commandContext, shellConfirmationRequest, } = useSlashCommandProcessor(config, settings, addItem, clearItems, loadHistory, refreshStatic, setShowHelp, setDebugMessage, openThemeDialog, openAuthDialog, openEditorDialog, openProviderDialog, openProviderModelDialog, openLoadProfileDialog, toggleCorgiMode, setQuittingMessages, openPrivacyNotice, toggleVimEnabled, setIsProcessing);
|
383
|
+
const { streamingState, submitQuery, initError, pendingHistoryItems: pendingGeminiHistoryItems, thought, } = useGeminiStream(config.getGeminiClient(), history, addItem, setShowHelp, config, setDebugMessage, handleSlashCommand, shellModeActive, getPreferredEditor, onAuthError, performMemoryRefresh, modelSwitchedFromQuotaError, setModelSwitchedFromQuotaError);
|
384
|
+
// Input handling
|
385
|
+
const handleFinalSubmit = useCallback((submittedValue) => {
|
386
|
+
const trimmedValue = submittedValue.trim();
|
387
|
+
if (trimmedValue.length > 0) {
|
388
|
+
submitQuery(trimmedValue);
|
389
|
+
}
|
390
|
+
}, [submitQuery]);
|
234
391
|
const buffer = useTextBuffer({
|
235
392
|
initialText: '',
|
236
|
-
viewport:
|
393
|
+
viewport: { height: 10, width: inputWidth },
|
237
394
|
stdin,
|
238
395
|
setRawMode,
|
239
396
|
isValidPath,
|
240
397
|
shellModeActive,
|
241
398
|
});
|
399
|
+
const { handleInput: vimHandleInput } = useVim(buffer, handleFinalSubmit);
|
400
|
+
const pendingHistoryItems = [...pendingSlashCommandHistoryItems];
|
401
|
+
pendingHistoryItems.push(...pendingGeminiHistoryItems);
|
402
|
+
const { elapsedTime, currentLoadingPhrase } = useLoadingIndicator(streamingState);
|
403
|
+
const showAutoAcceptIndicator = useAutoAcceptIndicator({ config });
|
242
404
|
const handleExit = useCallback((pressedOnce, setPressedOnce, timerRef) => {
|
243
405
|
if (pressedOnce) {
|
244
406
|
if (timerRef.current) {
|
@@ -276,7 +438,10 @@ const AppInner = ({ config, settings, startupWarnings = [], version, setIsAuthen
|
|
276
438
|
handleSlashCommand(newValue ? '/mcp desc' : '/mcp nodesc');
|
277
439
|
}
|
278
440
|
}
|
279
|
-
else if (key.ctrl &&
|
441
|
+
else if (key.ctrl &&
|
442
|
+
input === 'e' &&
|
443
|
+
config.getIdeMode() &&
|
444
|
+
ideContextState) {
|
280
445
|
setShowIDEContextDetail((prev) => !prev);
|
281
446
|
}
|
282
447
|
else if (key.ctrl && (input === 'c' || input === 'C')) {
|
@@ -298,49 +463,6 @@ const AppInner = ({ config, settings, startupWarnings = [], version, setIsAuthen
|
|
298
463
|
setLlxprtMdFileCount(config.getLlxprtMdFileCount());
|
299
464
|
}
|
300
465
|
}, [config]);
|
301
|
-
const getPreferredEditor = useCallback(() => {
|
302
|
-
const editorType = settings.merged.preferredEditor;
|
303
|
-
const isValidEditor = isEditorAvailable(editorType);
|
304
|
-
if (!isValidEditor) {
|
305
|
-
openEditorDialog();
|
306
|
-
return;
|
307
|
-
}
|
308
|
-
return editorType;
|
309
|
-
}, [settings, openEditorDialog]);
|
310
|
-
const onAuthError = useCallback(() => {
|
311
|
-
appDispatch({ type: 'SET_AUTH_ERROR', payload: 'reauth required' });
|
312
|
-
openAuthDialog();
|
313
|
-
}, [openAuthDialog, appDispatch]);
|
314
|
-
const geminiClientForStream = useMemo(() => config.getGeminiClient(), [config]);
|
315
|
-
const { streamingState, submitQuery, initError, pendingHistoryItems: pendingGeminiHistoryItems, thought, } = useGeminiStream(geminiClientForStream, history, addItem, setShowHelp, config, setDebugMessage, handleSlashCommand, shellModeActive, getPreferredEditor, onAuthError, performMemoryRefresh, modelSwitchedFromQuotaError, useCallback((value) => {
|
316
|
-
if (typeof value === 'function') {
|
317
|
-
// Handle function form of setState
|
318
|
-
const currentValue = modelSwitchedFromQuotaError;
|
319
|
-
sessionDispatch({
|
320
|
-
type: 'SET_MODEL_SWITCHED_FROM_QUOTA_ERROR',
|
321
|
-
payload: value(currentValue),
|
322
|
-
});
|
323
|
-
}
|
324
|
-
else {
|
325
|
-
sessionDispatch({
|
326
|
-
type: 'SET_MODEL_SWITCHED_FROM_QUOTA_ERROR',
|
327
|
-
payload: value,
|
328
|
-
});
|
329
|
-
}
|
330
|
-
}, [modelSwitchedFromQuotaError, sessionDispatch]));
|
331
|
-
// FIX: Create a new array instead of mutating the existing one
|
332
|
-
// This ensures React can properly track changes and prevents infinite loops
|
333
|
-
pendingHistoryItems = [...pendingHistoryItems, ...pendingGeminiHistoryItems];
|
334
|
-
const { elapsedTime, currentLoadingPhrase } = useLoadingIndicator(streamingState);
|
335
|
-
const showAutoAcceptIndicator = useAutoAcceptIndicator({ config });
|
336
|
-
const handleFinalSubmit = useCallback((submittedValue) => {
|
337
|
-
const trimmedValue = submittedValue.trim();
|
338
|
-
if (trimmedValue.length > 0) {
|
339
|
-
// Clear transient warnings when user submits a message
|
340
|
-
sessionDispatch({ type: 'CLEAR_TRANSIENT_WARNINGS' });
|
341
|
-
submitQuery(trimmedValue);
|
342
|
-
}
|
343
|
-
}, [submitQuery, sessionDispatch]);
|
344
466
|
const logger = useLogger();
|
345
467
|
const [userMessages, setUserMessages] = useState([]);
|
346
468
|
useEffect(() => {
|
@@ -372,12 +494,23 @@ const AppInner = ({ config, settings, startupWarnings = [], version, setIsAuthen
|
|
372
494
|
};
|
373
495
|
fetchUserMessages();
|
374
496
|
}, [history, logger]);
|
375
|
-
const isInputActive = streamingState === StreamingState.Idle && !initError;
|
497
|
+
const isInputActive = streamingState === StreamingState.Idle && !initError && !isProcessing;
|
498
|
+
const handleClearScreen = useCallback(() => {
|
499
|
+
clearItems();
|
500
|
+
clearConsoleMessagesState();
|
501
|
+
console.clear();
|
502
|
+
refreshStatic();
|
503
|
+
}, [clearItems, clearConsoleMessagesState, refreshStatic]);
|
504
|
+
const mainControlsRef = useRef(null);
|
376
505
|
const pendingHistoryItemRef = useRef(null);
|
377
|
-
// Register dependencies that affect footer height with LayoutManager
|
378
506
|
useEffect(() => {
|
379
|
-
|
380
|
-
|
507
|
+
if (mainControlsRef.current) {
|
508
|
+
const fullFooterMeasurement = measureElement(mainControlsRef.current);
|
509
|
+
setFooterHeight(fullFooterMeasurement.height);
|
510
|
+
}
|
511
|
+
}, [terminalHeight, consoleMessages, showErrorDetails]);
|
512
|
+
const staticExtraHeight = /* margins and padding */ 3;
|
513
|
+
const availableTerminalHeight = useMemo(() => terminalHeight - footerHeight - staticExtraHeight, [terminalHeight, footerHeight]);
|
381
514
|
useEffect(() => {
|
382
515
|
// skip refreshing Static during first mount
|
383
516
|
if (isInitialMount.current) {
|
@@ -414,26 +547,30 @@ const AppInner = ({ config, settings, startupWarnings = [], version, setIsAuthen
|
|
414
547
|
return getAllLlxprtMdFilenames();
|
415
548
|
}, [settings.merged.contextFileName]);
|
416
549
|
const initialPrompt = useMemo(() => config.getQuestion(), [config]);
|
417
|
-
const geminiClient =
|
550
|
+
const geminiClient = config.getGeminiClient();
|
418
551
|
useEffect(() => {
|
419
552
|
if (initialPrompt &&
|
420
553
|
!initialPromptSubmitted.current &&
|
421
|
-
!
|
554
|
+
!isAuthenticating &&
|
422
555
|
!isAuthDialogOpen &&
|
423
556
|
!isThemeDialogOpen &&
|
424
557
|
!isEditorDialogOpen &&
|
558
|
+
!isProviderDialogOpen &&
|
559
|
+
!isProviderModelDialogOpen &&
|
425
560
|
!showPrivacyNotice &&
|
426
|
-
geminiClient) {
|
561
|
+
geminiClient?.isInitialized?.()) {
|
427
562
|
submitQuery(initialPrompt);
|
428
563
|
initialPromptSubmitted.current = true;
|
429
564
|
}
|
430
565
|
}, [
|
431
566
|
initialPrompt,
|
432
567
|
submitQuery,
|
433
|
-
|
568
|
+
isAuthenticating,
|
434
569
|
isAuthDialogOpen,
|
435
570
|
isThemeDialogOpen,
|
436
571
|
isEditorDialogOpen,
|
572
|
+
isProviderDialogOpen,
|
573
|
+
isProviderModelDialogOpen,
|
437
574
|
showPrivacyNotice,
|
438
575
|
geminiClient,
|
439
576
|
]);
|
@@ -445,32 +582,25 @@ const AppInner = ({ config, settings, startupWarnings = [], version, setIsAuthen
|
|
445
582
|
// Arbitrary threshold to ensure that items in the static area are large
|
446
583
|
// enough but not too large to make the terminal hard to use.
|
447
584
|
const staticAreaMaxItemHeight = Math.max(terminalHeight * 4, 100);
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
}
|
453
|
-
return (_jsx(StreamingContext.Provider, { value: streamingState, children: _jsxs(Box, { flexDirection: "column", marginBottom: 1, width: "90%", children: [updateMessage && _jsx(UpdateNotification, { message: updateMessage }), _jsx(Static, { items: [
|
585
|
+
const placeholder = vimModeEnabled
|
586
|
+
? " Press 'i' for INSERT mode and 'Esc' for NORMAL mode."
|
587
|
+
: ' Type your message or @path/to/file';
|
588
|
+
return (_jsx(StreamingContext.Provider, { value: streamingState, children: _jsxs(Box, { flexDirection: "column", width: "90%", children: [_jsx(Static, { items: [
|
454
589
|
_jsxs(Box, { flexDirection: "column", children: [!settings.merged.hideBanner && (_jsx(Header, { terminalWidth: terminalWidth, version: version, nightly: nightly })), !settings.merged.hideTips && _jsx(Tips, { config: config })] }, "header"),
|
455
590
|
...history.map((h) => (_jsx(HistoryItemDisplay, { terminalWidth: mainAreaWidth, availableTerminalHeight: staticAreaMaxItemHeight, item: h, isPending: false, config: config }, h.id))),
|
456
591
|
], 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,
|
457
592
|
// TODO(taehykim): It seems like references to ids aren't necessary in
|
458
593
|
// HistoryItemDisplay. Refactor later. Use a fake id for now.
|
459
|
-
item: { ...item, id: 0 }, isPending: true, config: config, isFocused: !isEditorDialogOpen }, i))), _jsx(ShowMoreLines, { constrainHeight: constrainHeight })] }) }), showHelp && _jsx(Help, { commands: slashCommands }), _jsxs(Box, { flexDirection: "column", ref:
|
460
|
-
? terminalHeight -
|
461
|
-
: undefined, terminalWidth: mainAreaWidth })] })) :
|
594
|
+
item: { ...item, id: 0 }, isPending: true, config: config, isFocused: !isEditorDialogOpen }, i))), _jsx(ShowMoreLines, { constrainHeight: constrainHeight })] }) }), showHelp && _jsx(Help, { commands: slashCommands }), _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))) })), shellConfirmationRequest ? (_jsx(ShellConfirmationDialog, { request: shellConfirmationRequest })) : 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
|
595
|
+
? terminalHeight - staticExtraHeight
|
596
|
+
: undefined, terminalWidth: mainAreaWidth })] })) : isAuthenticating ? (_jsxs(_Fragment, { children: [_jsx(AuthInProgress, { onTimeout: handleAuthTimeout }), 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 })] })) : isProviderDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(ProviderDialog, { providers: providerManager.listProviders(), currentProvider: providerManager.getActiveProviderName(), onSelect: handleProviderSelect, onClose: exitProviderDialog }) })) : isProviderModelDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(ProviderModelDialog, { models: providerModels, currentModel: currentModel, onSelect: handleProviderModelChange, onClose: exitProviderModelDialog }) })) : isLoadProfileDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(LoadProfileDialog, { profiles: profiles, onSelect: handleProfileSelect, onClose: exitLoadProfileDialog }) })) : showPrivacyNotice ? (_jsx(PrivacyNotice, { onExit: handlePrivacyNoticeExit, config: config })) : (_jsxs(_Fragment, { children: [_jsx(LoadingIndicator, { thought: streamingState === StreamingState.WaitingForConfirmation ||
|
462
597
|
config.getAccessibility()?.disableLoadingPhrases
|
463
598
|
? undefined
|
464
599
|
: thought, currentLoadingPhrase: config.getAccessibility()?.disableLoadingPhrases
|
465
600
|
? undefined
|
466
|
-
: currentLoadingPhrase, elapsedTime: elapsedTime }), _jsxs(Box, { marginTop: 1, display: "flex", justifyContent: "space-between", width: "100%", 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." })) : (_jsx(ContextSummaryDisplay, {
|
467
|
-
!shellModeActive && (_jsx(AutoAcceptIndicator, { approvalMode: showAutoAcceptIndicator })), shellModeActive && _jsx(ShellModeIndicator, {})] })] }), showIDEContextDetail && (_jsx(IDEContextDetailDisplay, {
|
468
|
-
|
469
|
-
|
470
|
-
const AppWithAuth = (props) => {
|
471
|
-
const [isAuthenticating, setIsAuthenticating] = useState(false);
|
472
|
-
return (_jsx(SessionController, { config: props.config, isAuthenticating: isAuthenticating, children: _jsx(AppInner, { ...props, isAuthenticating: isAuthenticating, setIsAuthenticating: setIsAuthenticating }) }));
|
601
|
+
: currentLoadingPhrase, elapsedTime: elapsedTime }), _jsxs(Box, { marginTop: 1, display: "flex", justifyContent: "space-between", width: "100%", 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." })) : (_jsx(ContextSummaryDisplay, { ideContext: ideContextState, llxprtMdFileCount: llxprtMdFileCount, contextFileNames: contextFileNames, mcpServers: config.getMcpServers(), blockedMcpServers: config.getBlockedMcpServers(), showToolDescriptions: showToolDescriptions }))] }), _jsxs(Box, { children: [showAutoAcceptIndicator !== ApprovalMode.DEFAULT &&
|
602
|
+
!shellModeActive && (_jsx(AutoAcceptIndicator, { approvalMode: showAutoAcceptIndicator })), shellModeActive && _jsx(ShellModeIndicator, {})] })] }), showIDEContextDetail && (_jsx(IDEContextDetailDisplay, { ideContext: ideContextState, detectedIdeDisplay: config
|
603
|
+
.getIdeClient()
|
604
|
+
?.getDetectedIdeDisplayName() })), 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: userMessages, onClearScreen: handleClearScreen, config: config, slashCommands: slashCommands, commandContext: commandContext, shellModeActive: shellModeActive, setShellModeActive: setShellModeActive, 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."] })] })) })), _jsx(Footer, { model: currentModel, targetDir: config.getTargetDir(), debugMode: config.getDebugMode(), branchName: branchName, debugMessage: debugMessage, errorCount: errorCount, showErrorDetails: showErrorDetails, showMemoryUsage: config.getDebugMode() || config.getShowMemoryUsage(), promptTokenCount: sessionStats.lastPromptTokenCount, nightly: nightly, vimMode: vimModeEnabled ? vimMode : undefined, contextLimit: config.getEphemeralSetting('context-limit') })] })] }) }));
|
473
605
|
};
|
474
|
-
// Main App component that provides the UIStateShell wrapper
|
475
|
-
const App = (props) => (_jsx(UIStateShell, { children: _jsx(AppWithAuth, { ...props }) }));
|
476
606
|
//# sourceMappingURL=App.js.map
|