snow-ai 0.4.15 → 0.4.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useRef, useMemo } from 'react';
|
|
1
|
+
import React, { useCallback, useEffect, useRef, useMemo, lazy, Suspense } from 'react';
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
import { cpSlice } from '../../utils/textUtils.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
// Lazy load panel components to reduce initial bundle size
|
|
5
|
+
const CommandPanel = lazy(() => import('./CommandPanel.js'));
|
|
6
|
+
const FileList = lazy(() => import('./FileList.js'));
|
|
7
|
+
const AgentPickerPanel = lazy(() => import('./AgentPickerPanel.js'));
|
|
8
|
+
const TodoPickerPanel = lazy(() => import('./TodoPickerPanel.js'));
|
|
8
9
|
import { useInputBuffer } from '../../hooks/useInputBuffer.js';
|
|
9
10
|
import { useCommandPanel } from '../../hooks/useCommandPanel.js';
|
|
10
11
|
import { useFilePicker } from '../../hooks/useFilePicker.js';
|
|
@@ -309,11 +310,15 @@ export default function ChatInput({ onSubmit, onCommand, placeholder = 'Type you
|
|
|
309
310
|
? t.chatScreen.contentSearchHint
|
|
310
311
|
: t.chatScreen.fileSearchHint
|
|
311
312
|
: ''))) : null,
|
|
312
|
-
React.createElement(
|
|
313
|
+
React.createElement(Suspense, { fallback: null },
|
|
314
|
+
React.createElement(CommandPanel, { commands: getFilteredCommands(), selectedIndex: commandSelectedIndex, query: buffer.getFullText().slice(1), visible: showCommands, isProcessing: commandPanelIsProcessing })),
|
|
313
315
|
React.createElement(Box, null,
|
|
314
|
-
React.createElement(
|
|
315
|
-
|
|
316
|
-
React.createElement(
|
|
316
|
+
React.createElement(Suspense, { fallback: null },
|
|
317
|
+
React.createElement(FileList, { ref: fileListRef, query: fileQuery, selectedIndex: fileSelectedIndex, visible: showFilePicker, maxItems: 10, rootPath: process.cwd(), onFilteredCountChange: handleFilteredCountChange, searchMode: searchMode }))),
|
|
318
|
+
React.createElement(Suspense, { fallback: null },
|
|
319
|
+
React.createElement(AgentPickerPanel, { agents: getFilteredAgents(), selectedIndex: agentSelectedIndex, visible: showAgentPicker, maxHeight: 5 })),
|
|
320
|
+
React.createElement(Suspense, { fallback: null },
|
|
321
|
+
React.createElement(TodoPickerPanel, { todos: todos, selectedIndex: todoSelectedIndex, selectedTodos: selectedTodos, visible: showTodoPicker, maxHeight: 5, isLoading: todoIsLoading, searchQuery: todoSearchQuery, totalCount: totalTodoCount })),
|
|
317
322
|
yoloMode && (React.createElement(Box, { marginTop: 1 },
|
|
318
323
|
React.createElement(Text, { color: theme.colors.warning, dimColor: true }, t.chatScreen.yoloModeActive))),
|
|
319
324
|
contextUsage && (React.createElement(Box, { marginTop: 1 },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useEffect, useRef } from 'react';
|
|
1
|
+
import React, { useState, useEffect, useRef, lazy, Suspense } from 'react';
|
|
2
2
|
import { Box, Text, useInput, Static, useStdout } from 'ink';
|
|
3
3
|
import Spinner from 'ink-spinner';
|
|
4
4
|
import Gradient from 'ink-gradient';
|
|
@@ -7,17 +7,18 @@ import { useI18n } from '../../i18n/I18nContext.js';
|
|
|
7
7
|
import { useTheme } from '../contexts/ThemeContext.js';
|
|
8
8
|
import ChatInput from '../components/ChatInput.js';
|
|
9
9
|
import PendingMessages from '../components/PendingMessages.js';
|
|
10
|
-
import MCPInfoScreen from '../components/MCPInfoScreen.js';
|
|
11
|
-
import MCPInfoPanel from '../components/MCPInfoPanel.js';
|
|
12
|
-
import SessionListPanel from '../components/SessionListPanel.js';
|
|
13
|
-
import UsagePanel from '../components/UsagePanel.js';
|
|
14
|
-
import HelpPanel from '../components/HelpPanel.js';
|
|
15
10
|
import MarkdownRenderer from '../components/MarkdownRenderer.js';
|
|
16
11
|
import ToolConfirmation from '../components/ToolConfirmation.js';
|
|
17
12
|
import DiffViewer from '../components/DiffViewer.js';
|
|
18
13
|
import ToolResultPreview from '../components/ToolResultPreview.js';
|
|
19
14
|
import FileRollbackConfirmation from '../components/FileRollbackConfirmation.js';
|
|
20
15
|
import ShimmerText from '../components/ShimmerText.js';
|
|
16
|
+
// Lazy load panel components to reduce initial bundle size
|
|
17
|
+
const MCPInfoScreen = lazy(() => import('../components/MCPInfoScreen.js'));
|
|
18
|
+
const MCPInfoPanel = lazy(() => import('../components/MCPInfoPanel.js'));
|
|
19
|
+
const SessionListPanel = lazy(() => import('../components/SessionListPanel.js'));
|
|
20
|
+
const UsagePanel = lazy(() => import('../components/UsagePanel.js'));
|
|
21
|
+
const HelpPanel = lazy(() => import('../components/HelpPanel.js'));
|
|
21
22
|
import { getOpenAiConfig } from '../../utils/apiConfig.js';
|
|
22
23
|
import { sessionManager } from '../../utils/sessionManager.js';
|
|
23
24
|
import { useSessionSave } from '../../hooks/useSessionSave.js';
|
|
@@ -30,7 +31,7 @@ import { useStreamingState } from '../../hooks/useStreamingState.js';
|
|
|
30
31
|
import { useCommandHandler } from '../../hooks/useCommandHandler.js';
|
|
31
32
|
import { useTerminalSize } from '../../hooks/useTerminalSize.js';
|
|
32
33
|
import { parseAndValidateFileReferences, createMessageWithFileInstructions, } from '../../utils/fileUtils.js';
|
|
33
|
-
import {
|
|
34
|
+
import { vscodeConnection } from '../../utils/vscodeConnection.js';
|
|
34
35
|
import { convertSessionMessagesToUI } from '../../utils/sessionConverter.js';
|
|
35
36
|
import { incrementalSnapshotManager } from '../../utils/incrementalSnapshot.js';
|
|
36
37
|
import { formatElapsedTime } from '../../utils/textUtils.js';
|
|
@@ -391,22 +392,33 @@ export default function ChatScreen({ skipWelcome }) {
|
|
|
391
392
|
return;
|
|
392
393
|
}
|
|
393
394
|
hasAttemptedAutoVscodeConnect.current = true;
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
395
|
+
// Auto-connect IDE in background without blocking UI
|
|
396
|
+
// Use setTimeout to defer execution and make it fully async
|
|
397
|
+
const timer = setTimeout(() => {
|
|
398
|
+
// Fire and forget - don't wait for result
|
|
399
|
+
(async () => {
|
|
400
|
+
try {
|
|
401
|
+
// Clean up any existing connection state first (like manual /ide does)
|
|
402
|
+
if (vscodeConnection.isConnected() || vscodeConnection.isClientRunning()) {
|
|
403
|
+
vscodeConnection.stop();
|
|
404
|
+
vscodeConnection.resetReconnectAttempts();
|
|
405
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
406
|
+
}
|
|
407
|
+
// Set connecting status after cleanup
|
|
408
|
+
vscodeState.setVscodeConnectionStatus('connecting');
|
|
409
|
+
// Now try to connect
|
|
410
|
+
await vscodeConnection.start();
|
|
411
|
+
// If we get here, connection succeeded
|
|
412
|
+
// Status will be updated by useVSCodeState hook monitoring
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
console.error('Background VSCode auto-connect failed:', error);
|
|
416
|
+
// Let useVSCodeState handle the timeout and error state
|
|
417
|
+
}
|
|
418
|
+
})();
|
|
419
|
+
}, 0);
|
|
420
|
+
return () => clearTimeout(timer);
|
|
421
|
+
}, [commandsLoaded, vscodeState]);
|
|
410
422
|
// Pending messages are now handled inline during tool execution in useConversation
|
|
411
423
|
// Auto-send pending messages when streaming completely stops (as fallback)
|
|
412
424
|
useEffect(() => {
|
|
@@ -1123,7 +1135,11 @@ export default function ChatScreen({ skipWelcome }) {
|
|
|
1123
1135
|
}
|
|
1124
1136
|
};
|
|
1125
1137
|
if (showMcpInfo) {
|
|
1126
|
-
return (React.createElement(
|
|
1138
|
+
return (React.createElement(Suspense, { fallback: React.createElement(Box, null,
|
|
1139
|
+
React.createElement(Text, null,
|
|
1140
|
+
React.createElement(Spinner, { type: "dots" }),
|
|
1141
|
+
" Loading...")) },
|
|
1142
|
+
React.createElement(MCPInfoScreen, { onClose: () => setShowMcpInfo(false), panelKey: mcpPanelKey })));
|
|
1127
1143
|
}
|
|
1128
1144
|
// Show warning if terminal is too small
|
|
1129
1145
|
if (terminalHeight < MIN_TERMINAL_HEIGHT) {
|
|
@@ -1416,17 +1432,33 @@ export default function ChatScreen({ skipWelcome }) {
|
|
|
1416
1432
|
? pendingToolConfirmation.tool.function.arguments
|
|
1417
1433
|
: undefined, allTools: pendingToolConfirmation.allTools, onConfirm: pendingToolConfirmation.resolve })),
|
|
1418
1434
|
showSessionPanel && (React.createElement(Box, { paddingX: 1, width: terminalWidth },
|
|
1419
|
-
React.createElement(
|
|
1435
|
+
React.createElement(Suspense, { fallback: React.createElement(Box, null,
|
|
1436
|
+
React.createElement(Text, null,
|
|
1437
|
+
React.createElement(Spinner, { type: "dots" }),
|
|
1438
|
+
" Loading...")) },
|
|
1439
|
+
React.createElement(SessionListPanel, { onSelectSession: handleSessionPanelSelect, onClose: () => setShowSessionPanel(false) })))),
|
|
1420
1440
|
showMcpPanel && (React.createElement(Box, { paddingX: 1, flexDirection: "column", width: terminalWidth },
|
|
1421
|
-
React.createElement(
|
|
1441
|
+
React.createElement(Suspense, { fallback: React.createElement(Box, null,
|
|
1442
|
+
React.createElement(Text, null,
|
|
1443
|
+
React.createElement(Spinner, { type: "dots" }),
|
|
1444
|
+
" Loading...")) },
|
|
1445
|
+
React.createElement(MCPInfoPanel, null)),
|
|
1422
1446
|
React.createElement(Box, { marginTop: 1 },
|
|
1423
1447
|
React.createElement(Text, { color: theme.colors.menuSecondary, dimColor: true }, t.chatScreen.pressEscToClose)))),
|
|
1424
1448
|
showUsagePanel && (React.createElement(Box, { paddingX: 1, flexDirection: "column", width: terminalWidth },
|
|
1425
|
-
React.createElement(
|
|
1449
|
+
React.createElement(Suspense, { fallback: React.createElement(Box, null,
|
|
1450
|
+
React.createElement(Text, null,
|
|
1451
|
+
React.createElement(Spinner, { type: "dots" }),
|
|
1452
|
+
" Loading...")) },
|
|
1453
|
+
React.createElement(UsagePanel, null)),
|
|
1426
1454
|
React.createElement(Box, { marginTop: 1 },
|
|
1427
1455
|
React.createElement(Text, { color: theme.colors.menuSecondary, dimColor: true }, t.chatScreen.pressEscToClose)))),
|
|
1428
1456
|
showHelpPanel && (React.createElement(Box, { paddingX: 1, flexDirection: "column", width: terminalWidth },
|
|
1429
|
-
React.createElement(
|
|
1457
|
+
React.createElement(Suspense, { fallback: React.createElement(Box, null,
|
|
1458
|
+
React.createElement(Text, null,
|
|
1459
|
+
React.createElement(Spinner, { type: "dots" }),
|
|
1460
|
+
" Loading...")) },
|
|
1461
|
+
React.createElement(HelpPanel, null)))),
|
|
1430
1462
|
snapshotState.pendingRollback && (React.createElement(FileRollbackConfirmation, { fileCount: snapshotState.pendingRollback.fileCount, filePaths: snapshotState.pendingRollback.filePaths || [], onConfirm: handleRollbackConfirm })),
|
|
1431
1463
|
!pendingToolConfirmation &&
|
|
1432
1464
|
!isCompressing &&
|
|
@@ -1444,29 +1476,21 @@ export default function ChatScreen({ skipWelcome }) {
|
|
|
1444
1476
|
cachedTokens: streamingState.contextUsage.cached_tokens,
|
|
1445
1477
|
}
|
|
1446
1478
|
: undefined, initialContent: restoreInputContent, onContextPercentageChange: setCurrentContextPercentage }),
|
|
1447
|
-
vscodeState.vscodeConnectionStatus
|
|
1479
|
+
(vscodeState.vscodeConnectionStatus === 'connecting' ||
|
|
1480
|
+
vscodeState.vscodeConnectionStatus === 'connected') && (React.createElement(Box, { marginTop: 1, paddingX: 1 },
|
|
1448
1481
|
React.createElement(Text, { color: vscodeState.vscodeConnectionStatus === 'connecting'
|
|
1449
1482
|
? 'yellow'
|
|
1450
|
-
: vscodeState.vscodeConnectionStatus === '
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
: theme.colors.menuSecondary, dimColor: vscodeState.vscodeConnectionStatus !== 'error' },
|
|
1483
|
+
: 'green', dimColor: true }, vscodeState.vscodeConnectionStatus === 'connecting' ? (React.createElement(React.Fragment, null,
|
|
1484
|
+
React.createElement(Spinner, { type: "dots" }),
|
|
1485
|
+
" ",
|
|
1486
|
+
t.chatScreen.ideConnecting)) : (React.createElement(React.Fragment, null,
|
|
1455
1487
|
"\u25CF",
|
|
1456
1488
|
' ',
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
: vscodeState.vscodeConnectionStatus === 'connected'
|
|
1460
|
-
? t.chatScreen.ideConnected
|
|
1461
|
-
: vscodeState.vscodeConnectionStatus === 'error'
|
|
1462
|
-
? t.chatScreen.ideError
|
|
1463
|
-
: 'IDE',
|
|
1464
|
-
vscodeState.vscodeConnectionStatus === 'connected' &&
|
|
1465
|
-
vscodeState.editorContext.activeFile &&
|
|
1489
|
+
t.chatScreen.ideConnected,
|
|
1490
|
+
vscodeState.editorContext.activeFile &&
|
|
1466
1491
|
t.chatScreen.ideActiveFile.replace('{file}', vscodeState.editorContext.activeFile),
|
|
1467
|
-
vscodeState.
|
|
1468
|
-
vscodeState.editorContext.selectedText
|
|
1469
|
-
t.chatScreen.ideSelectedText.replace('{count}', vscodeState.editorContext.selectedText.length.toString())))),
|
|
1492
|
+
vscodeState.editorContext.selectedText &&
|
|
1493
|
+
t.chatScreen.ideSelectedText.replace('{count}', vscodeState.editorContext.selectedText.length.toString())))))),
|
|
1470
1494
|
codebaseIndexing && codebaseProgress && (React.createElement(Box, { marginTop: 1, paddingX: 1 },
|
|
1471
1495
|
React.createElement(Text, { color: "cyan", dimColor: true },
|
|
1472
1496
|
React.createElement(Spinner, { type: "dots" }),
|