@blackbox_ai/blackbox-cli 0.8.6 → 1.0.2
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 +20 -0
- package/dist/assets/notification.mp3 +0 -0
- package/dist/package.json +2 -2
- package/dist/src/commands/configure/ConfigureUI.d.ts +1 -1
- package/dist/src/commands/configure/ConfigureUI.js +91 -22
- package/dist/src/commands/configure/ConfigureUI.js.map +1 -1
- package/dist/src/commands/configure.js +57 -16
- package/dist/src/commands/configure.js.map +1 -1
- package/dist/src/commands/shortcut.d.ts +10 -0
- package/dist/src/commands/shortcut.js +72 -0
- package/dist/src/commands/shortcut.js.map +1 -0
- package/dist/src/commands/voice.js +39 -34
- package/dist/src/commands/voice.js.map +1 -1
- package/dist/src/config/config.js +8 -5
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/modelFetcher.d.ts +4 -0
- package/dist/src/config/modelFetcher.js +68 -22
- package/dist/src/config/modelFetcher.js.map +1 -1
- package/dist/src/config/settings.d.ts +2 -0
- package/dist/src/config/settings.js +48 -3
- package/dist/src/config/settings.js.map +1 -1
- package/dist/src/config/settingsSchema.d.ts +64 -6
- package/dist/src/config/settingsSchema.js +62 -6
- package/dist/src/config/settingsSchema.js.map +1 -1
- package/dist/src/gemini.js +31 -20
- package/dist/src/gemini.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/services/BuiltinCommandLoader.js +4 -2
- package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
- package/dist/src/services/agentExecutor.d.ts +57 -0
- package/dist/src/services/agentExecutor.js +149 -0
- package/dist/src/services/agentExecutor.js.map +1 -0
- package/dist/src/services/voiceRecordingService.d.ts +13 -1
- package/dist/src/services/voiceRecordingService.js +38 -5
- package/dist/src/services/voiceRecordingService.js.map +1 -1
- package/dist/src/ui/App.d.ts +1 -1
- package/dist/src/ui/App.js +292 -26
- package/dist/src/ui/App.js.map +1 -1
- package/dist/src/ui/colors.js +3 -0
- package/dist/src/ui/colors.js.map +1 -1
- package/dist/src/ui/commands/agentCommand.d.ts +7 -0
- package/dist/src/ui/commands/agentCommand.js +181 -0
- package/dist/src/ui/commands/agentCommand.js.map +1 -0
- package/dist/src/ui/commands/modelCommand.js +15 -2
- package/dist/src/ui/commands/modelCommand.js.map +1 -1
- package/dist/src/ui/commands/quitCommand.js +5 -0
- package/dist/src/ui/commands/quitCommand.js.map +1 -1
- package/dist/src/ui/commands/subAgentsCommand.d.ts +7 -0
- package/dist/src/ui/commands/subAgentsCommand.js +32 -0
- package/dist/src/ui/commands/subAgentsCommand.js.map +1 -0
- package/dist/src/ui/commands/types.d.ts +24 -3
- package/dist/src/ui/commands/types.js.map +1 -1
- package/dist/src/ui/commands/voiceCommand.js +70 -34
- package/dist/src/ui/commands/voiceCommand.js.map +1 -1
- package/dist/src/ui/commands/voiceCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/voiceCommand.test.js +131 -0
- package/dist/src/ui/commands/voiceCommand.test.js.map +1 -0
- package/dist/src/ui/components/AgentModelSelector.d.ts +17 -0
- package/dist/src/ui/components/AgentModelSelector.js +41 -0
- package/dist/src/ui/components/AgentModelSelector.js.map +1 -0
- package/dist/src/ui/components/AgentSetDialog.d.ts +15 -0
- package/dist/src/ui/components/AgentSetDialog.js +52 -0
- package/dist/src/ui/components/AgentSetDialog.js.map +1 -0
- package/dist/src/ui/components/ApiKeyInputDialog.d.ts +17 -0
- package/dist/src/ui/components/ApiKeyInputDialog.js +44 -0
- package/dist/src/ui/components/ApiKeyInputDialog.js.map +1 -0
- package/dist/src/ui/components/AsciiArt.d.ts +3 -3
- package/dist/src/ui/components/AsciiArt.js +18 -18
- package/dist/src/ui/components/AsciiArt.js.map +1 -1
- package/dist/src/ui/components/AuthDialog.js +50 -7
- package/dist/src/ui/components/AuthDialog.js.map +1 -1
- package/dist/src/ui/components/Footer.d.ts +8 -0
- package/dist/src/ui/components/Footer.js +17 -4
- package/dist/src/ui/components/Footer.js.map +1 -1
- package/dist/src/ui/components/GenericProviderKeyPrompt.js +1 -1
- package/dist/src/ui/components/GenericProviderKeyPrompt.js.map +1 -1
- package/dist/src/ui/components/Header.js +6 -10
- package/dist/src/ui/components/Header.js.map +1 -1
- package/dist/src/ui/components/HistoryBrowserDialog.js +2 -1
- package/dist/src/ui/components/HistoryBrowserDialog.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.js +3 -1
- package/dist/src/ui/components/InputPrompt.js.map +1 -1
- package/dist/src/ui/components/MemoryUsageDisplay.js +41 -8
- package/dist/src/ui/components/MemoryUsageDisplay.js.map +1 -1
- package/dist/src/ui/components/SettingsDialog.js +4 -3
- package/dist/src/ui/components/SettingsDialog.js.map +1 -1
- package/dist/src/ui/components/StatsDisplay.js +1 -1
- package/dist/src/ui/components/StatsDisplay.js.map +1 -1
- package/dist/src/ui/components/SuggestionsDisplay.js +3 -2
- 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/agents/SingleAgentDialog.d.ts +23 -0
- package/dist/src/ui/components/agents/SingleAgentDialog.js +222 -0
- package/dist/src/ui/components/agents/SingleAgentDialog.js.map +1 -0
- package/dist/src/ui/components/messages/DiffRenderer.js +1 -9
- package/dist/src/ui/components/messages/DiffRenderer.js.map +1 -1
- package/dist/src/ui/components/messages/ErrorMessage.js +2 -1
- package/dist/src/ui/components/messages/ErrorMessage.js.map +1 -1
- package/dist/src/ui/components/messages/InfoMessage.js +2 -1
- package/dist/src/ui/components/messages/InfoMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.js +4 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolMessage.js +4 -4
- package/dist/src/ui/components/messages/ToolMessage.js.map +1 -1
- package/dist/src/ui/components/messages/UserMessage.js +1 -2
- package/dist/src/ui/components/messages/UserMessage.js.map +1 -1
- package/dist/src/ui/components/multiagent/MultiAgentConfigDialog.js +1 -19
- package/dist/src/ui/components/multiagent/MultiAgentConfigDialog.js.map +1 -1
- package/dist/src/ui/components/shared/RadioButtonSelect.js +14 -4
- package/dist/src/ui/components/shared/RadioButtonSelect.js.map +1 -1
- package/dist/src/ui/contexts/SessionContext.d.ts +18 -0
- package/dist/src/ui/contexts/SessionContext.js +25 -1
- package/dist/src/ui/contexts/SessionContext.js.map +1 -1
- package/dist/src/ui/hooks/shellCommandProcessor.d.ts +1 -1
- package/dist/src/ui/hooks/shellCommandProcessor.js +13 -2
- package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.d.ts +2 -2
- package/dist/src/ui/hooks/slashCommandProcessor.js +65 -29
- package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/useAdaptiveStream.d.ts +2 -1
- package/dist/src/ui/hooks/useAdaptiveStream.js +2 -2
- package/dist/src/ui/hooks/useAdaptiveStream.js.map +1 -1
- package/dist/src/ui/hooks/useAgentCommandProcessor.d.ts +26 -0
- package/dist/src/ui/hooks/useAgentCommandProcessor.js +967 -0
- package/dist/src/ui/hooks/useAgentCommandProcessor.js.map +1 -0
- package/dist/src/ui/hooks/useAuthCommand.d.ts +2 -1
- package/dist/src/ui/hooks/useAuthCommand.js +22 -2
- package/dist/src/ui/hooks/useAuthCommand.js.map +1 -1
- package/dist/src/ui/hooks/useDialogClose.d.ts +2 -0
- package/dist/src/ui/hooks/useDialogClose.js +5 -0
- package/dist/src/ui/hooks/useDialogClose.js.map +1 -1
- package/dist/src/ui/hooks/useEncryptedStream.d.ts +2 -1
- package/dist/src/ui/hooks/useEncryptedStream.js +31 -3
- package/dist/src/ui/hooks/useEncryptedStream.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.d.ts +2 -1
- package/dist/src/ui/hooks/useGeminiStream.js +292 -22
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useInputBoxColor.d.ts +13 -0
- package/dist/src/ui/hooks/useInputBoxColor.js +62 -0
- package/dist/src/ui/hooks/useInputBoxColor.js.map +1 -0
- package/dist/src/ui/hooks/useMessageQueue.d.ts +7 -1
- package/dist/src/ui/hooks/useMessageQueue.js +9 -3
- package/dist/src/ui/hooks/useMessageQueue.js.map +1 -1
- package/dist/src/ui/hooks/useSingleAgentCommand.d.ts +10 -0
- package/dist/src/ui/hooks/useSingleAgentCommand.js +21 -0
- package/dist/src/ui/hooks/useSingleAgentCommand.js.map +1 -0
- package/dist/src/ui/themes/ansi-light.js +1 -0
- package/dist/src/ui/themes/ansi-light.js.map +1 -1
- package/dist/src/ui/themes/ansi.js +1 -0
- package/dist/src/ui/themes/ansi.js.map +1 -1
- package/dist/src/ui/themes/atom-one-dark.js +14 -13
- package/dist/src/ui/themes/atom-one-dark.js.map +1 -1
- package/dist/src/ui/themes/ayu-light.js +14 -13
- package/dist/src/ui/themes/ayu-light.js.map +1 -1
- package/dist/src/ui/themes/ayu.js +14 -13
- package/dist/src/ui/themes/ayu.js.map +1 -1
- package/dist/src/ui/themes/blackbox-dark.js +36 -31
- package/dist/src/ui/themes/blackbox-dark.js.map +1 -1
- package/dist/src/ui/themes/blackbox-light.js +41 -39
- package/dist/src/ui/themes/blackbox-light.js.map +1 -1
- package/dist/src/ui/themes/default-light.js +20 -20
- package/dist/src/ui/themes/default-light.js.map +1 -1
- package/dist/src/ui/themes/default.js +27 -27
- package/dist/src/ui/themes/default.js.map +1 -1
- package/dist/src/ui/themes/dracula.js +14 -13
- package/dist/src/ui/themes/dracula.js.map +1 -1
- package/dist/src/ui/themes/github-dark.js +14 -13
- package/dist/src/ui/themes/github-dark.js.map +1 -1
- package/dist/src/ui/themes/github-light.js +14 -13
- package/dist/src/ui/themes/github-light.js.map +1 -1
- package/dist/src/ui/themes/googlecode.js +1 -0
- package/dist/src/ui/themes/googlecode.js.map +1 -1
- package/dist/src/ui/themes/no-color.js +2 -0
- package/dist/src/ui/themes/no-color.js.map +1 -1
- package/dist/src/ui/themes/semantic-tokens.d.ts +1 -0
- package/dist/src/ui/themes/semantic-tokens.js +3 -0
- package/dist/src/ui/themes/semantic-tokens.js.map +1 -1
- package/dist/src/ui/themes/shades-of-purple.js +1 -0
- package/dist/src/ui/themes/shades-of-purple.js.map +1 -1
- package/dist/src/ui/themes/theme.d.ts +2 -0
- package/dist/src/ui/themes/theme.js +35 -28
- package/dist/src/ui/themes/theme.js.map +1 -1
- package/dist/src/ui/themes/xcode.js +1 -0
- package/dist/src/ui/themes/xcode.js.map +1 -1
- package/dist/src/ui/types.d.ts +5 -0
- package/dist/src/ui/utils/agentConversationUtils.d.ts +28 -0
- package/dist/src/ui/utils/agentConversationUtils.js +71 -0
- package/dist/src/ui/utils/agentConversationUtils.js.map +1 -0
- package/dist/src/ui/utils/colorBlend.d.ts +33 -0
- package/dist/src/ui/utils/colorBlend.js +61 -0
- package/dist/src/ui/utils/colorBlend.js.map +1 -0
- package/dist/src/ui/utils/commandUtils.d.ts +2 -1
- package/dist/src/ui/utils/commandUtils.js +14 -1
- package/dist/src/ui/utils/commandUtils.js.map +1 -1
- package/dist/src/ui/utils/commandUtils.test.js +25 -0
- package/dist/src/ui/utils/commandUtils.test.js.map +1 -1
- package/dist/src/ui/utils/terminalBackgroundDetector.d.ts +35 -0
- package/dist/src/ui/utils/terminalBackgroundDetector.js +200 -0
- package/dist/src/ui/utils/terminalBackgroundDetector.js.map +1 -0
- package/dist/src/utils/agentCommandBuilder.d.ts +48 -0
- package/dist/src/utils/agentCommandBuilder.js +328 -0
- package/dist/src/utils/agentCommandBuilder.js.map +1 -0
- package/dist/src/utils/apiKeyUtils.d.ts +47 -0
- package/dist/src/utils/apiKeyUtils.js +177 -0
- package/dist/src/utils/apiKeyUtils.js.map +1 -0
- package/dist/src/utils/backgroundUpdateCheck.js +104 -7
- package/dist/src/utils/backgroundUpdateCheck.js.map +1 -1
- package/dist/src/utils/memoryManager.d.ts +85 -0
- package/dist/src/utils/memoryManager.js +258 -0
- package/dist/src/utils/memoryManager.js.map +1 -0
- package/dist/src/utils/memoryMonitor.d.ts +89 -0
- package/dist/src/utils/memoryMonitor.js +238 -0
- package/dist/src/utils/memoryMonitor.js.map +1 -0
- package/dist/src/utils/memoryWrapper.d.ts +18 -0
- package/dist/src/utils/memoryWrapper.js +62 -0
- package/dist/src/utils/memoryWrapper.js.map +1 -0
- package/dist/src/utils/preLaunchUpdateCheck.js +17 -7
- package/dist/src/utils/preLaunchUpdateCheck.js.map +1 -1
- package/dist/src/utils/shellShortcut.d.ts +45 -0
- package/dist/src/utils/shellShortcut.js +221 -0
- package/dist/src/utils/shellShortcut.js.map +1 -0
- package/dist/src/utils/soundNotification.d.ts +15 -0
- package/dist/src/utils/soundNotification.js +138 -0
- package/dist/src/utils/soundNotification.js.map +1 -0
- package/dist/src/utils/userStartupWarnings.js +0 -20
- package/dist/src/utils/userStartupWarnings.js.map +1 -1
- package/dist/src/utils/versionStorage.d.ts +20 -0
- package/dist/src/utils/versionStorage.js +62 -0
- package/dist/src/utils/versionStorage.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
package/dist/src/ui/App.js
CHANGED
|
@@ -24,6 +24,7 @@ import { useDialogCloseAnimation } from './hooks/useDialogCloseAnimation.js';
|
|
|
24
24
|
import { useSlashCommandProcessor } from './hooks/slashCommandProcessor.js';
|
|
25
25
|
import { useSubagentCreateDialog } from './hooks/useSubagentCreateDialog.js';
|
|
26
26
|
import { useAgentsManagerDialog } from './hooks/useAgentsManagerDialog.js';
|
|
27
|
+
import { useSingleAgentCommand } from './hooks/useSingleAgentCommand.js';
|
|
27
28
|
import { useMultiAgentConfigCommand } from './hooks/useMultiAgentConfigCommand.js';
|
|
28
29
|
import { useAutoAcceptIndicator } from './hooks/useAutoAcceptIndicator.js';
|
|
29
30
|
import { useMessageQueue } from './hooks/useMessageQueue.js';
|
|
@@ -42,7 +43,6 @@ import { BlackboxOAuthProgress } from './components/BlackboxOAuthProgress.js';
|
|
|
42
43
|
import { EditorSettingsDialog } from './components/EditorSettingsDialog.js';
|
|
43
44
|
import { FolderTrustDialog } from './components/FolderTrustDialog.js';
|
|
44
45
|
import { ShellConfirmationDialog } from './components/ShellConfirmationDialog.js';
|
|
45
|
-
import { QuitConfirmationDialog } from './components/QuitConfirmationDialog.js';
|
|
46
46
|
import { RadioButtonSelect } from './components/shared/RadioButtonSelect.js';
|
|
47
47
|
import { ModelSelectionDialog } from './components/ModelSelectionDialog.js';
|
|
48
48
|
import { ModelSwitchDialog, } from './components/ModelSwitchDialog.js';
|
|
@@ -50,19 +50,20 @@ import { getOpenAIAvailableModelFromEnv, getFilteredBlackboxModels, } from './mo
|
|
|
50
50
|
import { HistoryBrowserDialog } from './components/HistoryBrowserDialog.js';
|
|
51
51
|
import { processVisionSwitchOutcome } from './hooks/useVisionAutoSwitch.js';
|
|
52
52
|
import { AgentCreationWizard, AgentsManagerDialog, } from './components/subagents/index.js';
|
|
53
|
+
import { SingleAgentDialog } from './components/agents/SingleAgentDialog.js';
|
|
53
54
|
import { MultiAgentConfigDialog } from './components/multiagent/MultiAgentConfigDialog.js';
|
|
54
55
|
import { Colors } from './colors.js';
|
|
56
|
+
import { convertHistoryToConversationString } from './utils/agentConversationUtils.js';
|
|
55
57
|
import { loadHierarchicalGeminiMemory } from '../config/config.js';
|
|
56
|
-
import { SettingScope } from '../config/settings.js';
|
|
58
|
+
import { SettingScope, settingsChangeEmitter } from '../config/settings.js';
|
|
57
59
|
import { Tips } from './components/Tips.js';
|
|
58
60
|
import { ConsolePatcher } from './utils/ConsolePatcher.js';
|
|
59
61
|
import { registerCleanup } from '../utils/cleanup.js';
|
|
60
62
|
import { DetailedMessagesDisplay } from './components/DetailedMessagesDisplay.js';
|
|
61
63
|
import { HistoryItemDisplay } from './components/HistoryItemDisplay.js';
|
|
62
|
-
import { ContextSummaryDisplay } from './components/ContextSummaryDisplay.js';
|
|
63
64
|
import { useHistory } from './hooks/useHistoryManager.js';
|
|
64
65
|
import process from 'node:process';
|
|
65
|
-
import { ApprovalMode,
|
|
66
|
+
import { ApprovalMode, isEditorAvailable, getErrorMessage, AuthType, logFlashFallback, FlashFallbackEvent, ideContext, isProQuotaExceededError, isGenericQuotaExceededError, UserTierId, } from '@blackbox_ai/blackbox-cli-core';
|
|
66
67
|
import { validateAuthMethod } from '../config/auth.js';
|
|
67
68
|
import { useLogger } from './hooks/useLogger.js';
|
|
68
69
|
import { StreamingContext } from './contexts/StreamingContext.js';
|
|
@@ -95,6 +96,8 @@ import { WelcomeBackDialog } from './components/WelcomeBackDialog.js';
|
|
|
95
96
|
import { TodoListDialog } from './components/TodoListDialog.js';
|
|
96
97
|
import { ConfigureUI } from '../commands/configure/ConfigureUI.js';
|
|
97
98
|
import { VoiceConfigDialog } from './components/VoiceConfigDialog.js';
|
|
99
|
+
import { QuitConfirmationDialog } from './components/QuitConfirmationDialog.js';
|
|
100
|
+
import { AgentSetDialog } from './components/AgentSetDialog.js';
|
|
98
101
|
// Maximum number of queued messages to display in UI to prevent performance issues
|
|
99
102
|
const MAX_DISPLAYED_QUEUED_MESSAGES = 3;
|
|
100
103
|
function isToolExecuting(pendingHistoryItems) {
|
|
@@ -130,6 +133,7 @@ const ShellConfirmationDialogWithAnimation = ({ request }) => {
|
|
|
130
133
|
return (_jsx(ShellConfirmationDialog, { request: wrappedRequest, isClosing: shellDialogAnimation.isClosing }));
|
|
131
134
|
};
|
|
132
135
|
const App = ({ config, settings, startupWarnings = [], version, initialSlashCommand, }) => {
|
|
136
|
+
const [_geminiMdFileCount, setGeminiMdFileCount] = useState(0);
|
|
133
137
|
const isFocused = useFocus();
|
|
134
138
|
useBracketedPaste();
|
|
135
139
|
const [updateInfo, _setUpdateInfo] = useState(null);
|
|
@@ -149,7 +153,7 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
149
153
|
consolePatcher.patch();
|
|
150
154
|
registerCleanup(consolePatcher.cleanup);
|
|
151
155
|
}, [handleNewMessage, config]);
|
|
152
|
-
const { stats: sessionStats, initializeProgressiveAutoSave, setProgressiveAutoSaveEnabled } = useSessionStats();
|
|
156
|
+
const { stats: sessionStats, initializeProgressiveAutoSave, setProgressiveAutoSaveEnabled, setAgentRoutingDisabled, setActiveAgentSession } = useSessionStats();
|
|
153
157
|
// Initialize progressive auto-save service
|
|
154
158
|
useEffect(() => {
|
|
155
159
|
const progressiveAutoSaveEnabled = settings.merged.general?.progressiveAutoSave?.enabled ?? true;
|
|
@@ -160,13 +164,29 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
160
164
|
const enabled = settings.merged.general?.progressiveAutoSave?.enabled ?? true;
|
|
161
165
|
setProgressiveAutoSaveEnabled(enabled);
|
|
162
166
|
}, [settings.merged.general?.progressiveAutoSave?.enabled, setProgressiveAutoSaveEnabled]);
|
|
167
|
+
// Initialize agent routing disabled state from settings on startup
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
const routingDisabled = settings.merged.singleAgent?.routingDisabled ?? false;
|
|
170
|
+
setAgentRoutingDisabled(routingDisabled);
|
|
171
|
+
}, [settings.merged.singleAgent?.routingDisabled, setAgentRoutingDisabled, settings.merged.singleAgent]);
|
|
172
|
+
// Watch for changes in singleAgent settings and update local state for Footer
|
|
173
|
+
useEffect(() => {
|
|
174
|
+
const selectedAgent = settings.merged.singleAgent?.selectedAgent;
|
|
175
|
+
setSelectedAgentForFooter(selectedAgent);
|
|
176
|
+
// Get model from per-agent configuration
|
|
177
|
+
const agentModel = selectedAgent
|
|
178
|
+
? settings.merged.singleAgent?.agents?.[selectedAgent]?.model
|
|
179
|
+
: undefined;
|
|
180
|
+
setAgentModelForFooter(agentModel);
|
|
181
|
+
}, [settings.merged.singleAgent?.selectedAgent, settings.merged.singleAgent?.agents]);
|
|
163
182
|
const [staticNeedsRefresh, setStaticNeedsRefresh] = useState(false);
|
|
164
183
|
const [staticKey, setStaticKey] = useState(0);
|
|
165
184
|
const refreshStatic = useCallback(() => {
|
|
166
|
-
|
|
185
|
+
// Use cursor repositioning + erase instead of full terminal clear to reduce flickering
|
|
186
|
+
// This moves cursor to top-left and clears from there, which is less jarring than clearTerminal
|
|
187
|
+
stdout.write(ansiEscapes.cursorTo(0, 0) + ansiEscapes.eraseDown);
|
|
167
188
|
setStaticKey((prev) => prev + 1);
|
|
168
189
|
}, [setStaticKey, stdout]);
|
|
169
|
-
const [geminiMdFileCount, setGeminiMdFileCount] = useState(0);
|
|
170
190
|
const [debugMessage, setDebugMessage] = useState('');
|
|
171
191
|
const [themeError, setThemeError] = useState(null);
|
|
172
192
|
const [authError, setAuthError] = useState(null);
|
|
@@ -192,6 +212,80 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
192
212
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
193
213
|
const [showTodoListDialog, setShowTodoListDialog] = useState(false);
|
|
194
214
|
const [isVoiceConfigDialogOpen, setIsVoiceConfigDialogOpen] = useState(false);
|
|
215
|
+
const [showHelpTip, setShowHelpTip] = useState(true);
|
|
216
|
+
// Hide help tip if history is loaded (e.g., from previous session)
|
|
217
|
+
useEffect(() => {
|
|
218
|
+
if (history.length > 0) {
|
|
219
|
+
setShowHelpTip(false);
|
|
220
|
+
}
|
|
221
|
+
}, [history.length]);
|
|
222
|
+
const [isAgentSetDialogOpen, setIsAgentSetDialogOpen] = useState(false);
|
|
223
|
+
const [voiceRecordingActive, setVoiceRecordingActive] = useState(false);
|
|
224
|
+
// State for agent configuration to ensure Footer updates when /agent model changes
|
|
225
|
+
const [selectedAgentForFooter, setSelectedAgentForFooter] = useState(settings.merged.singleAgent?.selectedAgent);
|
|
226
|
+
const [agentModelForFooter, setAgentModelForFooter] = useState(() => {
|
|
227
|
+
const selectedAgent = settings.merged.singleAgent?.selectedAgent;
|
|
228
|
+
return selectedAgent
|
|
229
|
+
? settings.merged.singleAgent?.agents?.[selectedAgent]?.model
|
|
230
|
+
: undefined;
|
|
231
|
+
});
|
|
232
|
+
// Listen for settings changes via event emitter to ensure UI reactivity
|
|
233
|
+
useEffect(() => {
|
|
234
|
+
const handleSettingsChange = (changeData) => {
|
|
235
|
+
// If singleAgent settings changed, update local state immediately
|
|
236
|
+
if (changeData.key === 'singleAgent') {
|
|
237
|
+
const singleAgentConfig = changeData.merged.singleAgent;
|
|
238
|
+
// Check if we should preserve the active session
|
|
239
|
+
// Only clear the session if the agent type changed, not just the model
|
|
240
|
+
const currentSession = sessionStats.activeAgentSession;
|
|
241
|
+
const newSelectedAgent = singleAgentConfig?.selectedAgent;
|
|
242
|
+
// Sync conversation history from UI history when switching agents
|
|
243
|
+
// This ensures CLI agents (claude, codex, gemini) have access to the full conversation
|
|
244
|
+
// that was built up while using blackbox (which uses Gemini client internal history)
|
|
245
|
+
const syncedConversationHistory = convertHistoryToConversationString(history);
|
|
246
|
+
// Get the model for the new agent
|
|
247
|
+
const newModel = newSelectedAgent
|
|
248
|
+
? singleAgentConfig?.agents?.[newSelectedAgent]?.model
|
|
249
|
+
: currentSession?.model;
|
|
250
|
+
// Always preserve conversation history when switching agents
|
|
251
|
+
// History should only be cleared via /agent exit command
|
|
252
|
+
if (currentSession) {
|
|
253
|
+
// Update the existing session with new agent type, model, and synced conversation history
|
|
254
|
+
setActiveAgentSession({
|
|
255
|
+
...currentSession,
|
|
256
|
+
agentType: newSelectedAgent,
|
|
257
|
+
model: newModel || currentSession.model,
|
|
258
|
+
conversationHistory: syncedConversationHistory,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
else if (history.length > 0 && newSelectedAgent) {
|
|
262
|
+
// No current session but there's UI history - create a new session with synced history
|
|
263
|
+
// This handles the case where user was using blackbox (direct Gemini client) and switches to another agent
|
|
264
|
+
setActiveAgentSession({
|
|
265
|
+
agentType: newSelectedAgent,
|
|
266
|
+
model: newModel || 'default',
|
|
267
|
+
task: '', // No specific task, just continuing conversation
|
|
268
|
+
conversationHistory: syncedConversationHistory,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
// If no current session and no history, don't set one - let the user start a new conversation
|
|
272
|
+
const selectedAgent = singleAgentConfig?.selectedAgent;
|
|
273
|
+
setSelectedAgentForFooter(selectedAgent);
|
|
274
|
+
// Get model from per-agent configuration
|
|
275
|
+
const agentModel = selectedAgent
|
|
276
|
+
? singleAgentConfig?.agents?.[selectedAgent]?.model
|
|
277
|
+
: undefined;
|
|
278
|
+
setAgentModelForFooter(agentModel);
|
|
279
|
+
// Also update agent routing disabled state
|
|
280
|
+
const routingDisabled = singleAgentConfig?.routingDisabled ?? false;
|
|
281
|
+
setAgentRoutingDisabled(routingDisabled);
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
settingsChangeEmitter.on('settingsChanged', handleSettingsChange);
|
|
285
|
+
return () => {
|
|
286
|
+
settingsChangeEmitter.off('settingsChanged', handleSettingsChange);
|
|
287
|
+
};
|
|
288
|
+
}, [setAgentRoutingDisabled, setActiveAgentSession, sessionStats.activeAgentSession, history]);
|
|
195
289
|
// Releases dialog hook
|
|
196
290
|
const { isReleasesDialogOpen, openReleasesDialog, closeReleasesDialog, releasesVersions, isReleasesLoading, } = useReleasesDialog();
|
|
197
291
|
const { showWorkspaceMigrationDialog, workspaceExtensions, onWorkspaceMigrationDialogOpen, onWorkspaceMigrationDialogClose, } = useWorkspaceMigration(settings);
|
|
@@ -350,8 +444,63 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
350
444
|
const closeVoiceConfigDialog = useCallback(() => {
|
|
351
445
|
voiceConfigDialogAnimation.startClosing();
|
|
352
446
|
}, [voiceConfigDialogAnimation]);
|
|
447
|
+
// Agent set dialog handlers
|
|
448
|
+
const openAgentSetDialog = useCallback(() => {
|
|
449
|
+
setIsAgentSetDialogOpen(true);
|
|
450
|
+
}, []);
|
|
451
|
+
const closeAgentSetDialogOriginal = useCallback(() => {
|
|
452
|
+
setIsAgentSetDialogOpen(false);
|
|
453
|
+
}, []);
|
|
454
|
+
// Animation hook for agent set dialog
|
|
455
|
+
const agentSetDialogAnimation = useDialogCloseAnimation(() => {
|
|
456
|
+
closeAgentSetDialogOriginal();
|
|
457
|
+
});
|
|
458
|
+
const closeAgentSetDialog = useCallback(() => {
|
|
459
|
+
agentSetDialogAnimation.startClosing();
|
|
460
|
+
}, [agentSetDialogAnimation]);
|
|
461
|
+
const handleAgentSelected = useCallback((agentType, model) => {
|
|
462
|
+
// Get the stored model for this agent, or use default
|
|
463
|
+
const currentAgentConfigs = settings.merged?.singleAgent?.agents || {};
|
|
464
|
+
const storedModel = currentAgentConfigs[agentType]?.model;
|
|
465
|
+
const finalModel = storedModel || model;
|
|
466
|
+
// Update UI state immediately for instant visual feedback
|
|
467
|
+
setSelectedAgentForFooter(agentType);
|
|
468
|
+
setAgentModelForFooter(finalModel);
|
|
469
|
+
// Defer ALL operations to avoid blocking the dialog close
|
|
470
|
+
setTimeout(() => {
|
|
471
|
+
// Show success message
|
|
472
|
+
addItem({
|
|
473
|
+
type: MessageType.INFO,
|
|
474
|
+
text: `✓ Switched to ${agentType.charAt(0).toUpperCase() + agentType.slice(1)} agent with model: ${finalModel}`,
|
|
475
|
+
}, Date.now());
|
|
476
|
+
// Build the complete singleAgent config object and save it
|
|
477
|
+
const updatedAgentConfigs = {
|
|
478
|
+
...currentAgentConfigs,
|
|
479
|
+
[agentType]: { model: finalModel },
|
|
480
|
+
};
|
|
481
|
+
const singleAgentConfig = {
|
|
482
|
+
...settings.merged?.singleAgent,
|
|
483
|
+
selectedAgent: agentType,
|
|
484
|
+
model: finalModel,
|
|
485
|
+
routingDisabled: false,
|
|
486
|
+
agents: updatedAgentConfigs,
|
|
487
|
+
};
|
|
488
|
+
// Save settings in the background - this will trigger the settings change event
|
|
489
|
+
// which will update other parts of the UI that depend on settings
|
|
490
|
+
settings.setValue(SettingScope.User, 'singleAgent', singleAgentConfig);
|
|
491
|
+
}, 0);
|
|
492
|
+
}, [addItem, settings, setSelectedAgentForFooter, setAgentModelForFooter]);
|
|
353
493
|
const { isSubagentCreateDialogOpen, openSubagentCreateDialog, closeSubagentCreateDialog, } = useSubagentCreateDialog();
|
|
354
494
|
const { isAgentsManagerDialogOpen, openAgentsManagerDialog, closeAgentsManagerDialog, } = useAgentsManagerDialog();
|
|
495
|
+
const { isSingleAgentDialogOpen, openSingleAgentDialog, closeSingleAgentDialog, } = useSingleAgentCommand();
|
|
496
|
+
// State for single agent model-only dialog
|
|
497
|
+
const [isSingleAgentModelDialogOpen, setIsSingleAgentModelDialogOpen] = useState(false);
|
|
498
|
+
const openSingleAgentModelDialog = useCallback(() => {
|
|
499
|
+
setIsSingleAgentModelDialogOpen(true);
|
|
500
|
+
}, []);
|
|
501
|
+
const closeSingleAgentModelDialog = useCallback(() => {
|
|
502
|
+
setIsSingleAgentModelDialogOpen(false);
|
|
503
|
+
}, []);
|
|
355
504
|
const { isMultiAgentConfigDialogOpen, openMultiAgentConfigDialog, closeMultiAgentConfigDialog, } = useMultiAgentConfigCommand();
|
|
356
505
|
const { isFolderTrustDialogOpen, handleFolderTrustSelect, isRestarting } = useFolderTrust(settings, setIsTrustedFolder);
|
|
357
506
|
const { showQuitConfirmation, handleQuitConfirmationSelect } = useQuitConfirmation();
|
|
@@ -365,7 +514,7 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
365
514
|
if (reloadCommandsRef.current) {
|
|
366
515
|
reloadCommandsRef.current();
|
|
367
516
|
}
|
|
368
|
-
});
|
|
517
|
+
}, setActiveAgentSession);
|
|
369
518
|
// Animation hook for auth dialog
|
|
370
519
|
const authDialogAnimation = useDialogCloseAnimation(() => {
|
|
371
520
|
// Close handler - for ESC case
|
|
@@ -542,6 +691,29 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
542
691
|
const isNarrow = isNarrowWidth(terminalWidth);
|
|
543
692
|
const { stdin, setRawMode } = useStdin();
|
|
544
693
|
const isInitialMount = useRef(true);
|
|
694
|
+
// Clear stdin on mount to prevent background detection leaks
|
|
695
|
+
useEffect(() => {
|
|
696
|
+
if (!process.stdin.isTTY) {
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
// Drain any buffered data from stdin that might have leaked from background detection
|
|
700
|
+
const drainStdin = () => {
|
|
701
|
+
try {
|
|
702
|
+
// Read and discard any buffered data
|
|
703
|
+
while (process.stdin.read() !== null) {
|
|
704
|
+
// Keep reading until buffer is empty
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
catch (_err) {
|
|
708
|
+
// Ignore errors
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
// Drain immediately on mount
|
|
712
|
+
drainStdin();
|
|
713
|
+
// Also drain after a short delay to catch any late-arriving data
|
|
714
|
+
const timeoutId = setTimeout(drainStdin, 50);
|
|
715
|
+
return () => clearTimeout(timeoutId);
|
|
716
|
+
}, []);
|
|
545
717
|
const widthFraction = 0.9;
|
|
546
718
|
const inputWidth = Math.max(20, Math.floor(terminalWidth * widthFraction) - 3);
|
|
547
719
|
const suggestionsWidth = Math.max(20, Math.floor(terminalWidth * 0.8));
|
|
@@ -559,7 +731,7 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
559
731
|
const isValidEditor = isEditorAvailable(editorType);
|
|
560
732
|
if (!isValidEditor) {
|
|
561
733
|
openEditorDialog();
|
|
562
|
-
return;
|
|
734
|
+
return undefined;
|
|
563
735
|
}
|
|
564
736
|
return editorType;
|
|
565
737
|
}, [settings, openEditorDialog]);
|
|
@@ -674,7 +846,7 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
674
846
|
}, [isModelSelectionDialogOpen, getAvailableModelsForCurrentAuth]);
|
|
675
847
|
// Core hooks and processors
|
|
676
848
|
const { vimEnabled: vimModeEnabled, vimMode, toggleVimEnabled, } = useVimMode();
|
|
677
|
-
const { handleSlashCommand, slashCommands, pendingHistoryItems: pendingSlashCommandHistoryItems, commandContext, shellConfirmationRequest, confirmationRequest, quitConfirmationRequest, } = useSlashCommandProcessor(config, settings, addItem, clearItems, loadHistory, refreshStatic, setDebugMessage, openThemeDialog, openAuthDialog, openEditorDialog, toggleCorgiMode, setQuittingMessages, openPrivacyNotice, openSettingsDialog, openExtensionsDialog, handleModelSelectionOpen, openSubagentCreateDialog, openAgentsManagerDialog, openMultiAgentConfigDialog, openHistoryBrowser, openDbConfigureDialog, toggleVimEnabled, setIsProcessing, setGeminiMdFileCount, showQuitConfirmation, openVoiceConfigDialog, openReleasesDialog);
|
|
849
|
+
const { handleSlashCommand, slashCommands, pendingHistoryItems: pendingSlashCommandHistoryItems, commandContext, shellConfirmationRequest, confirmationRequest, quitConfirmationRequest, } = useSlashCommandProcessor(config, settings, addItem, clearItems, loadHistory, refreshStatic, setDebugMessage, openThemeDialog, openAuthDialog, openEditorDialog, toggleCorgiMode, setQuittingMessages, openPrivacyNotice, openSettingsDialog, openExtensionsDialog, handleModelSelectionOpen, openSubagentCreateDialog, openAgentsManagerDialog, openSingleAgentDialog, openSingleAgentModelDialog, openMultiAgentConfigDialog, openHistoryBrowser, openDbConfigureDialog, toggleVimEnabled, setIsProcessing, setGeminiMdFileCount, showQuitConfirmation, openVoiceConfigDialog, openReleasesDialog, openAgentSetDialog, setVoiceRecordingActive);
|
|
678
850
|
// Set the reloadCommands ref when commandContext is available
|
|
679
851
|
useEffect(() => {
|
|
680
852
|
if (commandContext?.ui?.reloadCommands) {
|
|
@@ -692,7 +864,7 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
692
864
|
const [userMessages, setUserMessages] = useState([]);
|
|
693
865
|
// Stable reference for cancel handler to avoid circular dependency
|
|
694
866
|
const cancelHandlerRef = useRef(() => { });
|
|
695
|
-
const { streamingState, submitQuery, initError, pendingHistoryItems: pendingGeminiHistoryItems, thought, cancelOngoingRequest, isEncryptedMode: _isEncryptedMode, } = useAdaptiveStream(config, history, addItem, setDebugMessage, () => cancelHandlerRef.current(), {
|
|
867
|
+
const { streamingState, submitQuery, initError, pendingHistoryItems: pendingGeminiHistoryItems, thought, cancelOngoingRequest, isEncryptedMode: _isEncryptedMode, } = useAdaptiveStream(config, history, addItem, setDebugMessage, () => cancelHandlerRef.current(), settings, {
|
|
696
868
|
handleSlashCommand,
|
|
697
869
|
shellModeActive,
|
|
698
870
|
getPreferredEditor,
|
|
@@ -740,6 +912,8 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
740
912
|
closeExtensionsDialog,
|
|
741
913
|
isVoiceConfigDialogOpen,
|
|
742
914
|
closeVoiceConfigDialog,
|
|
915
|
+
isAgentSetDialogOpen,
|
|
916
|
+
closeAgentSetDialog,
|
|
743
917
|
isReleasesDialogOpen,
|
|
744
918
|
closeReleasesDialog,
|
|
745
919
|
isFolderTrustDialogOpen,
|
|
@@ -784,8 +958,12 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
784
958
|
]);
|
|
785
959
|
// Input handling - queue messages for processing
|
|
786
960
|
const handleFinalSubmit = useCallback((submittedValue) => {
|
|
961
|
+
// Hide help tip on first command submission
|
|
962
|
+
if (showHelpTip) {
|
|
963
|
+
setShowHelpTip(false);
|
|
964
|
+
}
|
|
787
965
|
addMessage(submittedValue);
|
|
788
|
-
}, [addMessage]);
|
|
966
|
+
}, [addMessage, showHelpTip]);
|
|
789
967
|
const { handleInput: vimHandleInput } = useVim(buffer, handleFinalSubmit);
|
|
790
968
|
const { todos, currentTodo, nextTodo } = useTodoList(config.getSessionId());
|
|
791
969
|
const { elapsedTime, currentLoadingPhrase } = useLoadingIndicator(streamingState, currentTodo?.content || null);
|
|
@@ -865,6 +1043,10 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
865
1043
|
if (isAuthenticating) {
|
|
866
1044
|
return;
|
|
867
1045
|
}
|
|
1046
|
+
// When voice recording is active, let the voice command handle Ctrl+C.
|
|
1047
|
+
if (voiceRecordingActive) {
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
868
1050
|
handleExit(ctrlCPressedOnce, setCtrlCPressedOnce, ctrlCTimerRef);
|
|
869
1051
|
}
|
|
870
1052
|
else if (keyMatchers[Command.EXIT](key)) {
|
|
@@ -895,6 +1077,7 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
895
1077
|
ctrlDTimerRef,
|
|
896
1078
|
handleSlashCommand,
|
|
897
1079
|
isAuthenticating,
|
|
1080
|
+
voiceRecordingActive,
|
|
898
1081
|
settings.merged.general?.debugKeystrokeLogging,
|
|
899
1082
|
]);
|
|
900
1083
|
useKeypress(handleGlobalKeypress, {
|
|
@@ -943,7 +1126,7 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
943
1126
|
const handleClearScreen = useCallback(() => {
|
|
944
1127
|
clearItems();
|
|
945
1128
|
clearConsoleMessagesState();
|
|
946
|
-
console.clear()
|
|
1129
|
+
// Removed redundant console.clear() - refreshStatic() already handles screen clearing
|
|
947
1130
|
refreshStatic();
|
|
948
1131
|
}, [clearItems, clearConsoleMessagesState, refreshStatic]);
|
|
949
1132
|
const mainControlsRef = useRef(null);
|
|
@@ -984,13 +1167,6 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
984
1167
|
return consoleMessages.filter((msg) => msg.type !== 'debug');
|
|
985
1168
|
}, [consoleMessages, config]);
|
|
986
1169
|
const branchName = useGitBranchName(config.getTargetDir());
|
|
987
|
-
const contextFileNames = useMemo(() => {
|
|
988
|
-
const fromSettings = settings.merged.context?.fileName;
|
|
989
|
-
if (fromSettings) {
|
|
990
|
-
return Array.isArray(fromSettings) ? fromSettings : [fromSettings];
|
|
991
|
-
}
|
|
992
|
-
return getAllGeminiMdFilenames();
|
|
993
|
-
}, [settings.merged.context?.fileName]);
|
|
994
1170
|
const initialPrompt = useMemo(() => config.getQuestion(), [config]);
|
|
995
1171
|
const geminiClient = config.getGeminiClient();
|
|
996
1172
|
useEffect(() => {
|
|
@@ -1067,7 +1243,7 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
1067
1243
|
const placeholder = vimModeEnabled
|
|
1068
1244
|
? " Press 'i' for INSERT mode and 'Esc' for NORMAL mode."
|
|
1069
1245
|
: ' Type your message or @path/to/file';
|
|
1070
|
-
return (_jsx(StreamingContext.Provider, { value: streamingState, children: _jsxs(Box, { flexDirection: "column", width: "
|
|
1246
|
+
return (_jsx(StreamingContext.Provider, { value: streamingState, children: _jsxs(Box, { flexDirection: "column", width: "99%", children: [_jsx(Static, { items: [
|
|
1071
1247
|
_jsxs(Box, { flexDirection: "column", children: [!(settings.merged.ui?.hideBanner || config.getScreenReader()) && _jsx(Header, { version: version, nightly: nightly }), !(settings.merged.ui?.hideTips || config.getScreenReader()) && (_jsx(Tips, { config: config }))] }, "header"),
|
|
1072
1248
|
...history.map((h) => (_jsx(HistoryItemDisplay, { terminalWidth: mainAreaWidth, availableTerminalHeight: staticAreaMaxItemHeight, item: h, isPending: false, config: config, commands: slashCommands }, h.id))),
|
|
1073
1249
|
], children: (item) => item }, staticKey), _jsx(OverflowProvider, { children: _jsxs(Box, { ref: pendingHistoryItemRef, flexDirection: "column", children: [pendingHistoryItems.map((item) => (_jsx(HistoryItemDisplay, { availableTerminalHeight: constrainHeight ? availableTerminalHeight : undefined, terminalWidth: mainAreaWidth, item: item, isPending: true, config: config, isFocused: !isEditorDialogOpen }, item.id))), _jsx(ShowMoreLines, { constrainHeight: constrainHeight })] }) }), _jsxs(Box, { flexDirection: "column", ref: mainControlsRef, children: [updateInfo && _jsx(UpdateNotification, { message: updateInfo.message }), startupWarnings.length > 0 && (_jsx(Box, { borderStyle: "round", borderColor: Colors.Gray, paddingX: 1, marginY: 1, flexDirection: "column", children: startupWarnings.map((warning, index) => (_jsx(Text, { color: Colors.Gray, children: warning }, index))) })), showWelcomeBackDialog && welcomeBackInfo?.hasHistory && (_jsx(WelcomeBackDialog, { welcomeBackInfo: welcomeBackInfo, onSelect: handleWelcomeBackSelection, onClose: handleWelcomeBackClose })), showWorkspaceMigrationDialog ? (_jsx(WorkspaceMigrationDialog, { workspaceExtensions: workspaceExtensions, onOpen: onWorkspaceMigrationDialogOpen, onClose: onWorkspaceMigrationDialogClose })) : isFolderTrustDialogOpen ? (_jsx(FolderTrustDialog, { onSelect: handleFolderTrustSelect, isRestarting: isRestarting })) : quitConfirmationRequest ? (_jsx(QuitConfirmationDialog, { onSelect: (choice) => {
|
|
@@ -1087,7 +1263,97 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
1087
1263
|
? terminalHeight - staticExtraHeight
|
|
1088
1264
|
: undefined, terminalWidth: mainAreaWidth, isClosing: themeDialogAnimation.isClosing })] })) : isReleasesDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(ReleaseNotesDialog, { versions: releasesVersions, onClose: closeReleasesDialog, availableTerminalHeight: constrainHeight
|
|
1089
1265
|
? terminalHeight - staticExtraHeight
|
|
1090
|
-
: undefined, terminalWidth: mainAreaWidth, isLoading: isReleasesLoading }) })) : isSettingsDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(SettingsDialog, { settings: settings, onSelect: () => closeSettingsDialog(), onRestartRequest: () => process.exit(0), isClosing: settingsDialogAnimation.isClosing }) })) : isExtensionsDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(ExtensionsDialog, { onClose: () => closeExtensionsDialog() }) })) : isSubagentCreateDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(AgentCreationWizard, { onClose: closeSubagentCreateDialog, config: config }) })) : isAgentsManagerDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(AgentsManagerDialog, { onClose: closeAgentsManagerDialog, config: config }) })) :
|
|
1266
|
+
: undefined, terminalWidth: mainAreaWidth, isLoading: isReleasesLoading }) })) : isSettingsDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(SettingsDialog, { settings: settings, onSelect: () => closeSettingsDialog(), onRestartRequest: () => process.exit(0), isClosing: settingsDialogAnimation.isClosing }) })) : isExtensionsDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(ExtensionsDialog, { onClose: () => closeExtensionsDialog() }) })) : isSubagentCreateDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(AgentCreationWizard, { onClose: closeSubagentCreateDialog, config: config }) })) : isAgentsManagerDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(AgentsManagerDialog, { onClose: closeAgentsManagerDialog, config: config }) })) : isSingleAgentDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(SingleAgentDialog, { onComplete: async (singleAgentConfig) => {
|
|
1267
|
+
// Always preserve conversation history when switching agents
|
|
1268
|
+
// History should only be cleared via /agent exit command
|
|
1269
|
+
const currentSession = sessionStats.activeAgentSession;
|
|
1270
|
+
if (currentSession) {
|
|
1271
|
+
// Update the session with new agent type and model, preserving conversation history
|
|
1272
|
+
setActiveAgentSession({
|
|
1273
|
+
...currentSession,
|
|
1274
|
+
agentType: singleAgentConfig.selectedAgent,
|
|
1275
|
+
model: singleAgentConfig.model,
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
// If no current session, don't set one - let the user start a new conversation
|
|
1279
|
+
// Get current agent configurations
|
|
1280
|
+
const currentAgentConfigs = settings.merged.singleAgent?.agents || {};
|
|
1281
|
+
// Update the model for the specific agent in the agents config
|
|
1282
|
+
const updatedAgentConfigs = {
|
|
1283
|
+
...currentAgentConfigs,
|
|
1284
|
+
[singleAgentConfig.selectedAgent]: {
|
|
1285
|
+
model: singleAgentConfig.model,
|
|
1286
|
+
},
|
|
1287
|
+
};
|
|
1288
|
+
// Save configuration to settings with per-agent model storage
|
|
1289
|
+
settings.setValue(SettingScope.User, 'singleAgent', {
|
|
1290
|
+
selectedAgent: singleAgentConfig.selectedAgent,
|
|
1291
|
+
agents: updatedAgentConfigs,
|
|
1292
|
+
routingDisabled: false,
|
|
1293
|
+
});
|
|
1294
|
+
// Re-enable agent routing when configuration is saved
|
|
1295
|
+
setAgentRoutingDisabled(false);
|
|
1296
|
+
// Update local state to trigger Footer re-render
|
|
1297
|
+
setSelectedAgentForFooter(singleAgentConfig.selectedAgent);
|
|
1298
|
+
setAgentModelForFooter(singleAgentConfig.model);
|
|
1299
|
+
closeSingleAgentDialog();
|
|
1300
|
+
// Show appropriate message based on whether history was preserved
|
|
1301
|
+
const historyPreserved = currentSession && currentSession.agentType === singleAgentConfig.selectedAgent;
|
|
1302
|
+
addItem({
|
|
1303
|
+
type: MessageType.INFO,
|
|
1304
|
+
text: historyPreserved
|
|
1305
|
+
? `Agent model changed to ${singleAgentConfig.model} for ${singleAgentConfig.selectedAgent}. Conversation context preserved.`
|
|
1306
|
+
: `Agent configuration saved: ${singleAgentConfig.selectedAgent} with model ${singleAgentConfig.model}. You're now working with ${singleAgentConfig.selectedAgent}.`,
|
|
1307
|
+
}, Date.now());
|
|
1308
|
+
}, onCancel: closeSingleAgentDialog, initialConfig: {
|
|
1309
|
+
selectedAgent: (settings.merged.singleAgent?.selectedAgent === 'blackbox' ? 'claude' : settings.merged.singleAgent?.selectedAgent || 'claude'),
|
|
1310
|
+
model: settings.merged.singleAgent?.agents?.[settings.merged.singleAgent?.selectedAgent === 'blackbox' ? 'claude' : settings.merged.singleAgent?.selectedAgent || 'claude']?.model ||
|
|
1311
|
+
settings.merged.singleAgent?.model ||
|
|
1312
|
+
'blackboxai/anthropic/claude-sonnet-4.5',
|
|
1313
|
+
}, settings: settings }) })) : isSingleAgentModelDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(SingleAgentDialog, { onComplete: async (singleAgentConfig) => {
|
|
1314
|
+
// Always preserve conversation history when switching agents
|
|
1315
|
+
// History should only be cleared via /agent exit command
|
|
1316
|
+
const currentSession = sessionStats.activeAgentSession;
|
|
1317
|
+
if (currentSession) {
|
|
1318
|
+
// Update the session with new agent type and model, preserving conversation history
|
|
1319
|
+
setActiveAgentSession({
|
|
1320
|
+
...currentSession,
|
|
1321
|
+
agentType: singleAgentConfig.selectedAgent,
|
|
1322
|
+
model: singleAgentConfig.model,
|
|
1323
|
+
});
|
|
1324
|
+
}
|
|
1325
|
+
// If no current session, don't set one - let the user start a new conversation
|
|
1326
|
+
// Get current agent configurations
|
|
1327
|
+
const currentAgentConfigs = settings.merged.singleAgent?.agents || {};
|
|
1328
|
+
// Update the model for the specific agent in the agents config
|
|
1329
|
+
const updatedAgentConfigs = {
|
|
1330
|
+
...currentAgentConfigs,
|
|
1331
|
+
[singleAgentConfig.selectedAgent]: {
|
|
1332
|
+
model: singleAgentConfig.model,
|
|
1333
|
+
},
|
|
1334
|
+
};
|
|
1335
|
+
// Save the updated per-agent configuration
|
|
1336
|
+
settings.setValue(SettingScope.User, 'singleAgent', {
|
|
1337
|
+
selectedAgent: singleAgentConfig.selectedAgent,
|
|
1338
|
+
agents: updatedAgentConfigs,
|
|
1339
|
+
routingDisabled: false,
|
|
1340
|
+
});
|
|
1341
|
+
// Re-enable agent routing when configuration is saved
|
|
1342
|
+
setAgentRoutingDisabled(false);
|
|
1343
|
+
// Update local state to trigger Footer re-render
|
|
1344
|
+
setSelectedAgentForFooter(singleAgentConfig.selectedAgent);
|
|
1345
|
+
setAgentModelForFooter(singleAgentConfig.model);
|
|
1346
|
+
closeSingleAgentModelDialog();
|
|
1347
|
+
addItem({
|
|
1348
|
+
type: MessageType.INFO,
|
|
1349
|
+
text: `Agent model changed to ${singleAgentConfig.model} for ${singleAgentConfig.selectedAgent}. Conversation context preserved.`,
|
|
1350
|
+
}, Date.now());
|
|
1351
|
+
}, onCancel: closeSingleAgentModelDialog, initialConfig: {
|
|
1352
|
+
selectedAgent: (settings.merged.singleAgent?.selectedAgent === 'blackbox' ? 'claude' : settings.merged.singleAgent?.selectedAgent || 'claude'),
|
|
1353
|
+
model: settings.merged.singleAgent?.agents?.[settings.merged.singleAgent?.selectedAgent === 'blackbox' ? 'claude' : settings.merged.singleAgent?.selectedAgent || 'claude']?.model ||
|
|
1354
|
+
settings.merged.singleAgent?.model ||
|
|
1355
|
+
'blackboxai/anthropic/claude-sonnet-4.5',
|
|
1356
|
+
}, settings: settings, startAtModelStep: true }) })) : isMultiAgentConfigDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(MultiAgentConfigDialog, { onComplete: (multiAgentConfig) => {
|
|
1091
1357
|
// Save configuration to settings
|
|
1092
1358
|
settings.setValue(SettingScope.User, 'multiAgent', multiAgentConfig);
|
|
1093
1359
|
closeMultiAgentConfigDialog();
|
|
@@ -1137,7 +1403,7 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
1137
1403
|
} })) : (_jsx(AuthInProgress, { onTimeout: () => {
|
|
1138
1404
|
// User cancelled - just return to agent without showing dialog
|
|
1139
1405
|
cancelAuthentication();
|
|
1140
|
-
} })), 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, isClosing: authDialogAnimation.isClosing }) })) : 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 })] })) : isModelSelectionDialogOpen ? (_jsx(ModelSelectionDialog, { availableModels: availableModelsForDialog, currentModel: currentModel, onSelect: handleModelSelect, onCancel: handleModelSelectionClose, isClosing: modelDialogAnimation.isClosing })) : isVisionSwitchDialogOpen ? (_jsx(ModelSwitchDialog, { onSelect: handleVisionSwitchSelect })) : isVoiceConfigDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(VoiceConfigDialog, { settings: settings, onClose: closeVoiceConfigDialog, isClosing: voiceConfigDialogAnimation.isClosing, onConfigComplete: handleVoiceConfigComplete }) })) : showPrivacyNotice ? (_jsx(PrivacyNotice, { onExit: () => setShowPrivacyNotice(false), config: config })) : (_jsxs(_Fragment, { children: [showTodoListDialog && (_jsx(TodoListDialog, { todos: todos, onClose: () => setShowTodoListDialog(false) })), _jsx(LoadingIndicator, { thought: streamingState === StreamingState.WaitingForConfirmation ||
|
|
1406
|
+
} })), 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, isClosing: authDialogAnimation.isClosing }) })) : 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 })] })) : isModelSelectionDialogOpen ? (_jsx(ModelSelectionDialog, { availableModels: availableModelsForDialog, currentModel: currentModel, onSelect: handleModelSelect, onCancel: handleModelSelectionClose, isClosing: modelDialogAnimation.isClosing })) : isVisionSwitchDialogOpen ? (_jsx(ModelSwitchDialog, { onSelect: handleVisionSwitchSelect })) : isVoiceConfigDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(VoiceConfigDialog, { settings: settings, onClose: closeVoiceConfigDialog, isClosing: voiceConfigDialogAnimation.isClosing, onConfigComplete: handleVoiceConfigComplete }) })) : isAgentSetDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(AgentSetDialog, { settings: settings, onClose: closeAgentSetDialog, onAgentSelected: handleAgentSelected }) })) : showPrivacyNotice ? (_jsx(PrivacyNotice, { onExit: () => setShowPrivacyNotice(false), config: config })) : (_jsxs(_Fragment, { children: [showTodoListDialog && (_jsx(TodoListDialog, { todos: todos, onClose: () => setShowTodoListDialog(false) })), _jsx(LoadingIndicator, { thought: streamingState === StreamingState.WaitingForConfirmation ||
|
|
1141
1407
|
config.getAccessibility()?.disableLoadingPhrases ||
|
|
1142
1408
|
config.getScreenReader()
|
|
1143
1409
|
? undefined
|
|
@@ -1153,9 +1419,9 @@ const App = ({ config, settings, startupWarnings = [], version, initialSlashComm
|
|
|
1153
1419
|
return (
|
|
1154
1420
|
// Ensure the Box takes full width so truncation calculates correctly
|
|
1155
1421
|
_jsx(Box, { paddingLeft: 2, width: "100%", children: _jsx(Text, { dimColor: true, wrap: "truncate", children: preview }) }, index));
|
|
1156
|
-
}), messageQueue.length > MAX_DISPLAYED_QUEUED_MESSAGES && (_jsx(Box, { paddingLeft: 2, children: _jsxs(Text, { dimColor: true, children: ["... (+", messageQueue.length - MAX_DISPLAYED_QUEUED_MESSAGES, "more)"] }) }))] })), _jsxs(Box, { marginTop: 1, justifyContent: "space-between", width: "100%", flexDirection: isNarrow ? 'column' : 'row', alignItems: isNarrow ? 'flex-start' : 'center', children: [_jsxs(Box, { children: [process.env['GEMINI_SYSTEM_MD'] && (_jsx(Text, { color: Colors.AccentRed, children: "|\u2310\u25A0_\u25A0| " })), ctrlCPressedOnce ? (_jsx(Text, { color: Colors.AccentYellow, children: "Press Ctrl+C again to confirm exit." })) : ctrlDPressedOnce ? (_jsx(Text, { color: Colors.AccentYellow, children: "Press Ctrl+D again to exit." })) : showEscapePrompt ? (_jsx(Text, { color: Colors.Gray, children: "Press Esc again to clear." })) :
|
|
1157
|
-
!shellModeActive && (_jsx(AutoAcceptIndicator, { approvalMode: showAutoAcceptIndicator })), shellModeActive && _jsx(ShellModeIndicator, {})] })] }), showErrorDetails && (_jsx(OverflowProvider, { children: _jsxs(Box, { flexDirection: "column", children: [_jsx(DetailedMessagesDisplay, { messages: filteredConsoleMessages, maxHeight: constrainHeight ? debugConsoleMaxHeight : undefined, width: inputWidth }), _jsx(ShowMoreLines, { constrainHeight: constrainHeight })] }) })), isInputActive && (_jsx(InputPrompt, { buffer: buffer, inputWidth: inputWidth, suggestionsWidth: suggestionsWidth, onSubmit: handleFinalSubmit, userMessages: userMessages, onClearScreen: handleClearScreen, config: config, slashCommands: slashCommands, commandContext: commandContext, shellModeActive: shellModeActive, setShellModeActive: setShellModeActive, onEscapePromptChange: handleEscapePromptChange, focus: isFocused, vimHandleInput: vimHandleInput, placeholder: placeholder }))] })), initError && streamingState !== StreamingState.Responding && (_jsx(Box, { borderStyle: "round", borderColor: Colors.AccentRed, paddingX: 1, marginBottom: 1, children: history.find((item) => item.type === 'error' && item.text?.includes(initError))?.text ? (_jsx(Text, { color: Colors.AccentRed, children: history.find((item) => item.type === 'error' && item.text?.includes(initError))?.text })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { color: Colors.AccentRed, children: ["Initialization Error: ", initError] }), _jsxs(Text, { color: Colors.AccentRed, children: [' ', "Please check API key and configuration."] })] })) })), !settings.merged.ui?.hideFooter && (_jsx(Footer, { model: currentModel, targetDir: config.getTargetDir(), debugMode: config.getDebugMode(), branchName: branchName, debugMessage: debugMessage, corgiMode: corgiMode, errorCount: errorCount, showErrorDetails: showErrorDetails, showMemoryUsage: config.getDebugMode() ||
|
|
1422
|
+
}), messageQueue.length > MAX_DISPLAYED_QUEUED_MESSAGES && (_jsx(Box, { paddingLeft: 2, children: _jsxs(Text, { dimColor: true, children: ["... (+", messageQueue.length - MAX_DISPLAYED_QUEUED_MESSAGES, "more)"] }) }))] })), _jsxs(Box, { marginTop: 1, justifyContent: "space-between", width: "100%", flexDirection: isNarrow ? 'column' : 'row', alignItems: isNarrow ? 'flex-start' : 'center', children: [_jsxs(Box, { children: [process.env['GEMINI_SYSTEM_MD'] && (_jsx(Text, { color: Colors.AccentRed, children: "|\u2310\u25A0_\u25A0| " })), ctrlCPressedOnce ? (_jsx(Text, { color: Colors.AccentYellow, children: "Press Ctrl+C again to confirm exit." })) : ctrlDPressedOnce ? (_jsx(Text, { color: Colors.AccentYellow, children: "Press Ctrl+D again to exit." })) : showEscapePrompt ? (_jsx(Text, { color: Colors.Gray, children: "Press Esc again to clear." })) : null] }), _jsxs(Box, { paddingTop: isNarrow ? 1 : 0, children: [showAutoAcceptIndicator !== ApprovalMode.DEFAULT &&
|
|
1423
|
+
!shellModeActive && (_jsx(AutoAcceptIndicator, { approvalMode: showAutoAcceptIndicator })), shellModeActive && _jsx(ShellModeIndicator, {})] })] }), showErrorDetails && (_jsx(OverflowProvider, { children: _jsxs(Box, { flexDirection: "column", children: [_jsx(DetailedMessagesDisplay, { messages: filteredConsoleMessages, maxHeight: constrainHeight ? debugConsoleMaxHeight : undefined, width: inputWidth }), _jsx(ShowMoreLines, { constrainHeight: constrainHeight })] }) })), isInputActive && (_jsx(InputPrompt, { buffer: buffer, inputWidth: inputWidth, suggestionsWidth: suggestionsWidth, onSubmit: handleFinalSubmit, userMessages: userMessages, onClearScreen: handleClearScreen, config: config, slashCommands: slashCommands, commandContext: commandContext, shellModeActive: shellModeActive, setShellModeActive: setShellModeActive, onEscapePromptChange: handleEscapePromptChange, focus: isFocused, vimHandleInput: vimHandleInput, placeholder: placeholder })), showHelpTip && isInputActive && history.length === 0 && (_jsxs(Box, { marginTop: 1, marginBottom: 1, flexDirection: "column", children: [_jsx(Text, { color: Colors.Gray, children: "Run /help for tips" }), _jsx(Text, { color: Colors.Gray, children: "Use Ctrl+J to newline" })] }))] })), initError && streamingState !== StreamingState.Responding && (_jsx(Box, { borderStyle: "round", borderColor: Colors.AccentRed, paddingX: 1, marginBottom: 1, children: history.find((item) => item.type === 'error' && item.text?.includes(initError))?.text ? (_jsx(Text, { color: Colors.AccentRed, children: history.find((item) => item.type === 'error' && item.text?.includes(initError))?.text })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { color: Colors.AccentRed, children: ["Initialization Error: ", initError] }), _jsxs(Text, { color: Colors.AccentRed, children: [' ', "Please check API key and configuration."] })] })) })), !settings.merged.ui?.hideFooter && (_jsx(Footer, { model: currentModel, targetDir: config.getTargetDir(), debugMode: config.getDebugMode(), branchName: branchName, debugMessage: debugMessage, corgiMode: corgiMode, errorCount: errorCount, showErrorDetails: showErrorDetails, showMemoryUsage: config.getDebugMode() ||
|
|
1158
1424
|
settings.merged.ui?.showMemoryUsage ||
|
|
1159
|
-
false, promptTokenCount: sessionStats.lastPromptTokenCount, nightly: nightly, vimMode: vimModeEnabled ? vimMode : undefined, isTrustedFolder: isTrustedFolderState }))] })] }) }));
|
|
1425
|
+
false, promptTokenCount: sessionStats.lastPromptTokenCount, nightly: nightly, vimMode: vimModeEnabled ? vimMode : undefined, isTrustedFolder: isTrustedFolderState, selectedAgent: selectedAgentForFooter, agentModel: agentModelForFooter, activeAgentSession: sessionStats.activeAgentSession, agentRoutingDisabled: sessionStats.agentRoutingDisabled }))] })] }) }));
|
|
1160
1426
|
};
|
|
1161
1427
|
//# sourceMappingURL=App.js.map
|