snow-ai 0.4.15 → 0.4.17
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/bundle/cli.mjs +477445 -0
- package/bundle/sql-wasm.wasm +0 -0
- package/package.json +31 -26
- package/dist/agents/codebaseIndexAgent.d.ts +0 -102
- package/dist/agents/codebaseIndexAgent.js +0 -641
- package/dist/agents/codebaseReviewAgent.d.ts +0 -61
- package/dist/agents/codebaseReviewAgent.js +0 -301
- package/dist/agents/compactAgent.d.ts +0 -55
- package/dist/agents/compactAgent.js +0 -306
- package/dist/agents/promptOptimizeAgent.d.ts +0 -54
- package/dist/agents/promptOptimizeAgent.js +0 -268
- package/dist/agents/reviewAgent.d.ts +0 -50
- package/dist/agents/reviewAgent.js +0 -265
- package/dist/agents/summaryAgent.d.ts +0 -57
- package/dist/agents/summaryAgent.js +0 -260
- package/dist/api/anthropic.d.ts +0 -44
- package/dist/api/anthropic.js +0 -598
- package/dist/api/chat.d.ts +0 -73
- package/dist/api/chat.js +0 -386
- package/dist/api/embedding.d.ts +0 -34
- package/dist/api/embedding.js +0 -80
- package/dist/api/gemini.d.ts +0 -31
- package/dist/api/gemini.js +0 -445
- package/dist/api/models.d.ts +0 -15
- package/dist/api/models.js +0 -139
- package/dist/api/responses.d.ts +0 -38
- package/dist/api/responses.js +0 -515
- package/dist/api/systemPrompt.d.ts +0 -4
- package/dist/api/systemPrompt.js +0 -408
- package/dist/api/types.d.ts +0 -53
- package/dist/api/types.js +0 -4
- package/dist/app.d.ts +0 -8
- package/dist/app.js +0 -112
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -199
- package/dist/hooks/useAgentPicker.d.ts +0 -14
- package/dist/hooks/useAgentPicker.js +0 -119
- package/dist/hooks/useClipboard.d.ts +0 -4
- package/dist/hooks/useClipboard.js +0 -175
- package/dist/hooks/useCommandHandler.d.ts +0 -35
- package/dist/hooks/useCommandHandler.js +0 -346
- package/dist/hooks/useCommandPanel.d.ts +0 -17
- package/dist/hooks/useCommandPanel.js +0 -114
- package/dist/hooks/useConversation.d.ts +0 -49
- package/dist/hooks/useConversation.js +0 -1052
- package/dist/hooks/useFilePicker.d.ts +0 -18
- package/dist/hooks/useFilePicker.js +0 -224
- package/dist/hooks/useGlobalExit.d.ts +0 -5
- package/dist/hooks/useGlobalExit.js +0 -34
- package/dist/hooks/useGlobalNavigation.d.ts +0 -6
- package/dist/hooks/useGlobalNavigation.js +0 -17
- package/dist/hooks/useHistoryNavigation.d.ts +0 -35
- package/dist/hooks/useHistoryNavigation.js +0 -133
- package/dist/hooks/useInputBuffer.d.ts +0 -6
- package/dist/hooks/useInputBuffer.js +0 -45
- package/dist/hooks/useKeyboardInput.d.ts +0 -80
- package/dist/hooks/useKeyboardInput.js +0 -608
- package/dist/hooks/useSessionManagement.d.ts +0 -10
- package/dist/hooks/useSessionManagement.js +0 -43
- package/dist/hooks/useSessionSave.d.ts +0 -8
- package/dist/hooks/useSessionSave.js +0 -63
- package/dist/hooks/useSnapshotState.d.ts +0 -26
- package/dist/hooks/useSnapshotState.js +0 -28
- package/dist/hooks/useStreamingState.d.ts +0 -33
- package/dist/hooks/useStreamingState.js +0 -105
- package/dist/hooks/useTerminalFocus.d.ts +0 -28
- package/dist/hooks/useTerminalFocus.js +0 -87
- package/dist/hooks/useTerminalSize.d.ts +0 -4
- package/dist/hooks/useTerminalSize.js +0 -20
- package/dist/hooks/useTodoPicker.d.ts +0 -16
- package/dist/hooks/useTodoPicker.js +0 -94
- package/dist/hooks/useToolConfirmation.d.ts +0 -19
- package/dist/hooks/useToolConfirmation.js +0 -61
- package/dist/hooks/useVSCodeState.d.ts +0 -8
- package/dist/hooks/useVSCodeState.js +0 -81
- package/dist/i18n/I18nContext.d.ts +0 -14
- package/dist/i18n/I18nContext.js +0 -24
- package/dist/i18n/index.d.ts +0 -3
- package/dist/i18n/index.js +0 -2
- package/dist/i18n/lang/en.d.ts +0 -2
- package/dist/i18n/lang/en.js +0 -502
- package/dist/i18n/lang/es.d.ts +0 -2
- package/dist/i18n/lang/es.js +0 -502
- package/dist/i18n/lang/ja.d.ts +0 -2
- package/dist/i18n/lang/ja.js +0 -502
- package/dist/i18n/lang/ko.d.ts +0 -2
- package/dist/i18n/lang/ko.js +0 -502
- package/dist/i18n/lang/zh-TW.d.ts +0 -2
- package/dist/i18n/lang/zh-TW.js +0 -502
- package/dist/i18n/lang/zh.d.ts +0 -2
- package/dist/i18n/lang/zh.js +0 -502
- package/dist/i18n/translations.d.ts +0 -2
- package/dist/i18n/translations.js +0 -14
- package/dist/i18n/types.d.ts +0 -478
- package/dist/i18n/types.js +0 -1
- package/dist/mcp/aceCodeSearch.d.ts +0 -247
- package/dist/mcp/aceCodeSearch.js +0 -1058
- package/dist/mcp/bash.d.ts +0 -50
- package/dist/mcp/bash.js +0 -153
- package/dist/mcp/codebaseSearch.d.ts +0 -44
- package/dist/mcp/codebaseSearch.js +0 -275
- package/dist/mcp/filesystem.d.ts +0 -392
- package/dist/mcp/filesystem.js +0 -1445
- package/dist/mcp/ideDiagnostics.d.ts +0 -36
- package/dist/mcp/ideDiagnostics.js +0 -90
- package/dist/mcp/notebook.d.ts +0 -10
- package/dist/mcp/notebook.js +0 -367
- package/dist/mcp/subagent.d.ts +0 -37
- package/dist/mcp/subagent.js +0 -113
- package/dist/mcp/todo.d.ts +0 -46
- package/dist/mcp/todo.js +0 -511
- package/dist/mcp/types/aceCodeSearch.types.d.ts +0 -92
- package/dist/mcp/types/aceCodeSearch.types.js +0 -4
- package/dist/mcp/types/bash.types.d.ts +0 -13
- package/dist/mcp/types/bash.types.js +0 -4
- package/dist/mcp/types/filesystem.types.d.ts +0 -210
- package/dist/mcp/types/filesystem.types.js +0 -27
- package/dist/mcp/types/todo.types.d.ts +0 -27
- package/dist/mcp/types/todo.types.js +0 -4
- package/dist/mcp/types/websearch.types.d.ts +0 -30
- package/dist/mcp/types/websearch.types.js +0 -4
- package/dist/mcp/utils/aceCodeSearch/filesystem.utils.d.ts +0 -34
- package/dist/mcp/utils/aceCodeSearch/filesystem.utils.js +0 -146
- package/dist/mcp/utils/aceCodeSearch/language.utils.d.ts +0 -14
- package/dist/mcp/utils/aceCodeSearch/language.utils.js +0 -418
- package/dist/mcp/utils/aceCodeSearch/search.utils.d.ts +0 -31
- package/dist/mcp/utils/aceCodeSearch/search.utils.js +0 -136
- package/dist/mcp/utils/aceCodeSearch/symbol.utils.d.ts +0 -20
- package/dist/mcp/utils/aceCodeSearch/symbol.utils.js +0 -141
- package/dist/mcp/utils/bash/security.utils.d.ts +0 -20
- package/dist/mcp/utils/bash/security.utils.js +0 -34
- package/dist/mcp/utils/filesystem/batch-operations.utils.d.ts +0 -39
- package/dist/mcp/utils/filesystem/batch-operations.utils.js +0 -182
- package/dist/mcp/utils/filesystem/code-analysis.utils.d.ts +0 -18
- package/dist/mcp/utils/filesystem/code-analysis.utils.js +0 -165
- package/dist/mcp/utils/filesystem/match-finder.utils.d.ts +0 -16
- package/dist/mcp/utils/filesystem/match-finder.utils.js +0 -85
- package/dist/mcp/utils/filesystem/office-parser.utils.d.ts +0 -43
- package/dist/mcp/utils/filesystem/office-parser.utils.js +0 -163
- package/dist/mcp/utils/filesystem/path-fixer.utils.d.ts +0 -7
- package/dist/mcp/utils/filesystem/path-fixer.utils.js +0 -60
- package/dist/mcp/utils/filesystem/similarity.utils.d.ts +0 -22
- package/dist/mcp/utils/filesystem/similarity.utils.js +0 -75
- package/dist/mcp/utils/todo/date.utils.d.ts +0 -9
- package/dist/mcp/utils/todo/date.utils.js +0 -14
- package/dist/mcp/utils/websearch/browser.utils.d.ts +0 -8
- package/dist/mcp/utils/websearch/browser.utils.js +0 -58
- package/dist/mcp/utils/websearch/text.utils.d.ts +0 -16
- package/dist/mcp/utils/websearch/text.utils.js +0 -39
- package/dist/mcp/websearch.d.ts +0 -88
- package/dist/mcp/websearch.js +0 -375
- package/dist/test/logger-test.d.ts +0 -1
- package/dist/test/logger-test.js +0 -7
- package/dist/types/index.d.ts +0 -15
- package/dist/types/index.js +0 -1
- package/dist/ui/components/AgentPickerPanel.d.ts +0 -10
- package/dist/ui/components/AgentPickerPanel.js +0 -74
- package/dist/ui/components/ChatInput.d.ts +0 -46
- package/dist/ui/components/ChatInput.js +0 -379
- package/dist/ui/components/CommandPanel.d.ts +0 -15
- package/dist/ui/components/CommandPanel.js +0 -80
- package/dist/ui/components/DiffViewer.d.ts +0 -11
- package/dist/ui/components/DiffViewer.js +0 -178
- package/dist/ui/components/FileList.d.ts +0 -15
- package/dist/ui/components/FileList.js +0 -360
- package/dist/ui/components/FileRollbackConfirmation.d.ts +0 -8
- package/dist/ui/components/FileRollbackConfirmation.js +0 -108
- package/dist/ui/components/HelpPanel.d.ts +0 -2
- package/dist/ui/components/HelpPanel.js +0 -67
- package/dist/ui/components/MCPInfoPanel.d.ts +0 -2
- package/dist/ui/components/MCPInfoPanel.js +0 -108
- package/dist/ui/components/MCPInfoScreen.d.ts +0 -7
- package/dist/ui/components/MCPInfoScreen.js +0 -115
- package/dist/ui/components/MarkdownRenderer.d.ts +0 -6
- package/dist/ui/components/MarkdownRenderer.js +0 -70
- package/dist/ui/components/Menu.d.ts +0 -17
- package/dist/ui/components/Menu.js +0 -88
- package/dist/ui/components/MessageList.d.ts +0 -56
- package/dist/ui/components/MessageList.js +0 -97
- package/dist/ui/components/PendingMessages.d.ts +0 -13
- package/dist/ui/components/PendingMessages.js +0 -29
- package/dist/ui/components/PendingToolCalls.d.ts +0 -11
- package/dist/ui/components/PendingToolCalls.js +0 -35
- package/dist/ui/components/ScrollableSelectInput.d.ts +0 -29
- package/dist/ui/components/ScrollableSelectInput.js +0 -157
- package/dist/ui/components/SessionListPanel.d.ts +0 -7
- package/dist/ui/components/SessionListPanel.js +0 -175
- package/dist/ui/components/SessionListScreen.d.ts +0 -7
- package/dist/ui/components/SessionListScreen.js +0 -217
- package/dist/ui/components/SessionListScreenWrapper.d.ts +0 -7
- package/dist/ui/components/SessionListScreenWrapper.js +0 -14
- package/dist/ui/components/ShimmerText.d.ts +0 -9
- package/dist/ui/components/ShimmerText.js +0 -30
- package/dist/ui/components/TodoPickerPanel.d.ts +0 -14
- package/dist/ui/components/TodoPickerPanel.js +0 -119
- package/dist/ui/components/TodoTree.d.ts +0 -15
- package/dist/ui/components/TodoTree.js +0 -60
- package/dist/ui/components/ToolConfirmation.d.ts +0 -21
- package/dist/ui/components/ToolConfirmation.js +0 -204
- package/dist/ui/components/ToolResultPreview.d.ts +0 -13
- package/dist/ui/components/ToolResultPreview.js +0 -337
- package/dist/ui/components/UsagePanel.d.ts +0 -2
- package/dist/ui/components/UsagePanel.js +0 -394
- package/dist/ui/contexts/ThemeContext.d.ts +0 -13
- package/dist/ui/contexts/ThemeContext.js +0 -28
- package/dist/ui/pages/ChatScreen.d.ts +0 -6
- package/dist/ui/pages/ChatScreen.js +0 -1495
- package/dist/ui/pages/CodeBaseConfigScreen.d.ts +0 -8
- package/dist/ui/pages/CodeBaseConfigScreen.js +0 -350
- package/dist/ui/pages/ConfigScreen.d.ts +0 -8
- package/dist/ui/pages/ConfigScreen.js +0 -1101
- package/dist/ui/pages/CustomHeadersScreen.d.ts +0 -6
- package/dist/ui/pages/CustomHeadersScreen.js +0 -502
- package/dist/ui/pages/HeadlessModeScreen.d.ts +0 -7
- package/dist/ui/pages/HeadlessModeScreen.js +0 -381
- package/dist/ui/pages/LanguageSettingsScreen.d.ts +0 -7
- package/dist/ui/pages/LanguageSettingsScreen.js +0 -91
- package/dist/ui/pages/MCPConfigScreen.d.ts +0 -6
- package/dist/ui/pages/MCPConfigScreen.js +0 -55
- package/dist/ui/pages/ProxyConfigScreen.d.ts +0 -8
- package/dist/ui/pages/ProxyConfigScreen.js +0 -149
- package/dist/ui/pages/SensitiveCommandConfigScreen.d.ts +0 -7
- package/dist/ui/pages/SensitiveCommandConfigScreen.js +0 -271
- package/dist/ui/pages/SubAgentConfigScreen.d.ts +0 -9
- package/dist/ui/pages/SubAgentConfigScreen.js +0 -435
- package/dist/ui/pages/SubAgentListScreen.d.ts +0 -9
- package/dist/ui/pages/SubAgentListScreen.js +0 -131
- package/dist/ui/pages/SystemPromptConfigScreen.d.ts +0 -6
- package/dist/ui/pages/SystemPromptConfigScreen.js +0 -326
- package/dist/ui/pages/ThemeSettingsScreen.d.ts +0 -7
- package/dist/ui/pages/ThemeSettingsScreen.js +0 -106
- package/dist/ui/pages/WelcomeScreen.d.ts +0 -7
- package/dist/ui/pages/WelcomeScreen.js +0 -217
- package/dist/ui/themes/index.d.ts +0 -23
- package/dist/ui/themes/index.js +0 -140
- package/dist/utils/apiConfig.d.ts +0 -126
- package/dist/utils/apiConfig.js +0 -423
- package/dist/utils/autoCompress.d.ts +0 -15
- package/dist/utils/autoCompress.js +0 -24
- package/dist/utils/chatExporter.d.ts +0 -9
- package/dist/utils/chatExporter.js +0 -118
- package/dist/utils/checkpointManager.d.ts +0 -74
- package/dist/utils/checkpointManager.js +0 -181
- package/dist/utils/codebaseConfig.d.ts +0 -16
- package/dist/utils/codebaseConfig.js +0 -67
- package/dist/utils/codebaseDatabase.d.ts +0 -102
- package/dist/utils/codebaseDatabase.js +0 -333
- package/dist/utils/codebaseSearchEvents.d.ts +0 -16
- package/dist/utils/codebaseSearchEvents.js +0 -13
- package/dist/utils/commandExecutor.d.ts +0 -13
- package/dist/utils/commandExecutor.js +0 -26
- package/dist/utils/commands/agent.d.ts +0 -2
- package/dist/utils/commands/agent.js +0 -12
- package/dist/utils/commands/clear.d.ts +0 -2
- package/dist/utils/commands/clear.js +0 -12
- package/dist/utils/commands/compact.d.ts +0 -2
- package/dist/utils/commands/compact.js +0 -12
- package/dist/utils/commands/export.d.ts +0 -2
- package/dist/utils/commands/export.js +0 -12
- package/dist/utils/commands/help.d.ts +0 -2
- package/dist/utils/commands/help.js +0 -11
- package/dist/utils/commands/home.d.ts +0 -2
- package/dist/utils/commands/home.js +0 -34
- package/dist/utils/commands/ide.d.ts +0 -2
- package/dist/utils/commands/ide.js +0 -32
- package/dist/utils/commands/init.d.ts +0 -2
- package/dist/utils/commands/init.js +0 -93
- package/dist/utils/commands/mcp.d.ts +0 -2
- package/dist/utils/commands/mcp.js +0 -12
- package/dist/utils/commands/resume.d.ts +0 -2
- package/dist/utils/commands/resume.js +0 -12
- package/dist/utils/commands/review.d.ts +0 -2
- package/dist/utils/commands/review.js +0 -81
- package/dist/utils/commands/role.d.ts +0 -2
- package/dist/utils/commands/role.js +0 -37
- package/dist/utils/commands/todoPicker.d.ts +0 -2
- package/dist/utils/commands/todoPicker.js +0 -12
- package/dist/utils/commands/usage.d.ts +0 -2
- package/dist/utils/commands/usage.js +0 -12
- package/dist/utils/commands/yolo.d.ts +0 -2
- package/dist/utils/commands/yolo.js +0 -12
- package/dist/utils/configManager.d.ts +0 -45
- package/dist/utils/configManager.js +0 -303
- package/dist/utils/contextCompressor.d.ts +0 -16
- package/dist/utils/contextCompressor.js +0 -334
- package/dist/utils/devMode.d.ts +0 -13
- package/dist/utils/devMode.js +0 -54
- package/dist/utils/escapeHandler.d.ts +0 -79
- package/dist/utils/escapeHandler.js +0 -153
- package/dist/utils/fileDialog.d.ts +0 -9
- package/dist/utils/fileDialog.js +0 -74
- package/dist/utils/fileUtils.d.ts +0 -40
- package/dist/utils/fileUtils.js +0 -185
- package/dist/utils/historyManager.d.ts +0 -45
- package/dist/utils/historyManager.js +0 -159
- package/dist/utils/incrementalSnapshot.d.ts +0 -109
- package/dist/utils/incrementalSnapshot.js +0 -383
- package/dist/utils/index.d.ts +0 -11
- package/dist/utils/index.js +0 -18
- package/dist/utils/languageConfig.d.ts +0 -21
- package/dist/utils/languageConfig.js +0 -61
- package/dist/utils/logger.d.ts +0 -37
- package/dist/utils/logger.js +0 -122
- package/dist/utils/mcpToolsManager.d.ts +0 -52
- package/dist/utils/mcpToolsManager.js +0 -878
- package/dist/utils/messageFormatter.d.ts +0 -12
- package/dist/utils/messageFormatter.js +0 -115
- package/dist/utils/notebookManager.d.ts +0 -59
- package/dist/utils/notebookManager.js +0 -213
- package/dist/utils/patch-highlight.d.ts +0 -5
- package/dist/utils/patch-highlight.js +0 -23
- package/dist/utils/processManager.d.ts +0 -27
- package/dist/utils/processManager.js +0 -75
- package/dist/utils/proxyUtils.d.ts +0 -15
- package/dist/utils/proxyUtils.js +0 -50
- package/dist/utils/resourceMonitor.d.ts +0 -65
- package/dist/utils/resourceMonitor.js +0 -175
- package/dist/utils/retryUtils.d.ts +0 -49
- package/dist/utils/retryUtils.js +0 -303
- package/dist/utils/sensitiveCommandManager.d.ts +0 -53
- package/dist/utils/sensitiveCommandManager.js +0 -308
- package/dist/utils/sessionConverter.d.ts +0 -7
- package/dist/utils/sessionConverter.js +0 -306
- package/dist/utils/sessionManager.d.ts +0 -53
- package/dist/utils/sessionManager.js +0 -371
- package/dist/utils/subAgentConfig.d.ts +0 -50
- package/dist/utils/subAgentConfig.js +0 -221
- package/dist/utils/subAgentExecutor.d.ts +0 -40
- package/dist/utils/subAgentExecutor.js +0 -434
- package/dist/utils/terminal.d.ts +0 -5
- package/dist/utils/terminal.js +0 -13
- package/dist/utils/textBuffer.d.ts +0 -99
- package/dist/utils/textBuffer.js +0 -547
- package/dist/utils/textUtils.d.ts +0 -37
- package/dist/utils/textUtils.js +0 -102
- package/dist/utils/themeConfig.d.ts +0 -21
- package/dist/utils/themeConfig.js +0 -61
- package/dist/utils/todoPreprocessor.d.ts +0 -5
- package/dist/utils/todoPreprocessor.js +0 -18
- package/dist/utils/todoScanner.d.ts +0 -8
- package/dist/utils/todoScanner.js +0 -148
- package/dist/utils/toolDisplayConfig.d.ts +0 -16
- package/dist/utils/toolDisplayConfig.js +0 -47
- package/dist/utils/toolExecutor.d.ts +0 -37
- package/dist/utils/toolExecutor.js +0 -224
- package/dist/utils/usageLogger.d.ts +0 -11
- package/dist/utils/usageLogger.js +0 -114
- package/dist/utils/vscodeConnection.d.ts +0 -76
- package/dist/utils/vscodeConnection.js +0 -430
- package/dist/utils/workspaceSnapshot.d.ts +0 -63
- package/dist/utils/workspaceSnapshot.js +0 -300
|
@@ -1,608 +0,0 @@
|
|
|
1
|
-
import { useRef, useEffect } from 'react';
|
|
2
|
-
import { useInput } from 'ink';
|
|
3
|
-
import { executeCommand } from '../utils/commandExecutor.js';
|
|
4
|
-
export function useKeyboardInput(options) {
|
|
5
|
-
const { buffer, disabled, triggerUpdate, forceUpdate, showCommands, setShowCommands, commandSelectedIndex, setCommandSelectedIndex, getFilteredCommands, updateCommandPanelState, onCommand, showFilePicker, setShowFilePicker, fileSelectedIndex, setFileSelectedIndex, setFileQuery, setAtSymbolPosition, filteredFileCount, updateFilePickerState, handleFileSelect, fileListRef, showHistoryMenu, setShowHistoryMenu, historySelectedIndex, setHistorySelectedIndex, escapeKeyCount, setEscapeKeyCount, escapeKeyTimer, getUserMessages, handleHistorySelect, currentHistoryIndex, navigateHistoryUp, navigateHistoryDown, resetHistoryNavigation, saveToHistory, pasteFromClipboard, onSubmit, ensureFocus, showAgentPicker, setShowAgentPicker, agentSelectedIndex, setAgentSelectedIndex, updateAgentPickerState, getFilteredAgents, handleAgentSelect, showTodoPicker, setShowTodoPicker, todoSelectedIndex, setTodoSelectedIndex, todos, selectedTodos, toggleTodoSelection, confirmTodoSelection, todoSearchQuery, setTodoSearchQuery, } = options;
|
|
6
|
-
// Mark variables as used (they are used in useInput closure below)
|
|
7
|
-
void todoSelectedIndex;
|
|
8
|
-
void selectedTodos;
|
|
9
|
-
// Track paste detection
|
|
10
|
-
const inputBuffer = useRef('');
|
|
11
|
-
const inputTimer = useRef(null);
|
|
12
|
-
const isPasting = useRef(false); // Track if we're in pasting mode
|
|
13
|
-
const inputStartCursorPos = useRef(0); // Track cursor position when input starts accumulating
|
|
14
|
-
// Cleanup timer on unmount
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
return () => {
|
|
17
|
-
if (inputTimer.current) {
|
|
18
|
-
clearTimeout(inputTimer.current);
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
}, []);
|
|
22
|
-
// Force immediate state update for critical operations like backspace
|
|
23
|
-
const forceStateUpdate = () => {
|
|
24
|
-
const text = buffer.getFullText();
|
|
25
|
-
const cursorPos = buffer.getCursorPosition();
|
|
26
|
-
updateFilePickerState(text, cursorPos);
|
|
27
|
-
updateAgentPickerState(text, cursorPos);
|
|
28
|
-
updateCommandPanelState(text);
|
|
29
|
-
forceUpdate({});
|
|
30
|
-
};
|
|
31
|
-
// Handle input using useInput hook
|
|
32
|
-
useInput((input, key) => {
|
|
33
|
-
if (disabled)
|
|
34
|
-
return;
|
|
35
|
-
// Filter out focus events more robustly
|
|
36
|
-
// Focus events: ESC[I (focus in) or ESC[O (focus out)
|
|
37
|
-
// Some terminals may send these with or without ESC, and they might appear
|
|
38
|
-
// anywhere in the input string (especially during drag-and-drop with Shift held)
|
|
39
|
-
// We need to filter them out but NOT remove legitimate user input
|
|
40
|
-
const focusEventPattern = /(\s|^)\[(?:I|O)(?=(?:\s|$|["'~\\\/]|[A-Za-z]:))/;
|
|
41
|
-
if (
|
|
42
|
-
// Complete escape sequences
|
|
43
|
-
input === '\x1b[I' ||
|
|
44
|
-
input === '\x1b[O' ||
|
|
45
|
-
// Standalone sequences (exact match only)
|
|
46
|
-
input === '[I' ||
|
|
47
|
-
input === '[O' ||
|
|
48
|
-
// Filter if input ONLY contains focus events, whitespace, and optional ESC prefix
|
|
49
|
-
(/^[\s\x1b\[IO]+$/.test(input) && focusEventPattern.test(input))) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
// Shift+Tab - Toggle YOLO mode
|
|
53
|
-
if (key.shift && key.tab) {
|
|
54
|
-
executeCommand('yolo').then(result => {
|
|
55
|
-
if (onCommand) {
|
|
56
|
-
onCommand('yolo', result);
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
// Handle escape key for double-ESC history navigation
|
|
62
|
-
if (key.escape) {
|
|
63
|
-
// Close todo picker if open
|
|
64
|
-
if (showTodoPicker) {
|
|
65
|
-
setShowTodoPicker(false);
|
|
66
|
-
setTodoSelectedIndex(0);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
// Close agent picker if open
|
|
70
|
-
if (showAgentPicker) {
|
|
71
|
-
setShowAgentPicker(false);
|
|
72
|
-
setAgentSelectedIndex(0);
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
// Close file picker if open
|
|
76
|
-
if (showFilePicker) {
|
|
77
|
-
setShowFilePicker(false);
|
|
78
|
-
setFileSelectedIndex(0);
|
|
79
|
-
setFileQuery('');
|
|
80
|
-
setAtSymbolPosition(-1);
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
// Don't interfere with existing ESC behavior if in command panel
|
|
84
|
-
if (showCommands) {
|
|
85
|
-
setShowCommands(false);
|
|
86
|
-
setCommandSelectedIndex(0);
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
// Handle history navigation
|
|
90
|
-
if (showHistoryMenu) {
|
|
91
|
-
setShowHistoryMenu(false);
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
// Count escape key presses for double-ESC detection
|
|
95
|
-
setEscapeKeyCount(prev => prev + 1);
|
|
96
|
-
// Clear any existing timer
|
|
97
|
-
if (escapeKeyTimer.current) {
|
|
98
|
-
clearTimeout(escapeKeyTimer.current);
|
|
99
|
-
}
|
|
100
|
-
// Set timer to reset count after 500ms
|
|
101
|
-
escapeKeyTimer.current = setTimeout(() => {
|
|
102
|
-
setEscapeKeyCount(0);
|
|
103
|
-
}, 500);
|
|
104
|
-
// Check for double escape
|
|
105
|
-
if (escapeKeyCount >= 1) {
|
|
106
|
-
// This will be 2 after increment
|
|
107
|
-
const userMessages = getUserMessages();
|
|
108
|
-
if (userMessages.length > 0) {
|
|
109
|
-
setShowHistoryMenu(true);
|
|
110
|
-
setHistorySelectedIndex(0); // Reset selection to first item
|
|
111
|
-
setEscapeKeyCount(0);
|
|
112
|
-
if (escapeKeyTimer.current) {
|
|
113
|
-
clearTimeout(escapeKeyTimer.current);
|
|
114
|
-
escapeKeyTimer.current = null;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
// Handle todo picker navigation
|
|
121
|
-
if (showTodoPicker) {
|
|
122
|
-
// Up arrow in todo picker
|
|
123
|
-
if (key.upArrow) {
|
|
124
|
-
setTodoSelectedIndex(prev => Math.max(0, prev - 1));
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
// Down arrow in todo picker
|
|
128
|
-
if (key.downArrow) {
|
|
129
|
-
const maxIndex = Math.max(0, todos.length - 1);
|
|
130
|
-
setTodoSelectedIndex(prev => Math.min(maxIndex, prev + 1));
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
// Space - toggle selection
|
|
134
|
-
if (input === ' ') {
|
|
135
|
-
toggleTodoSelection();
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
// Enter - confirm selection
|
|
139
|
-
if (key.return) {
|
|
140
|
-
confirmTodoSelection();
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
// Backspace - remove last character from search
|
|
144
|
-
if (key.backspace || key.delete) {
|
|
145
|
-
if (todoSearchQuery.length > 0) {
|
|
146
|
-
setTodoSearchQuery(todoSearchQuery.slice(0, -1));
|
|
147
|
-
setTodoSelectedIndex(0); // Reset to first item
|
|
148
|
-
triggerUpdate();
|
|
149
|
-
}
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
// Type to search - alphanumeric and common characters
|
|
153
|
-
if (input &&
|
|
154
|
-
input.length === 1 &&
|
|
155
|
-
!key.ctrl &&
|
|
156
|
-
!key.meta &&
|
|
157
|
-
input !== '\x1b' // Ignore escape sequences
|
|
158
|
-
) {
|
|
159
|
-
setTodoSearchQuery(todoSearchQuery + input);
|
|
160
|
-
setTodoSelectedIndex(0); // Reset to first item
|
|
161
|
-
triggerUpdate();
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
// For any other key in todo picker, just return to prevent interference
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
// Handle agent picker navigation
|
|
168
|
-
if (showAgentPicker) {
|
|
169
|
-
const filteredAgents = getFilteredAgents();
|
|
170
|
-
// Up arrow in agent picker
|
|
171
|
-
if (key.upArrow) {
|
|
172
|
-
setAgentSelectedIndex(prev => Math.max(0, prev - 1));
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
// Down arrow in agent picker
|
|
176
|
-
if (key.downArrow) {
|
|
177
|
-
const maxIndex = Math.max(0, filteredAgents.length - 1);
|
|
178
|
-
setAgentSelectedIndex(prev => Math.min(maxIndex, prev + 1));
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
// Enter - select agent
|
|
182
|
-
if (key.return) {
|
|
183
|
-
if (filteredAgents.length > 0 && agentSelectedIndex < filteredAgents.length) {
|
|
184
|
-
const selectedAgent = filteredAgents[agentSelectedIndex];
|
|
185
|
-
if (selectedAgent) {
|
|
186
|
-
handleAgentSelect(selectedAgent);
|
|
187
|
-
setShowAgentPicker(false);
|
|
188
|
-
setAgentSelectedIndex(0);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
// Allow typing to filter - don't block regular input
|
|
194
|
-
// The input will be processed below and updateAgentPickerState will be called
|
|
195
|
-
// which will update the filter automatically
|
|
196
|
-
}
|
|
197
|
-
// Handle history menu navigation
|
|
198
|
-
if (showHistoryMenu) {
|
|
199
|
-
const userMessages = getUserMessages();
|
|
200
|
-
// Up arrow in history menu
|
|
201
|
-
if (key.upArrow) {
|
|
202
|
-
setHistorySelectedIndex(prev => Math.max(0, prev - 1));
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
// Down arrow in history menu
|
|
206
|
-
if (key.downArrow) {
|
|
207
|
-
const maxIndex = Math.max(0, userMessages.length - 1);
|
|
208
|
-
setHistorySelectedIndex(prev => Math.min(maxIndex, prev + 1));
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
// Enter - select history item
|
|
212
|
-
if (key.return) {
|
|
213
|
-
if (userMessages.length > 0 &&
|
|
214
|
-
historySelectedIndex < userMessages.length) {
|
|
215
|
-
const selectedMessage = userMessages[historySelectedIndex];
|
|
216
|
-
if (selectedMessage) {
|
|
217
|
-
handleHistorySelect(selectedMessage.value);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
// For any other key in history menu, just return to prevent interference
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
// Ctrl+L - Delete from cursor to beginning
|
|
226
|
-
if (key.ctrl && input === 'l') {
|
|
227
|
-
const displayText = buffer.text;
|
|
228
|
-
const cursorPos = buffer.getCursorPosition();
|
|
229
|
-
const afterCursor = displayText.slice(cursorPos);
|
|
230
|
-
buffer.setText(afterCursor);
|
|
231
|
-
forceStateUpdate();
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
// Ctrl+R - Delete from cursor to end
|
|
235
|
-
if (key.ctrl && input === 'r') {
|
|
236
|
-
const displayText = buffer.text;
|
|
237
|
-
const cursorPos = buffer.getCursorPosition();
|
|
238
|
-
const beforeCursor = displayText.slice(0, cursorPos);
|
|
239
|
-
buffer.setText(beforeCursor);
|
|
240
|
-
forceStateUpdate();
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
// Windows: Alt+V, macOS: Ctrl+V - Paste from clipboard (including images)
|
|
244
|
-
const isPasteShortcut = process.platform === 'darwin'
|
|
245
|
-
? key.ctrl && input === 'v'
|
|
246
|
-
: key.meta && input === 'v';
|
|
247
|
-
if (isPasteShortcut) {
|
|
248
|
-
pasteFromClipboard();
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
// Backspace
|
|
252
|
-
if (key.backspace || key.delete) {
|
|
253
|
-
buffer.backspace();
|
|
254
|
-
forceStateUpdate();
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
// Handle file picker navigation
|
|
258
|
-
if (showFilePicker) {
|
|
259
|
-
// Up arrow in file picker
|
|
260
|
-
if (key.upArrow) {
|
|
261
|
-
setFileSelectedIndex(prev => Math.max(0, prev - 1));
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
// Down arrow in file picker
|
|
265
|
-
if (key.downArrow) {
|
|
266
|
-
const maxIndex = Math.max(0, filteredFileCount - 1);
|
|
267
|
-
setFileSelectedIndex(prev => Math.min(maxIndex, prev + 1));
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
// Tab or Enter - select file
|
|
271
|
-
if (key.tab || key.return) {
|
|
272
|
-
if (filteredFileCount > 0 && fileSelectedIndex < filteredFileCount) {
|
|
273
|
-
const selectedFile = fileListRef.current?.getSelectedFile();
|
|
274
|
-
if (selectedFile) {
|
|
275
|
-
handleFileSelect(selectedFile);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
// Handle command panel navigation
|
|
282
|
-
if (showCommands) {
|
|
283
|
-
const filteredCommands = getFilteredCommands();
|
|
284
|
-
// Up arrow in command panel
|
|
285
|
-
if (key.upArrow) {
|
|
286
|
-
setCommandSelectedIndex(prev => Math.max(0, prev - 1));
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
// Down arrow in command panel
|
|
290
|
-
if (key.downArrow) {
|
|
291
|
-
const maxIndex = Math.max(0, filteredCommands.length - 1);
|
|
292
|
-
setCommandSelectedIndex(prev => Math.min(maxIndex, prev + 1));
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
// Enter - select command
|
|
296
|
-
if (key.return) {
|
|
297
|
-
if (filteredCommands.length > 0 &&
|
|
298
|
-
commandSelectedIndex < filteredCommands.length) {
|
|
299
|
-
const selectedCommand = filteredCommands[commandSelectedIndex];
|
|
300
|
-
if (selectedCommand) {
|
|
301
|
-
// Special handling for todo- command
|
|
302
|
-
if (selectedCommand.name === 'todo-') {
|
|
303
|
-
buffer.setText('');
|
|
304
|
-
setShowCommands(false);
|
|
305
|
-
setCommandSelectedIndex(0);
|
|
306
|
-
setShowTodoPicker(true);
|
|
307
|
-
triggerUpdate();
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
// Special handling for agent- command
|
|
311
|
-
if (selectedCommand.name === 'agent-') {
|
|
312
|
-
buffer.setText('');
|
|
313
|
-
setShowCommands(false);
|
|
314
|
-
setCommandSelectedIndex(0);
|
|
315
|
-
setShowAgentPicker(true);
|
|
316
|
-
triggerUpdate();
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
// Execute command instead of inserting text
|
|
320
|
-
executeCommand(selectedCommand.name).then(result => {
|
|
321
|
-
if (onCommand) {
|
|
322
|
-
onCommand(selectedCommand.name, result);
|
|
323
|
-
}
|
|
324
|
-
});
|
|
325
|
-
buffer.setText('');
|
|
326
|
-
setShowCommands(false);
|
|
327
|
-
setCommandSelectedIndex(0);
|
|
328
|
-
triggerUpdate();
|
|
329
|
-
return;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
// If no commands available, fall through to normal Enter handling
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
// Enter - submit message
|
|
336
|
-
if (key.return) {
|
|
337
|
-
// Reset history navigation on submit
|
|
338
|
-
if (currentHistoryIndex !== -1) {
|
|
339
|
-
resetHistoryNavigation();
|
|
340
|
-
}
|
|
341
|
-
const message = buffer.getFullText().trim();
|
|
342
|
-
if (message) {
|
|
343
|
-
// Check if message is a command with arguments (e.g., /review [note])
|
|
344
|
-
if (message.startsWith('/')) {
|
|
345
|
-
const commandMatch = message.match(/^\/(\w+)(?:\s+(.+))?$/);
|
|
346
|
-
if (commandMatch && commandMatch[1]) {
|
|
347
|
-
const commandName = commandMatch[1];
|
|
348
|
-
const commandArgs = commandMatch[2];
|
|
349
|
-
// Execute command with arguments
|
|
350
|
-
executeCommand(commandName, commandArgs).then(result => {
|
|
351
|
-
if (onCommand) {
|
|
352
|
-
onCommand(commandName, result);
|
|
353
|
-
}
|
|
354
|
-
});
|
|
355
|
-
buffer.setText('');
|
|
356
|
-
setShowCommands(false);
|
|
357
|
-
setCommandSelectedIndex(0);
|
|
358
|
-
triggerUpdate();
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
// Get images data, but only include images whose placeholders still exist
|
|
363
|
-
const currentText = buffer.text; // Use internal text (includes placeholders)
|
|
364
|
-
const allImages = buffer.getImages();
|
|
365
|
-
const validImages = allImages
|
|
366
|
-
.filter(img => currentText.includes(img.placeholder))
|
|
367
|
-
.map(img => ({
|
|
368
|
-
data: img.data,
|
|
369
|
-
mimeType: img.mimeType,
|
|
370
|
-
}));
|
|
371
|
-
buffer.setText('');
|
|
372
|
-
forceUpdate({});
|
|
373
|
-
// Save to persistent history
|
|
374
|
-
saveToHistory(message);
|
|
375
|
-
onSubmit(message, validImages.length > 0 ? validImages : undefined);
|
|
376
|
-
}
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
// Arrow keys for cursor movement
|
|
380
|
-
if (key.leftArrow) {
|
|
381
|
-
// If there's accumulated input, process it immediately before moving cursor
|
|
382
|
-
if (inputBuffer.current) {
|
|
383
|
-
if (inputTimer.current) {
|
|
384
|
-
clearTimeout(inputTimer.current);
|
|
385
|
-
inputTimer.current = null;
|
|
386
|
-
}
|
|
387
|
-
const accumulated = inputBuffer.current;
|
|
388
|
-
const savedCursorPosition = inputStartCursorPos.current;
|
|
389
|
-
inputBuffer.current = '';
|
|
390
|
-
isPasting.current = false;
|
|
391
|
-
// Insert at saved position
|
|
392
|
-
buffer.setCursorPosition(savedCursorPosition);
|
|
393
|
-
buffer.insert(accumulated);
|
|
394
|
-
// Reset inputStartCursorPos after processing
|
|
395
|
-
inputStartCursorPos.current = buffer.getCursorPosition();
|
|
396
|
-
}
|
|
397
|
-
buffer.moveLeft();
|
|
398
|
-
const text = buffer.getFullText();
|
|
399
|
-
const cursorPos = buffer.getCursorPosition();
|
|
400
|
-
updateFilePickerState(text, cursorPos);
|
|
401
|
-
updateAgentPickerState(text, cursorPos);
|
|
402
|
-
triggerUpdate();
|
|
403
|
-
return;
|
|
404
|
-
}
|
|
405
|
-
if (key.rightArrow) {
|
|
406
|
-
// If there's accumulated input, process it immediately before moving cursor
|
|
407
|
-
if (inputBuffer.current) {
|
|
408
|
-
if (inputTimer.current) {
|
|
409
|
-
clearTimeout(inputTimer.current);
|
|
410
|
-
inputTimer.current = null;
|
|
411
|
-
}
|
|
412
|
-
const accumulated = inputBuffer.current;
|
|
413
|
-
const savedCursorPosition = inputStartCursorPos.current;
|
|
414
|
-
inputBuffer.current = '';
|
|
415
|
-
isPasting.current = false;
|
|
416
|
-
// Insert at saved position
|
|
417
|
-
buffer.setCursorPosition(savedCursorPosition);
|
|
418
|
-
buffer.insert(accumulated);
|
|
419
|
-
// Reset inputStartCursorPos after processing
|
|
420
|
-
inputStartCursorPos.current = buffer.getCursorPosition();
|
|
421
|
-
}
|
|
422
|
-
buffer.moveRight();
|
|
423
|
-
const text = buffer.getFullText();
|
|
424
|
-
const cursorPos = buffer.getCursorPosition();
|
|
425
|
-
updateFilePickerState(text, cursorPos);
|
|
426
|
-
updateAgentPickerState(text, cursorPos);
|
|
427
|
-
triggerUpdate();
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
if (key.upArrow && !showCommands && !showFilePicker) {
|
|
431
|
-
// If there's accumulated input, process it immediately before moving cursor
|
|
432
|
-
if (inputBuffer.current) {
|
|
433
|
-
if (inputTimer.current) {
|
|
434
|
-
clearTimeout(inputTimer.current);
|
|
435
|
-
inputTimer.current = null;
|
|
436
|
-
}
|
|
437
|
-
const accumulated = inputBuffer.current;
|
|
438
|
-
const savedCursorPosition = inputStartCursorPos.current;
|
|
439
|
-
inputBuffer.current = '';
|
|
440
|
-
isPasting.current = false;
|
|
441
|
-
// Insert at saved position
|
|
442
|
-
buffer.setCursorPosition(savedCursorPosition);
|
|
443
|
-
buffer.insert(accumulated);
|
|
444
|
-
// Reset inputStartCursorPos after processing
|
|
445
|
-
inputStartCursorPos.current = buffer.getCursorPosition();
|
|
446
|
-
}
|
|
447
|
-
const text = buffer.getFullText();
|
|
448
|
-
const cursorPos = buffer.getCursorPosition();
|
|
449
|
-
const isEmpty = text.trim() === '';
|
|
450
|
-
const isAtStart = cursorPos === 0;
|
|
451
|
-
const hasNewline = text.includes('\n');
|
|
452
|
-
// Terminal-style history navigation:
|
|
453
|
-
// 1. Empty input box -> navigate history
|
|
454
|
-
// 2. Cursor at start of single line -> navigate history
|
|
455
|
-
// 3. Otherwise -> normal cursor movement
|
|
456
|
-
if (isEmpty || (!hasNewline && isAtStart)) {
|
|
457
|
-
const navigated = navigateHistoryUp();
|
|
458
|
-
if (navigated) {
|
|
459
|
-
updateFilePickerState(buffer.getFullText(), buffer.getCursorPosition());
|
|
460
|
-
updateAgentPickerState(buffer.getFullText(), buffer.getCursorPosition());
|
|
461
|
-
triggerUpdate();
|
|
462
|
-
return;
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
// Normal cursor movement
|
|
466
|
-
buffer.moveUp();
|
|
467
|
-
updateFilePickerState(buffer.getFullText(), buffer.getCursorPosition());
|
|
468
|
-
updateAgentPickerState(buffer.getFullText(), buffer.getCursorPosition());
|
|
469
|
-
triggerUpdate();
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
if (key.downArrow && !showCommands && !showFilePicker) {
|
|
473
|
-
// If there's accumulated input, process it immediately before moving cursor
|
|
474
|
-
if (inputBuffer.current) {
|
|
475
|
-
if (inputTimer.current) {
|
|
476
|
-
clearTimeout(inputTimer.current);
|
|
477
|
-
inputTimer.current = null;
|
|
478
|
-
}
|
|
479
|
-
const accumulated = inputBuffer.current;
|
|
480
|
-
const savedCursorPosition = inputStartCursorPos.current;
|
|
481
|
-
inputBuffer.current = '';
|
|
482
|
-
isPasting.current = false;
|
|
483
|
-
// Insert at saved position
|
|
484
|
-
buffer.setCursorPosition(savedCursorPosition);
|
|
485
|
-
buffer.insert(accumulated);
|
|
486
|
-
// Reset inputStartCursorPos after processing
|
|
487
|
-
inputStartCursorPos.current = buffer.getCursorPosition();
|
|
488
|
-
}
|
|
489
|
-
const text = buffer.getFullText();
|
|
490
|
-
const cursorPos = buffer.getCursorPosition();
|
|
491
|
-
const isEmpty = text.trim() === '';
|
|
492
|
-
const isAtEnd = cursorPos === text.length;
|
|
493
|
-
const hasNewline = text.includes('\n');
|
|
494
|
-
// Terminal-style history navigation:
|
|
495
|
-
// 1. Empty input box -> navigate history (if in history mode)
|
|
496
|
-
// 2. Cursor at end of single line -> navigate history (if in history mode)
|
|
497
|
-
// 3. Otherwise -> normal cursor movement
|
|
498
|
-
if ((isEmpty || (!hasNewline && isAtEnd)) && currentHistoryIndex !== -1) {
|
|
499
|
-
const navigated = navigateHistoryDown();
|
|
500
|
-
if (navigated) {
|
|
501
|
-
updateFilePickerState(buffer.getFullText(), buffer.getCursorPosition());
|
|
502
|
-
updateAgentPickerState(buffer.getFullText(), buffer.getCursorPosition());
|
|
503
|
-
triggerUpdate();
|
|
504
|
-
return;
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
// Normal cursor movement
|
|
508
|
-
buffer.moveDown();
|
|
509
|
-
updateFilePickerState(buffer.getFullText(), buffer.getCursorPosition());
|
|
510
|
-
updateAgentPickerState(buffer.getFullText(), buffer.getCursorPosition());
|
|
511
|
-
triggerUpdate();
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
|
-
// Regular character input
|
|
515
|
-
if (input && !key.ctrl && !key.meta && !key.escape) {
|
|
516
|
-
// Reset history navigation when user starts typing
|
|
517
|
-
if (currentHistoryIndex !== -1) {
|
|
518
|
-
resetHistoryNavigation();
|
|
519
|
-
}
|
|
520
|
-
// Ensure focus is active when user is typing (handles delayed focus events)
|
|
521
|
-
// This is especially important for drag-and-drop operations where focus
|
|
522
|
-
// events may arrive out of order or be filtered by sanitizeInput
|
|
523
|
-
ensureFocus();
|
|
524
|
-
// Detect if this is a single character input (normal typing) or multi-character (paste)
|
|
525
|
-
const isSingleCharInput = input.length === 1;
|
|
526
|
-
if (isSingleCharInput) {
|
|
527
|
-
// For single character input (normal typing), insert immediately
|
|
528
|
-
// This prevents the "disappearing text" issue at line start
|
|
529
|
-
buffer.insert(input);
|
|
530
|
-
const text = buffer.getFullText();
|
|
531
|
-
const cursorPos = buffer.getCursorPosition();
|
|
532
|
-
updateCommandPanelState(text);
|
|
533
|
-
updateFilePickerState(text, cursorPos);
|
|
534
|
-
updateAgentPickerState(text, cursorPos);
|
|
535
|
-
triggerUpdate();
|
|
536
|
-
}
|
|
537
|
-
else {
|
|
538
|
-
// For multi-character input (paste), use the buffering mechanism
|
|
539
|
-
// Save cursor position when starting new input accumulation
|
|
540
|
-
const isStartingNewInput = inputBuffer.current === '';
|
|
541
|
-
if (isStartingNewInput) {
|
|
542
|
-
inputStartCursorPos.current = buffer.getCursorPosition();
|
|
543
|
-
}
|
|
544
|
-
// Accumulate input for paste detection
|
|
545
|
-
inputBuffer.current += input;
|
|
546
|
-
// Clear existing timer
|
|
547
|
-
if (inputTimer.current) {
|
|
548
|
-
clearTimeout(inputTimer.current);
|
|
549
|
-
}
|
|
550
|
-
// Detect large paste: if accumulated buffer is getting large, extend timeout
|
|
551
|
-
// This prevents splitting large pastes into multiple insert() calls
|
|
552
|
-
const currentLength = inputBuffer.current.length;
|
|
553
|
-
const timeoutDelay = currentLength > 200 ? 150 : 10;
|
|
554
|
-
// Show pasting indicator for large text (>300 chars)
|
|
555
|
-
// Simple static message - no progress animation
|
|
556
|
-
if (currentLength > 300 && !isPasting.current) {
|
|
557
|
-
isPasting.current = true;
|
|
558
|
-
buffer.insertPastingIndicator();
|
|
559
|
-
// Trigger UI update to show the indicator
|
|
560
|
-
const text = buffer.getFullText();
|
|
561
|
-
const cursorPos = buffer.getCursorPosition();
|
|
562
|
-
updateCommandPanelState(text);
|
|
563
|
-
updateFilePickerState(text, cursorPos);
|
|
564
|
-
updateAgentPickerState(text, cursorPos);
|
|
565
|
-
triggerUpdate();
|
|
566
|
-
}
|
|
567
|
-
// Set timer to process accumulated input
|
|
568
|
-
inputTimer.current = setTimeout(() => {
|
|
569
|
-
const accumulated = inputBuffer.current;
|
|
570
|
-
const savedCursorPosition = inputStartCursorPos.current;
|
|
571
|
-
const wasPasting = isPasting.current; // Save pasting state before clearing
|
|
572
|
-
inputBuffer.current = '';
|
|
573
|
-
isPasting.current = false; // Reset pasting state
|
|
574
|
-
// If we accumulated input, insert it at the saved cursor position
|
|
575
|
-
// The insert() method will automatically remove the pasting indicator
|
|
576
|
-
if (accumulated) {
|
|
577
|
-
// Get current cursor position to calculate if user moved cursor during input
|
|
578
|
-
const currentCursor = buffer.getCursorPosition();
|
|
579
|
-
// If cursor hasn't moved from where we started (or only moved due to pasting indicator),
|
|
580
|
-
// insert at the saved position
|
|
581
|
-
// Otherwise, insert at current position (user deliberately moved cursor)
|
|
582
|
-
// Note: wasPasting check uses saved state, not current isPasting.current
|
|
583
|
-
if (currentCursor === savedCursorPosition ||
|
|
584
|
-
(wasPasting && currentCursor > savedCursorPosition)) {
|
|
585
|
-
// Temporarily set cursor to saved position for insertion
|
|
586
|
-
// This is safe because we're in a timeout, not during active cursor movement
|
|
587
|
-
buffer.setCursorPosition(savedCursorPosition);
|
|
588
|
-
buffer.insert(accumulated);
|
|
589
|
-
// No need to restore cursor - insert() moves it naturally
|
|
590
|
-
}
|
|
591
|
-
else {
|
|
592
|
-
// User moved cursor during input, insert at current position
|
|
593
|
-
buffer.insert(accumulated);
|
|
594
|
-
}
|
|
595
|
-
// Reset inputStartCursorPos after processing to prevent stale position
|
|
596
|
-
inputStartCursorPos.current = buffer.getCursorPosition();
|
|
597
|
-
const text = buffer.getFullText();
|
|
598
|
-
const cursorPos = buffer.getCursorPosition();
|
|
599
|
-
updateCommandPanelState(text);
|
|
600
|
-
updateFilePickerState(text, cursorPos);
|
|
601
|
-
updateAgentPickerState(text, cursorPos);
|
|
602
|
-
triggerUpdate();
|
|
603
|
-
}
|
|
604
|
-
}, timeoutDelay); // Extended delay for large pastes to ensure complete accumulation
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
});
|
|
608
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { Message } from '../ui/components/MessageList.js';
|
|
2
|
-
/**
|
|
3
|
-
* Hook for managing session list and session selection
|
|
4
|
-
*/
|
|
5
|
-
export declare function useSessionManagement(setMessages: React.Dispatch<React.SetStateAction<Message[]>>, setPendingMessages: React.Dispatch<React.SetStateAction<string[]>>, setIsStreaming: React.Dispatch<React.SetStateAction<boolean>>, setRemountKey: React.Dispatch<React.SetStateAction<number>>, initializeFromSession: (messages: any[]) => void): {
|
|
6
|
-
showSessionList: boolean;
|
|
7
|
-
setShowSessionList: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
8
|
-
handleSessionSelect: (sessionId: string) => Promise<void>;
|
|
9
|
-
handleBackFromSessionList: () => void;
|
|
10
|
-
};
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
|
-
import { sessionManager } from '../utils/sessionManager.js';
|
|
3
|
-
import { convertSessionMessagesToUI } from '../utils/sessionConverter.js';
|
|
4
|
-
/**
|
|
5
|
-
* Hook for managing session list and session selection
|
|
6
|
-
*/
|
|
7
|
-
export function useSessionManagement(setMessages, setPendingMessages, setIsStreaming, setRemountKey, initializeFromSession) {
|
|
8
|
-
const [showSessionList, setShowSessionList] = useState(false);
|
|
9
|
-
/**
|
|
10
|
-
* Handle session selection from the session list
|
|
11
|
-
*/
|
|
12
|
-
const handleSessionSelect = async (sessionId) => {
|
|
13
|
-
try {
|
|
14
|
-
const session = await sessionManager.loadSession(sessionId);
|
|
15
|
-
if (session) {
|
|
16
|
-
// Convert API format messages to UI format
|
|
17
|
-
const uiMessages = convertSessionMessagesToUI(session.messages);
|
|
18
|
-
setMessages(uiMessages);
|
|
19
|
-
setPendingMessages([]);
|
|
20
|
-
setIsStreaming(false);
|
|
21
|
-
setShowSessionList(false);
|
|
22
|
-
setRemountKey(prev => prev + 1);
|
|
23
|
-
// Initialize session save hook with loaded API messages
|
|
24
|
-
initializeFromSession(session.messages);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
catch (error) {
|
|
28
|
-
console.error('Failed to load session:', error);
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
/**
|
|
32
|
-
* Handle back action from session list
|
|
33
|
-
*/
|
|
34
|
-
const handleBackFromSessionList = () => {
|
|
35
|
-
setShowSessionList(false);
|
|
36
|
-
};
|
|
37
|
-
return {
|
|
38
|
-
showSessionList,
|
|
39
|
-
setShowSessionList,
|
|
40
|
-
handleSessionSelect,
|
|
41
|
-
handleBackFromSessionList
|
|
42
|
-
};
|
|
43
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { type ChatMessage as SessionChatMessage } from '../utils/sessionManager.js';
|
|
2
|
-
import type { ChatMessage as APIChatMessage } from '../api/chat.js';
|
|
3
|
-
export declare function useSessionSave(): {
|
|
4
|
-
saveMessage: (message: APIChatMessage) => Promise<void>;
|
|
5
|
-
saveMessages: (messages: APIChatMessage[]) => Promise<void>;
|
|
6
|
-
clearSavedMessages: () => void;
|
|
7
|
-
initializeFromSession: (messages: SessionChatMessage[]) => void;
|
|
8
|
-
};
|