snow-ai 0.4.16 → 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 -384
- 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 -1519
- 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,178 +0,0 @@
|
|
|
1
|
-
import React, { useMemo } from 'react';
|
|
2
|
-
import { Box, Text } from 'ink';
|
|
3
|
-
import * as Diff from 'diff';
|
|
4
|
-
import { useTheme } from '../contexts/ThemeContext.js';
|
|
5
|
-
// Helper function to strip line numbers from content (format: "123→content")
|
|
6
|
-
function stripLineNumbers(content) {
|
|
7
|
-
return content
|
|
8
|
-
.split('\n')
|
|
9
|
-
.map(line => {
|
|
10
|
-
// Match pattern: digits + → + content
|
|
11
|
-
const match = line.match(/^\s*\d+→(.*)$/);
|
|
12
|
-
return match ? match[1] : line;
|
|
13
|
-
})
|
|
14
|
-
.join('\n');
|
|
15
|
-
}
|
|
16
|
-
export default function DiffViewer({ oldContent = '', newContent, filename, completeOldContent, completeNewContent, startLineNumber = 1, }) {
|
|
17
|
-
const { theme } = useTheme();
|
|
18
|
-
// If complete file contents are provided, use them for intelligent diff
|
|
19
|
-
const useCompleteContent = completeOldContent && completeNewContent;
|
|
20
|
-
const diffOldContent = useCompleteContent
|
|
21
|
-
? completeOldContent
|
|
22
|
-
: stripLineNumbers(oldContent);
|
|
23
|
-
const diffNewContent = useCompleteContent
|
|
24
|
-
? completeNewContent
|
|
25
|
-
: stripLineNumbers(newContent);
|
|
26
|
-
// If no old content, show as new file creation
|
|
27
|
-
const isNewFile = !diffOldContent || diffOldContent.trim() === '';
|
|
28
|
-
// Memoize new file rendering to avoid re-splitting lines on every render
|
|
29
|
-
const newFileContent = useMemo(() => {
|
|
30
|
-
if (!isNewFile)
|
|
31
|
-
return null;
|
|
32
|
-
const allLines = diffNewContent.split('\n');
|
|
33
|
-
return (React.createElement(Box, { flexDirection: "column" },
|
|
34
|
-
React.createElement(Box, { marginBottom: 1 },
|
|
35
|
-
React.createElement(Text, { bold: true, color: "green" }, "[New File]"),
|
|
36
|
-
filename && React.createElement(Text, { color: "cyan" },
|
|
37
|
-
" ",
|
|
38
|
-
filename)),
|
|
39
|
-
React.createElement(Box, { flexDirection: "column" }, allLines.map((line, index) => (React.createElement(Text, { key: index, color: "white", backgroundColor: theme.colors.diffAdded },
|
|
40
|
-
"+ ",
|
|
41
|
-
line))))));
|
|
42
|
-
}, [isNewFile, diffNewContent, filename, theme.colors.text, theme.colors.diffAdded]);
|
|
43
|
-
if (isNewFile) {
|
|
44
|
-
return newFileContent;
|
|
45
|
-
}
|
|
46
|
-
// Memoize expensive diff calculation - only recompute when content changes
|
|
47
|
-
const hunks = useMemo(() => {
|
|
48
|
-
// Generate line-by-line diff
|
|
49
|
-
const diffResult = Diff.diffLines(diffOldContent, diffNewContent);
|
|
50
|
-
const allChanges = [];
|
|
51
|
-
let oldLineNum = startLineNumber;
|
|
52
|
-
let newLineNum = startLineNumber;
|
|
53
|
-
diffResult.forEach(part => {
|
|
54
|
-
const lines = part.value.replace(/\n$/, '').split('\n');
|
|
55
|
-
lines.forEach(line => {
|
|
56
|
-
if (part.added) {
|
|
57
|
-
allChanges.push({
|
|
58
|
-
type: 'added',
|
|
59
|
-
content: line,
|
|
60
|
-
oldLineNum: null,
|
|
61
|
-
newLineNum: newLineNum++,
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
else if (part.removed) {
|
|
65
|
-
allChanges.push({
|
|
66
|
-
type: 'removed',
|
|
67
|
-
content: line,
|
|
68
|
-
oldLineNum: oldLineNum++,
|
|
69
|
-
newLineNum: null,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
allChanges.push({
|
|
74
|
-
type: 'unchanged',
|
|
75
|
-
content: line,
|
|
76
|
-
oldLineNum: oldLineNum++,
|
|
77
|
-
newLineNum: newLineNum++,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
// Find diff hunks (groups of changes with context)
|
|
83
|
-
const computedHunks = [];
|
|
84
|
-
const contextLines = 3; // Number of context lines before and after changes
|
|
85
|
-
for (let i = 0; i < allChanges.length; i++) {
|
|
86
|
-
const change = allChanges[i];
|
|
87
|
-
if (change?.type !== 'unchanged') {
|
|
88
|
-
// Found a change, create a hunk
|
|
89
|
-
const hunkStart = Math.max(0, i - contextLines);
|
|
90
|
-
let hunkEnd = i;
|
|
91
|
-
// Extend the hunk to include all consecutive changes
|
|
92
|
-
while (hunkEnd < allChanges.length - 1) {
|
|
93
|
-
const nextChange = allChanges[hunkEnd + 1];
|
|
94
|
-
if (!nextChange)
|
|
95
|
-
break;
|
|
96
|
-
// If next line is a change, extend the hunk
|
|
97
|
-
if (nextChange.type !== 'unchanged') {
|
|
98
|
-
hunkEnd++;
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
// If there are more changes within context distance, extend the hunk
|
|
102
|
-
let hasMoreChanges = false;
|
|
103
|
-
for (let j = hunkEnd + 1; j < Math.min(allChanges.length, hunkEnd + 1 + contextLines * 2); j++) {
|
|
104
|
-
if (allChanges[j]?.type !== 'unchanged') {
|
|
105
|
-
hasMoreChanges = true;
|
|
106
|
-
break;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
if (hasMoreChanges) {
|
|
110
|
-
hunkEnd++;
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
// Add context lines after the hunk
|
|
117
|
-
hunkEnd = Math.min(allChanges.length - 1, hunkEnd + contextLines);
|
|
118
|
-
// Extract the hunk
|
|
119
|
-
const hunkChanges = allChanges.slice(hunkStart, hunkEnd + 1);
|
|
120
|
-
const firstChange = hunkChanges[0];
|
|
121
|
-
const lastChange = hunkChanges[hunkChanges.length - 1];
|
|
122
|
-
if (firstChange && lastChange) {
|
|
123
|
-
computedHunks.push({
|
|
124
|
-
startLine: firstChange.oldLineNum || firstChange.newLineNum || 1,
|
|
125
|
-
endLine: lastChange.oldLineNum || lastChange.newLineNum || 1,
|
|
126
|
-
changes: hunkChanges,
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
// Skip to the end of this hunk
|
|
130
|
-
i = hunkEnd;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return computedHunks;
|
|
134
|
-
}, [diffOldContent, diffNewContent, startLineNumber]);
|
|
135
|
-
return (React.createElement(Box, { flexDirection: "column" },
|
|
136
|
-
React.createElement(Box, { marginBottom: 1 },
|
|
137
|
-
React.createElement(Text, { bold: true, color: "yellow" }, "[File Modified]"),
|
|
138
|
-
filename && React.createElement(Text, { color: "cyan" },
|
|
139
|
-
" ",
|
|
140
|
-
filename)),
|
|
141
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
142
|
-
hunks.map((hunk, hunkIndex) => (React.createElement(Box, { key: hunkIndex, flexDirection: "column", marginBottom: 1 },
|
|
143
|
-
React.createElement(Text, { color: "cyan", dimColor: true },
|
|
144
|
-
"@@ Lines ",
|
|
145
|
-
hunk.startLine,
|
|
146
|
-
"-",
|
|
147
|
-
hunk.endLine,
|
|
148
|
-
" @@"),
|
|
149
|
-
hunk.changes.map((change, changeIndex) => {
|
|
150
|
-
// Calculate line number to display
|
|
151
|
-
const lineNum = change.type === 'added' ? change.newLineNum : change.oldLineNum;
|
|
152
|
-
const lineNumStr = lineNum
|
|
153
|
-
? String(lineNum).padStart(4, ' ')
|
|
154
|
-
: ' ';
|
|
155
|
-
if (change.type === 'added') {
|
|
156
|
-
return (React.createElement(Text, { key: changeIndex, color: "white", backgroundColor: theme.colors.diffAdded },
|
|
157
|
-
lineNumStr,
|
|
158
|
-
" + ",
|
|
159
|
-
change.content));
|
|
160
|
-
}
|
|
161
|
-
if (change.type === 'removed') {
|
|
162
|
-
return (React.createElement(Text, { key: changeIndex, color: "white", backgroundColor: theme.colors.diffRemoved },
|
|
163
|
-
lineNumStr,
|
|
164
|
-
" - ",
|
|
165
|
-
change.content));
|
|
166
|
-
}
|
|
167
|
-
// Unchanged lines (context)
|
|
168
|
-
return (React.createElement(Text, { key: changeIndex, dimColor: true },
|
|
169
|
-
lineNumStr,
|
|
170
|
-
" ",
|
|
171
|
-
change.content));
|
|
172
|
-
})))),
|
|
173
|
-
hunks.length > 1 && (React.createElement(Box, { marginTop: 1 },
|
|
174
|
-
React.createElement(Text, { color: "gray", dimColor: true },
|
|
175
|
-
"Total: ",
|
|
176
|
-
hunks.length,
|
|
177
|
-
" change region(s)"))))));
|
|
178
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
type Props = {
|
|
3
|
-
query: string;
|
|
4
|
-
selectedIndex: number;
|
|
5
|
-
visible: boolean;
|
|
6
|
-
maxItems?: number;
|
|
7
|
-
rootPath?: string;
|
|
8
|
-
onFilteredCountChange?: (count: number) => void;
|
|
9
|
-
searchMode?: 'file' | 'content';
|
|
10
|
-
};
|
|
11
|
-
export type FileListRef = {
|
|
12
|
-
getSelectedFile: () => string | null;
|
|
13
|
-
};
|
|
14
|
-
declare const FileList: React.MemoExoticComponent<React.ForwardRefExoticComponent<Props & React.RefAttributes<FileListRef>>>;
|
|
15
|
-
export default FileList;
|
|
@@ -1,360 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect, useMemo, useCallback, forwardRef, useImperativeHandle, memo, } from 'react';
|
|
2
|
-
import { Box, Text } from 'ink';
|
|
3
|
-
import fs from 'fs';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { useTerminalSize } from '../../hooks/useTerminalSize.js';
|
|
6
|
-
import { useTheme } from '../contexts/ThemeContext.js';
|
|
7
|
-
const FileList = memo(forwardRef(({ query, selectedIndex, visible, maxItems = 10, rootPath = process.cwd(), onFilteredCountChange, searchMode = 'file', }, ref) => {
|
|
8
|
-
const { theme } = useTheme();
|
|
9
|
-
const [files, setFiles] = useState([]);
|
|
10
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
11
|
-
// Get terminal size for dynamic content display
|
|
12
|
-
const { columns: terminalWidth } = useTerminalSize();
|
|
13
|
-
// Fixed maximum display items to prevent rendering issues
|
|
14
|
-
const MAX_DISPLAY_ITEMS = 5;
|
|
15
|
-
const effectiveMaxItems = useMemo(() => {
|
|
16
|
-
return maxItems
|
|
17
|
-
? Math.min(maxItems, MAX_DISPLAY_ITEMS)
|
|
18
|
-
: MAX_DISPLAY_ITEMS;
|
|
19
|
-
}, [maxItems]);
|
|
20
|
-
// Get files from directory - optimized for performance with depth limit
|
|
21
|
-
const loadFiles = useCallback(async () => {
|
|
22
|
-
const MAX_DEPTH = 5; // Limit recursion depth to prevent performance issues
|
|
23
|
-
const MAX_FILES = 1000; // Reduced from 2000 for better performance
|
|
24
|
-
const getFilesRecursively = async (dir, depth = 0) => {
|
|
25
|
-
// Stop recursion if depth limit reached
|
|
26
|
-
if (depth > MAX_DEPTH) {
|
|
27
|
-
return [];
|
|
28
|
-
}
|
|
29
|
-
try {
|
|
30
|
-
const entries = await fs.promises.readdir(dir, {
|
|
31
|
-
withFileTypes: true,
|
|
32
|
-
});
|
|
33
|
-
let result = [];
|
|
34
|
-
// Common ignore patterns for better performance
|
|
35
|
-
const ignorePatterns = [
|
|
36
|
-
'node_modules',
|
|
37
|
-
'dist',
|
|
38
|
-
'build',
|
|
39
|
-
'coverage',
|
|
40
|
-
'.git',
|
|
41
|
-
'.vscode',
|
|
42
|
-
'.idea',
|
|
43
|
-
'out',
|
|
44
|
-
'target',
|
|
45
|
-
'bin',
|
|
46
|
-
'obj',
|
|
47
|
-
'.next',
|
|
48
|
-
'.nuxt',
|
|
49
|
-
'vendor',
|
|
50
|
-
'__pycache__',
|
|
51
|
-
'.pytest_cache',
|
|
52
|
-
'.mypy_cache',
|
|
53
|
-
'venv',
|
|
54
|
-
'.venv',
|
|
55
|
-
'env',
|
|
56
|
-
'.env',
|
|
57
|
-
];
|
|
58
|
-
for (const entry of entries) {
|
|
59
|
-
// Early exit if we've collected enough files
|
|
60
|
-
if (result.length >= MAX_FILES) {
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
// Skip hidden files and ignore patterns
|
|
64
|
-
if (entry.name.startsWith('.') ||
|
|
65
|
-
ignorePatterns.includes(entry.name)) {
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
const fullPath = path.join(dir, entry.name);
|
|
69
|
-
// Skip if file is too large (> 10MB) for performance
|
|
70
|
-
try {
|
|
71
|
-
const stats = await fs.promises.stat(fullPath);
|
|
72
|
-
if (!entry.isDirectory() && stats.size > 10 * 1024 * 1024) {
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
catch {
|
|
77
|
-
continue;
|
|
78
|
-
}
|
|
79
|
-
let relativePath = path.relative(rootPath, fullPath);
|
|
80
|
-
// Ensure relative paths start with ./ for consistency
|
|
81
|
-
if (!relativePath.startsWith('.') &&
|
|
82
|
-
!path.isAbsolute(relativePath)) {
|
|
83
|
-
relativePath = './' + relativePath;
|
|
84
|
-
}
|
|
85
|
-
// Normalize to forward slashes for cross-platform consistency
|
|
86
|
-
relativePath = relativePath.replace(/\\/g, '/');
|
|
87
|
-
result.push({
|
|
88
|
-
name: entry.name,
|
|
89
|
-
path: relativePath,
|
|
90
|
-
isDirectory: entry.isDirectory(),
|
|
91
|
-
});
|
|
92
|
-
// Recursively get files from subdirectories with depth limit
|
|
93
|
-
if (entry.isDirectory() && depth < MAX_DEPTH) {
|
|
94
|
-
const subFiles = await getFilesRecursively(fullPath, depth + 1);
|
|
95
|
-
result = result.concat(subFiles);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return result;
|
|
99
|
-
}
|
|
100
|
-
catch (error) {
|
|
101
|
-
return [];
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
// Batch all state updates together
|
|
105
|
-
setIsLoading(true);
|
|
106
|
-
const fileList = await getFilesRecursively(rootPath);
|
|
107
|
-
setFiles(fileList);
|
|
108
|
-
setIsLoading(false);
|
|
109
|
-
}, [rootPath]);
|
|
110
|
-
// Search file content for content search mode
|
|
111
|
-
const searchFileContent = useCallback(async (query) => {
|
|
112
|
-
if (!query.trim()) {
|
|
113
|
-
return [];
|
|
114
|
-
}
|
|
115
|
-
const results = [];
|
|
116
|
-
const queryLower = query.toLowerCase();
|
|
117
|
-
const maxResults = 100; // Limit results for performance
|
|
118
|
-
// Text file extensions to search
|
|
119
|
-
const textExtensions = new Set([
|
|
120
|
-
'.js',
|
|
121
|
-
'.jsx',
|
|
122
|
-
'.ts',
|
|
123
|
-
'.tsx',
|
|
124
|
-
'.py',
|
|
125
|
-
'.java',
|
|
126
|
-
'.c',
|
|
127
|
-
'.cpp',
|
|
128
|
-
'.h',
|
|
129
|
-
'.hpp',
|
|
130
|
-
'.cs',
|
|
131
|
-
'.go',
|
|
132
|
-
'.rs',
|
|
133
|
-
'.rb',
|
|
134
|
-
'.php',
|
|
135
|
-
'.swift',
|
|
136
|
-
'.kt',
|
|
137
|
-
'.scala',
|
|
138
|
-
'.sh',
|
|
139
|
-
'.bash',
|
|
140
|
-
'.zsh',
|
|
141
|
-
'.fish',
|
|
142
|
-
'.ps1',
|
|
143
|
-
'.html',
|
|
144
|
-
'.css',
|
|
145
|
-
'.scss',
|
|
146
|
-
'.sass',
|
|
147
|
-
'.less',
|
|
148
|
-
'.xml',
|
|
149
|
-
'.json',
|
|
150
|
-
'.yaml',
|
|
151
|
-
'.yml',
|
|
152
|
-
'.toml',
|
|
153
|
-
'.ini',
|
|
154
|
-
'.conf',
|
|
155
|
-
'.config',
|
|
156
|
-
'.txt',
|
|
157
|
-
'.md',
|
|
158
|
-
'.markdown',
|
|
159
|
-
'.rst',
|
|
160
|
-
'.tex',
|
|
161
|
-
'.sql',
|
|
162
|
-
'.graphql',
|
|
163
|
-
'.proto',
|
|
164
|
-
'.vue',
|
|
165
|
-
'.svelte',
|
|
166
|
-
]);
|
|
167
|
-
// Filter to only text files
|
|
168
|
-
const filesToSearch = files.filter(f => {
|
|
169
|
-
if (f.isDirectory)
|
|
170
|
-
return false;
|
|
171
|
-
const ext = path.extname(f.path).toLowerCase();
|
|
172
|
-
return textExtensions.has(ext);
|
|
173
|
-
});
|
|
174
|
-
// Process files in batches to avoid blocking
|
|
175
|
-
const batchSize = 10;
|
|
176
|
-
for (let batchStart = 0; batchStart < filesToSearch.length; batchStart += batchSize) {
|
|
177
|
-
if (results.length >= maxResults) {
|
|
178
|
-
break;
|
|
179
|
-
}
|
|
180
|
-
const batch = filesToSearch.slice(batchStart, batchStart + batchSize);
|
|
181
|
-
// Process batch files concurrently but with limit
|
|
182
|
-
const batchPromises = batch.map(async (file) => {
|
|
183
|
-
const fileResults = [];
|
|
184
|
-
try {
|
|
185
|
-
const fullPath = path.join(rootPath, file.path);
|
|
186
|
-
const content = await fs.promises.readFile(fullPath, 'utf-8');
|
|
187
|
-
const lines = content.split('\n');
|
|
188
|
-
// Search each line for the query
|
|
189
|
-
for (let i = 0; i < lines.length; i++) {
|
|
190
|
-
if (fileResults.length >= 10) {
|
|
191
|
-
// Max 10 results per file
|
|
192
|
-
break;
|
|
193
|
-
}
|
|
194
|
-
const line = lines[i];
|
|
195
|
-
if (line && line.toLowerCase().includes(queryLower)) {
|
|
196
|
-
const maxLineLength = Math.max(40, terminalWidth - 10);
|
|
197
|
-
fileResults.push({
|
|
198
|
-
name: file.name,
|
|
199
|
-
path: file.path,
|
|
200
|
-
isDirectory: false,
|
|
201
|
-
lineNumber: i + 1,
|
|
202
|
-
lineContent: line.trim().slice(0, maxLineLength),
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
catch (error) {
|
|
208
|
-
// Skip files that can't be read (binary or encoding issues)
|
|
209
|
-
}
|
|
210
|
-
return fileResults;
|
|
211
|
-
});
|
|
212
|
-
// Wait for batch to complete
|
|
213
|
-
const batchResults = await Promise.all(batchPromises);
|
|
214
|
-
// Flatten and add to results
|
|
215
|
-
for (const fileResults of batchResults) {
|
|
216
|
-
if (results.length >= maxResults) {
|
|
217
|
-
break;
|
|
218
|
-
}
|
|
219
|
-
results.push(...fileResults.slice(0, maxResults - results.length));
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
return results;
|
|
223
|
-
}, [files, rootPath, terminalWidth]);
|
|
224
|
-
// Load files when component becomes visible
|
|
225
|
-
// This ensures the file list is always fresh without complex file watching
|
|
226
|
-
useEffect(() => {
|
|
227
|
-
if (!visible) {
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
// Always reload when becoming visible to ensure fresh data
|
|
231
|
-
loadFiles();
|
|
232
|
-
}, [visible, rootPath, loadFiles]);
|
|
233
|
-
// State for filtered files (needed for async content search)
|
|
234
|
-
const [allFilteredFiles, setAllFilteredFiles] = useState([]);
|
|
235
|
-
// Filter files based on query and search mode with debounce
|
|
236
|
-
useEffect(() => {
|
|
237
|
-
const performSearch = async () => {
|
|
238
|
-
if (!query.trim()) {
|
|
239
|
-
setAllFilteredFiles(files);
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
if (searchMode === 'content') {
|
|
243
|
-
// Content search mode (@@)
|
|
244
|
-
const results = await searchFileContent(query);
|
|
245
|
-
setAllFilteredFiles(results);
|
|
246
|
-
}
|
|
247
|
-
else {
|
|
248
|
-
// File name search mode (@)
|
|
249
|
-
const queryLower = query.toLowerCase();
|
|
250
|
-
const filtered = files.filter(file => {
|
|
251
|
-
const fileName = file.name.toLowerCase();
|
|
252
|
-
const filePath = file.path.toLowerCase();
|
|
253
|
-
return (fileName.includes(queryLower) || filePath.includes(queryLower));
|
|
254
|
-
});
|
|
255
|
-
// Sort by relevance (exact name matches first, then path matches)
|
|
256
|
-
filtered.sort((a, b) => {
|
|
257
|
-
const aNameMatch = a.name.toLowerCase().startsWith(queryLower);
|
|
258
|
-
const bNameMatch = b.name.toLowerCase().startsWith(queryLower);
|
|
259
|
-
if (aNameMatch && !bNameMatch)
|
|
260
|
-
return -1;
|
|
261
|
-
if (!aNameMatch && bNameMatch)
|
|
262
|
-
return 1;
|
|
263
|
-
return a.name.localeCompare(b.name);
|
|
264
|
-
});
|
|
265
|
-
setAllFilteredFiles(filtered);
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
// Debounce search to avoid excessive updates during fast typing
|
|
269
|
-
// Use shorter delay for file search (150ms) and longer for content search (500ms)
|
|
270
|
-
const debounceDelay = searchMode === 'content' ? 500 : 150;
|
|
271
|
-
const timer = setTimeout(() => {
|
|
272
|
-
performSearch();
|
|
273
|
-
}, debounceDelay);
|
|
274
|
-
return () => clearTimeout(timer);
|
|
275
|
-
}, [files, query, searchMode, searchFileContent]);
|
|
276
|
-
// Display with scrolling window
|
|
277
|
-
const filteredFiles = useMemo(() => {
|
|
278
|
-
if (allFilteredFiles.length <= effectiveMaxItems) {
|
|
279
|
-
return allFilteredFiles;
|
|
280
|
-
}
|
|
281
|
-
// Show files around the selected index
|
|
282
|
-
const halfWindow = Math.floor(effectiveMaxItems / 2);
|
|
283
|
-
let startIndex = Math.max(0, selectedIndex - halfWindow);
|
|
284
|
-
let endIndex = Math.min(allFilteredFiles.length, startIndex + effectiveMaxItems);
|
|
285
|
-
// Adjust if we're near the end
|
|
286
|
-
if (endIndex - startIndex < effectiveMaxItems) {
|
|
287
|
-
startIndex = Math.max(0, endIndex - effectiveMaxItems);
|
|
288
|
-
}
|
|
289
|
-
return allFilteredFiles.slice(startIndex, endIndex);
|
|
290
|
-
}, [allFilteredFiles, selectedIndex, effectiveMaxItems]);
|
|
291
|
-
// Notify parent of filtered count changes
|
|
292
|
-
useEffect(() => {
|
|
293
|
-
if (onFilteredCountChange) {
|
|
294
|
-
onFilteredCountChange(allFilteredFiles.length);
|
|
295
|
-
}
|
|
296
|
-
}, [allFilteredFiles.length, onFilteredCountChange]);
|
|
297
|
-
// Expose methods to parent
|
|
298
|
-
useImperativeHandle(ref, () => ({
|
|
299
|
-
getSelectedFile: () => {
|
|
300
|
-
if (allFilteredFiles.length > 0 &&
|
|
301
|
-
selectedIndex < allFilteredFiles.length &&
|
|
302
|
-
allFilteredFiles[selectedIndex]) {
|
|
303
|
-
const selectedFile = allFilteredFiles[selectedIndex];
|
|
304
|
-
// For content search mode, include line number
|
|
305
|
-
if (selectedFile.lineNumber !== undefined) {
|
|
306
|
-
return `${selectedFile.path}:${selectedFile.lineNumber}`;
|
|
307
|
-
}
|
|
308
|
-
return selectedFile.path;
|
|
309
|
-
}
|
|
310
|
-
return null;
|
|
311
|
-
},
|
|
312
|
-
}), [allFilteredFiles, selectedIndex]);
|
|
313
|
-
// Calculate display index for the scrolling window
|
|
314
|
-
// MUST be before early returns to avoid hook order issues
|
|
315
|
-
const displaySelectedIndex = useMemo(() => {
|
|
316
|
-
return filteredFiles.findIndex(file => {
|
|
317
|
-
const originalIndex = allFilteredFiles.indexOf(file);
|
|
318
|
-
return originalIndex === selectedIndex;
|
|
319
|
-
});
|
|
320
|
-
}, [filteredFiles, allFilteredFiles, selectedIndex]);
|
|
321
|
-
if (!visible) {
|
|
322
|
-
return null;
|
|
323
|
-
}
|
|
324
|
-
if (isLoading) {
|
|
325
|
-
return (React.createElement(Box, { paddingX: 1, marginTop: 1 },
|
|
326
|
-
React.createElement(Text, { color: "blue", dimColor: true }, "Loading files...")));
|
|
327
|
-
}
|
|
328
|
-
if (filteredFiles.length === 0) {
|
|
329
|
-
return (React.createElement(Box, { paddingX: 1, marginTop: 1 },
|
|
330
|
-
React.createElement(Text, { color: theme.colors.menuSecondary, dimColor: true }, "No files found")));
|
|
331
|
-
}
|
|
332
|
-
return (React.createElement(Box, { paddingX: 1, marginTop: 1, flexDirection: "column" },
|
|
333
|
-
React.createElement(Box, { marginBottom: 1 },
|
|
334
|
-
React.createElement(Text, { color: "blue", bold: true },
|
|
335
|
-
searchMode === 'content' ? '≡ Content Search' : '≡ Files',
|
|
336
|
-
' ',
|
|
337
|
-
allFilteredFiles.length > effectiveMaxItems &&
|
|
338
|
-
`(${selectedIndex + 1}/${allFilteredFiles.length})`)),
|
|
339
|
-
filteredFiles.map((file, index) => (React.createElement(Box, { key: `${file.path}-${file.lineNumber || 0}`, flexDirection: "column" },
|
|
340
|
-
React.createElement(Text, { backgroundColor: index === displaySelectedIndex ? theme.colors.menuSelected : undefined, color: index === displaySelectedIndex
|
|
341
|
-
? theme.colors.menuNormal
|
|
342
|
-
: file.isDirectory
|
|
343
|
-
? theme.colors.warning
|
|
344
|
-
: 'white' }, searchMode === 'content' && file.lineNumber !== undefined
|
|
345
|
-
? `${file.path}:${file.lineNumber}`
|
|
346
|
-
: file.isDirectory
|
|
347
|
-
? '◇ ' + file.path
|
|
348
|
-
: '◆ ' + file.path),
|
|
349
|
-
searchMode === 'content' && file.lineContent && (React.createElement(Text, { backgroundColor: index === displaySelectedIndex ? theme.colors.menuSelected : undefined, color: index === displaySelectedIndex ? theme.colors.menuSecondary : theme.colors.menuSecondary, dimColor: true },
|
|
350
|
-
' ',
|
|
351
|
-
file.lineContent))))),
|
|
352
|
-
allFilteredFiles.length > effectiveMaxItems && (React.createElement(Box, { marginTop: 1 },
|
|
353
|
-
React.createElement(Text, { color: theme.colors.menuSecondary, dimColor: true },
|
|
354
|
-
"\u2191\u2193 to scroll \u00B7 ",
|
|
355
|
-
allFilteredFiles.length - effectiveMaxItems,
|
|
356
|
-
' ',
|
|
357
|
-
"more hidden")))));
|
|
358
|
-
}));
|
|
359
|
-
FileList.displayName = 'FileList';
|
|
360
|
-
export default FileList;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
type Props = {
|
|
3
|
-
fileCount: number;
|
|
4
|
-
filePaths: string[];
|
|
5
|
-
onConfirm: (rollbackFiles: boolean | null) => void;
|
|
6
|
-
};
|
|
7
|
-
export default function FileRollbackConfirmation({ fileCount, filePaths, onConfirm }: Props): React.JSX.Element;
|
|
8
|
-
export {};
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { Box, Text, useInput } from 'ink';
|
|
3
|
-
export default function FileRollbackConfirmation({ fileCount, filePaths, onConfirm }) {
|
|
4
|
-
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
5
|
-
const [showFullList, setShowFullList] = useState(false);
|
|
6
|
-
const [fileScrollIndex, setFileScrollIndex] = useState(0);
|
|
7
|
-
const options = [
|
|
8
|
-
{ label: 'Yes, rollback files and conversation', value: true },
|
|
9
|
-
{ label: 'No, rollback conversation only', value: false }
|
|
10
|
-
];
|
|
11
|
-
useInput((_, key) => {
|
|
12
|
-
// Tab - toggle full file list view
|
|
13
|
-
if (key.tab) {
|
|
14
|
-
setShowFullList(prev => !prev);
|
|
15
|
-
setFileScrollIndex(0); // Reset scroll when toggling
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
// In full list mode, use up/down to scroll files
|
|
19
|
-
if (showFullList) {
|
|
20
|
-
const maxVisibleFiles = 10;
|
|
21
|
-
const maxScroll = Math.max(0, filePaths.length - maxVisibleFiles);
|
|
22
|
-
if (key.upArrow) {
|
|
23
|
-
setFileScrollIndex(prev => Math.max(0, prev - 1));
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
if (key.downArrow) {
|
|
27
|
-
setFileScrollIndex(prev => Math.min(maxScroll, prev + 1));
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
// In compact mode, up/down navigate options
|
|
33
|
-
if (key.upArrow) {
|
|
34
|
-
setSelectedIndex(prev => Math.max(0, prev - 1));
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
if (key.downArrow) {
|
|
38
|
-
setSelectedIndex(prev => Math.min(options.length - 1, prev + 1));
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
// Enter - confirm selection (only when not in full list mode)
|
|
43
|
-
if (key.return && !showFullList) {
|
|
44
|
-
onConfirm(options[selectedIndex]?.value ?? false);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
// ESC - exit full list mode or cancel rollback
|
|
48
|
-
if (key.escape) {
|
|
49
|
-
if (showFullList) {
|
|
50
|
-
setShowFullList(false);
|
|
51
|
-
setFileScrollIndex(0);
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
onConfirm(null); // null means cancel everything
|
|
55
|
-
}
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
// Display logic for file list
|
|
60
|
-
const maxFilesToShowCompact = 5;
|
|
61
|
-
const maxFilesToShowFull = 10;
|
|
62
|
-
const displayFiles = showFullList
|
|
63
|
-
? filePaths.slice(fileScrollIndex, fileScrollIndex + maxFilesToShowFull)
|
|
64
|
-
: filePaths.slice(0, maxFilesToShowCompact);
|
|
65
|
-
const remainingCountCompact = fileCount - maxFilesToShowCompact;
|
|
66
|
-
const hasMoreAbove = showFullList && fileScrollIndex > 0;
|
|
67
|
-
const hasMoreBelow = showFullList && (fileScrollIndex + maxFilesToShowFull) < filePaths.length;
|
|
68
|
-
return (React.createElement(Box, { flexDirection: "column", marginX: 1, marginBottom: 1, padding: 1 },
|
|
69
|
-
React.createElement(Box, { marginBottom: 1 },
|
|
70
|
-
React.createElement(Text, { color: "yellow", bold: true }, "\u26A0 File Rollback Confirmation")),
|
|
71
|
-
React.createElement(Box, { marginBottom: 1 },
|
|
72
|
-
React.createElement(Text, { color: "white" },
|
|
73
|
-
"This checkpoint has ",
|
|
74
|
-
fileCount,
|
|
75
|
-
" file",
|
|
76
|
-
fileCount > 1 ? 's' : '',
|
|
77
|
-
" that will be rolled back:")),
|
|
78
|
-
React.createElement(Box, { flexDirection: "column", marginBottom: 1, marginLeft: 2 },
|
|
79
|
-
hasMoreAbove && (React.createElement(Text, { color: "gray", dimColor: true },
|
|
80
|
-
"\u2191 ",
|
|
81
|
-
fileScrollIndex,
|
|
82
|
-
" more above...")),
|
|
83
|
-
displayFiles.map((file, index) => (React.createElement(Text, { key: index, color: "cyan", dimColor: true },
|
|
84
|
-
"\u2022 ",
|
|
85
|
-
file))),
|
|
86
|
-
hasMoreBelow && (React.createElement(Text, { color: "gray", dimColor: true },
|
|
87
|
-
"\u2193 ",
|
|
88
|
-
filePaths.length - (fileScrollIndex + maxFilesToShowFull),
|
|
89
|
-
" more below...")),
|
|
90
|
-
!showFullList && remainingCountCompact > 0 && (React.createElement(Text, { color: "gray", dimColor: true },
|
|
91
|
-
"... and ",
|
|
92
|
-
remainingCountCompact,
|
|
93
|
-
" more file",
|
|
94
|
-
remainingCountCompact > 1 ? 's' : ''))),
|
|
95
|
-
!showFullList && (React.createElement(React.Fragment, null,
|
|
96
|
-
React.createElement(Box, { marginBottom: 1 },
|
|
97
|
-
React.createElement(Text, { color: "gray", dimColor: true }, "Do you want to rollback the files as well?")),
|
|
98
|
-
React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, options.map((option, index) => (React.createElement(Box, { key: index },
|
|
99
|
-
React.createElement(Text, { color: index === selectedIndex ? 'green' : 'white', bold: index === selectedIndex },
|
|
100
|
-
index === selectedIndex ? '❯ ' : ' ',
|
|
101
|
-
option.label))))))),
|
|
102
|
-
React.createElement(Box, null,
|
|
103
|
-
React.createElement(Text, { color: "gray", dimColor: true }, showFullList
|
|
104
|
-
? '↑↓ scroll · Tab back · ESC close'
|
|
105
|
-
: fileCount > maxFilesToShowCompact
|
|
106
|
-
? `↑↓ select · Tab view all (${fileCount} files) · Enter confirm · ESC cancel`
|
|
107
|
-
: '↑↓ select · Enter confirm · ESC cancel'))));
|
|
108
|
-
}
|