wave-code 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/components/ChatInterface.d.ts.map +1 -1
- package/dist/components/ChatInterface.js +4 -24
- package/dist/components/CommandSelector.js +4 -4
- package/dist/components/DiffViewer.d.ts +1 -1
- package/dist/components/DiffViewer.d.ts.map +1 -1
- package/dist/components/DiffViewer.js +15 -15
- package/dist/components/FileSelector.js +2 -2
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +21 -50
- package/dist/components/Markdown.d.ts +6 -0
- package/dist/components/Markdown.d.ts.map +1 -0
- package/dist/components/Markdown.js +22 -0
- package/dist/components/MessageItem.d.ts +9 -0
- package/dist/components/MessageItem.d.ts.map +1 -0
- package/dist/components/MessageItem.js +15 -0
- package/dist/components/MessageList.d.ts +1 -1
- package/dist/components/MessageList.d.ts.map +1 -1
- package/dist/components/MessageList.js +33 -33
- package/dist/components/SubagentBlock.d.ts +0 -1
- package/dist/components/SubagentBlock.d.ts.map +1 -1
- package/dist/components/SubagentBlock.js +29 -30
- package/dist/components/ToolResultDisplay.js +5 -5
- package/dist/contexts/useChat.d.ts +2 -2
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +18 -9
- package/dist/hooks/useInputManager.d.ts +3 -1
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +15 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -2
- package/dist/managers/InputManager.d.ts +3 -1
- package/dist/managers/InputManager.d.ts.map +1 -1
- package/dist/managers/InputManager.js +44 -24
- package/dist/print-cli.d.ts +1 -0
- package/dist/print-cli.d.ts.map +1 -1
- package/dist/print-cli.js +88 -23
- package/dist/utils/usageSummary.d.ts +6 -0
- package/dist/utils/usageSummary.d.ts.map +1 -1
- package/dist/utils/usageSummary.js +72 -0
- package/package.json +10 -6
- package/src/components/ChatInterface.tsx +13 -43
- package/src/components/CommandSelector.tsx +5 -5
- package/src/components/DiffViewer.tsx +18 -16
- package/src/components/FileSelector.tsx +2 -2
- package/src/components/InputBox.tsx +22 -74
- package/src/components/Markdown.tsx +29 -0
- package/src/components/MessageItem.tsx +104 -0
- package/src/components/MessageList.tsx +142 -202
- package/src/components/SubagentBlock.tsx +56 -84
- package/src/components/ToolResultDisplay.tsx +5 -5
- package/src/contexts/useChat.tsx +22 -13
- package/src/hooks/useInputManager.ts +21 -3
- package/src/index.ts +12 -2
- package/src/managers/InputManager.ts +55 -25
- package/src/print-cli.ts +103 -21
- package/src/utils/usageSummary.ts +109 -0
package/README.md
CHANGED
|
@@ -51,8 +51,8 @@ export LOG_FILE="/path/to/your/logfile.log"
|
|
|
51
51
|
# Maximum log file size (optional, defaults to 10MB)
|
|
52
52
|
export LOG_MAX_FILE_SIZE="10485760"
|
|
53
53
|
|
|
54
|
-
# Token limit (optional, defaults to
|
|
55
|
-
export TOKEN_LIMIT="
|
|
54
|
+
# Token limit (optional, defaults to 96000)
|
|
55
|
+
export TOKEN_LIMIT="96000"
|
|
56
56
|
|
|
57
57
|
```
|
|
58
58
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAmDjC,CAAC"}
|
|
@@ -1,31 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useRef, useEffect } from "react";
|
|
3
2
|
import { Box } from "ink";
|
|
4
3
|
import { MessageList } from "./MessageList.js";
|
|
5
4
|
import { InputBox } from "./InputBox.js";
|
|
6
5
|
import { useChat } from "../contexts/useChat.js";
|
|
7
6
|
export const ChatInterface = () => {
|
|
8
|
-
const { messages, isLoading, isCommandRunning, userInputHistory, isCompressing, sendMessage, abortMessage, saveMemory, mcpServers, connectMcpServer, disconnectMcpServer, isExpanded, latestTotalTokens, slashCommands, hasSlashCommand, } = useChat();
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// Only sync when collapsed
|
|
13
|
-
if (!isExpanded) {
|
|
14
|
-
expandedMessagesRef.current = messages.map((message, index) => {
|
|
15
|
-
// If it's the last message, deep copy its blocks
|
|
16
|
-
if (index === messages.length - 1) {
|
|
17
|
-
return {
|
|
18
|
-
...message,
|
|
19
|
-
blocks: message.blocks.map((block) => ({ ...block })),
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
return message;
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
}, [isExpanded, messages]);
|
|
26
|
-
return (_jsxs(Box, { flexDirection: "column", height: "100%", children: [_jsx(Box, { flexGrow: 1, flexDirection: "column", paddingX: 1, children: isExpanded ? (
|
|
27
|
-
// Expanded mode uses messages from ref, loading and tokens are hardcoded to false and 0
|
|
28
|
-
_jsx(MessageList, { messages: expandedMessagesRef.current, isLoading: false, isCommandRunning: false, latestTotalTokens: 0, isExpanded: true })) : (
|
|
29
|
-
// Normal mode uses real-time state
|
|
30
|
-
_jsx(MessageList, { messages: messages, isLoading: isLoading, isCommandRunning: isCommandRunning, isCompressing: isCompressing, latestTotalTokens: latestTotalTokens, isExpanded: false })) }), !isExpanded && (_jsx(InputBox, { isLoading: isLoading, isCommandRunning: isCommandRunning, userInputHistory: userInputHistory, sendMessage: sendMessage, abortMessage: abortMessage, saveMemory: saveMemory, mcpServers: mcpServers, connectMcpServer: connectMcpServer, disconnectMcpServer: disconnectMcpServer, slashCommands: slashCommands, hasSlashCommand: hasSlashCommand }))] }));
|
|
7
|
+
const { messages, isLoading, isCommandRunning, userInputHistory, isCompressing, sendMessage, abortMessage, saveMemory, mcpServers, connectMcpServer, disconnectMcpServer, isExpanded, sessionId, latestTotalTokens, slashCommands, hasSlashCommand, } = useChat();
|
|
8
|
+
if (!sessionId)
|
|
9
|
+
return null;
|
|
10
|
+
return (_jsxs(Box, { flexDirection: "column", height: "100%", paddingY: 1, children: [_jsx(MessageList, { messages: messages, isLoading: isLoading, isCommandRunning: isCommandRunning, isCompressing: isCompressing, latestTotalTokens: latestTotalTokens, isExpanded: isExpanded }, String(isExpanded) + sessionId), !isExpanded && (_jsx(InputBox, { isLoading: isLoading, isCommandRunning: isCommandRunning, userInputHistory: userInputHistory, sendMessage: sendMessage, abortMessage: abortMessage, saveMemory: saveMemory, mcpServers: mcpServers, connectMcpServer: connectMcpServer, disconnectMcpServer: disconnectMcpServer, slashCommands: slashCommands, hasSlashCommand: hasSlashCommand }))] }));
|
|
31
11
|
};
|
|
@@ -22,12 +22,12 @@ export const CommandSelector = ({ searchQuery, onSelect, onInsert, onCancel, com
|
|
|
22
22
|
const allCommands = [...commands, ...AVAILABLE_COMMANDS];
|
|
23
23
|
// Filter command list
|
|
24
24
|
const filteredCommands = allCommands.filter((command) => !searchQuery ||
|
|
25
|
-
command.
|
|
25
|
+
command.id.toLowerCase().includes(searchQuery.toLowerCase()));
|
|
26
26
|
useInput((input, key) => {
|
|
27
27
|
if (key.return) {
|
|
28
28
|
if (filteredCommands.length > 0 &&
|
|
29
29
|
selectedIndex < filteredCommands.length) {
|
|
30
|
-
const selectedCommand = filteredCommands[selectedIndex].
|
|
30
|
+
const selectedCommand = filteredCommands[selectedIndex].id;
|
|
31
31
|
onSelect(selectedCommand);
|
|
32
32
|
}
|
|
33
33
|
return;
|
|
@@ -35,7 +35,7 @@ export const CommandSelector = ({ searchQuery, onSelect, onInsert, onCancel, com
|
|
|
35
35
|
if (key.tab && onInsert) {
|
|
36
36
|
if (filteredCommands.length > 0 &&
|
|
37
37
|
selectedIndex < filteredCommands.length) {
|
|
38
|
-
const selectedCommand = filteredCommands[selectedIndex].
|
|
38
|
+
const selectedCommand = filteredCommands[selectedIndex].id;
|
|
39
39
|
onInsert(selectedCommand);
|
|
40
40
|
}
|
|
41
41
|
return;
|
|
@@ -56,5 +56,5 @@ export const CommandSelector = ({ searchQuery, onSelect, onInsert, onCancel, com
|
|
|
56
56
|
if (filteredCommands.length === 0) {
|
|
57
57
|
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", padding: 1, marginBottom: 1, children: [_jsxs(Text, { color: "yellow", children: ["No commands found for \"", searchQuery, "\""] }), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] }));
|
|
58
58
|
}
|
|
59
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "magenta", padding: 1, gap: 1, marginBottom: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "magenta", bold: true, children: ["Command Selector ", searchQuery && `(filtering: "${searchQuery}")`] }) }), filteredCommands.map((command, index) => (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: index === selectedIndex ? "black" : "white", backgroundColor: index === selectedIndex ? "magenta" : undefined, children: [index === selectedIndex ? "▶ " : " ", "/", command.
|
|
59
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "magenta", padding: 1, gap: 1, marginBottom: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "magenta", bold: true, children: ["Command Selector ", searchQuery && `(filtering: "${searchQuery}")`] }) }), filteredCommands.map((command, index) => (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: index === selectedIndex ? "black" : "white", backgroundColor: index === selectedIndex ? "magenta" : undefined, children: [index === selectedIndex ? "▶ " : " ", "/", command.id] }), index === selectedIndex && (_jsx(Box, { marginLeft: 4, children: _jsx(Text, { color: "gray", dimColor: true, children: command.description }) }))] }, command.id))), _jsx(Box, { children: _jsxs(Text, { dimColor: true, children: ["\u2191\u2193 navigate \u2022 Enter execute \u2022 ", onInsert ? "Tab insert • " : "", "Esc cancel"] }) })] }));
|
|
60
60
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DiffViewer.d.ts","sourceRoot":"","sources":["../../src/components/DiffViewer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,UAAU,eAAe;IACvB,KAAK,EAAE,SAAS,CAAC;IACjB,
|
|
1
|
+
{"version":3,"file":"DiffViewer.d.ts","sourceRoot":"","sources":["../../src/components/DiffViewer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,UAAU,eAAe;IACvB,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAwCD,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAkRhD,CAAC"}
|
|
@@ -22,7 +22,7 @@ const renderWordLevelDiff = (removedLine, addedLine) => {
|
|
|
22
22
|
});
|
|
23
23
|
return { removedParts, addedParts };
|
|
24
24
|
};
|
|
25
|
-
export const DiffViewer = ({ block,
|
|
25
|
+
export const DiffViewer = ({ block, isStatic = true, }) => {
|
|
26
26
|
const { diffResult } = block;
|
|
27
27
|
const diffLines = useMemo(() => {
|
|
28
28
|
if (!diffResult)
|
|
@@ -183,24 +183,24 @@ export const DiffViewer = ({ block, isExpanded = false, }) => {
|
|
|
183
183
|
});
|
|
184
184
|
// Handle remaining deleted lines at the end
|
|
185
185
|
flushPendingLines();
|
|
186
|
-
// Only limit displayed lines in collapsed state
|
|
187
|
-
if (!isExpanded) {
|
|
188
|
-
const MAX_DISPLAY_LINES = 50;
|
|
189
|
-
if (lines.length > MAX_DISPLAY_LINES) {
|
|
190
|
-
const truncatedLines = lines.slice(0, MAX_DISPLAY_LINES);
|
|
191
|
-
truncatedLines.push({
|
|
192
|
-
content: `... (${lines.length - MAX_DISPLAY_LINES} more lines truncated, press Ctrl+O to expand)`,
|
|
193
|
-
type: "separator",
|
|
194
|
-
});
|
|
195
|
-
return truncatedLines;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
186
|
return lines;
|
|
199
|
-
}, [diffResult
|
|
187
|
+
}, [diffResult]);
|
|
188
|
+
// Truncate to last 10 lines for non-static items
|
|
189
|
+
const displayLines = useMemo(() => {
|
|
190
|
+
if (isStatic) {
|
|
191
|
+
return diffLines;
|
|
192
|
+
}
|
|
193
|
+
const MAX_LINES = 10;
|
|
194
|
+
if (diffLines.length <= MAX_LINES) {
|
|
195
|
+
return diffLines;
|
|
196
|
+
}
|
|
197
|
+
return diffLines.slice(-MAX_LINES);
|
|
198
|
+
}, [diffLines, isStatic]);
|
|
200
199
|
if (!diffResult || diffResult.length === 0) {
|
|
201
200
|
return (_jsx(Box, { flexDirection: "column", children: _jsx(Text, { color: "gray", children: "No changes detected" }) }));
|
|
202
201
|
}
|
|
203
|
-
|
|
202
|
+
// Show traditional diff view
|
|
203
|
+
return (_jsx(Box, { flexDirection: "column", children: _jsx(Box, { flexDirection: "column", children: _jsx(Box, { flexDirection: "column", children: displayLines.map((line, index) => {
|
|
204
204
|
// If has word-level diff, render special effects
|
|
205
205
|
if (line.wordDiff) {
|
|
206
206
|
const prefix = line.type === "removed" ? "- " : "+ ";
|
|
@@ -4,7 +4,7 @@ import { Box, Text, useInput } from "ink";
|
|
|
4
4
|
export const FileSelector = ({ files, searchQuery, onSelect, onCancel, }) => {
|
|
5
5
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
6
6
|
useInput((input, key) => {
|
|
7
|
-
if (key.return) {
|
|
7
|
+
if (key.return || key.tab) {
|
|
8
8
|
if (files.length > 0 && selectedIndex < files.length) {
|
|
9
9
|
onSelect(files[selectedIndex].path);
|
|
10
10
|
}
|
|
@@ -44,5 +44,5 @@ export const FileSelector = ({ files, searchQuery, onSelect, onCancel, }) => {
|
|
|
44
44
|
const isSelected = actualIndex === selectedIndex;
|
|
45
45
|
const icon = fileItem.type === "directory" ? "📁" : "📄";
|
|
46
46
|
return (_jsx(Box, { children: _jsxs(Text, { color: isSelected ? "black" : "white", backgroundColor: isSelected ? "cyan" : undefined, children: [" ", icon, " ", fileItem.path] }) }, fileItem.path));
|
|
47
|
-
}), endIndex < files.length && (_jsxs(Text, { dimColor: true, children: ["... ", files.length - endIndex, " more files below"] })), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Use \u2191\u2193 to navigate, Enter to select, Escape to cancel" }), _jsxs(Text, { dimColor: true, children: ["File ", selectedIndex + 1, " of ", files.length] })] })] }));
|
|
47
|
+
}), endIndex < files.length && (_jsxs(Text, { dimColor: true, children: ["... ", files.length - endIndex, " more files below"] })), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Use \u2191\u2193 to navigate, Enter/Tab to select, Escape to cancel" }), _jsxs(Text, { dimColor: true, children: ["File ", selectedIndex + 1, " of ", files.length] })] })] }));
|
|
48
48
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6B,MAAM,OAAO,CAAC;AAWlD,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEpE,eAAO,MAAM,sBAAsB,yGACqE,CAAC;AAEzG,eAAO,MAAM,6BAA6B,QAGzC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,CACZ,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,KAC/C,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1E,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,mBAAmB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAE/D,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAClD;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAiL5C,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useEffect, useMemo } from "react";
|
|
3
3
|
import { Box, Text } from "ink";
|
|
4
4
|
import { useInput } from "ink";
|
|
5
5
|
import { FileSelector } from "./FileSelector.js";
|
|
@@ -12,37 +12,34 @@ import { useInputManager } from "../hooks/useInputManager.js";
|
|
|
12
12
|
export const INPUT_PLACEHOLDER_TEXT = "Type your message (use @ to reference files, / for commands, ! for bash history, # to add memory)...";
|
|
13
13
|
export const INPUT_PLACEHOLDER_TEXT_PREFIX = INPUT_PLACEHOLDER_TEXT.substring(0, 10);
|
|
14
14
|
export const InputBox = ({ isLoading = false, isCommandRunning = false, workdir, userInputHistory = [], sendMessage = () => { }, abortMessage = () => { }, saveMemory = async () => { }, mcpServers = [], connectMcpServer = async () => false, disconnectMcpServer = async () => false, slashCommands = [], hasSlashCommand = () => false, }) => {
|
|
15
|
-
// Get current working directory
|
|
16
|
-
const currentWorkdir = workdir || process.cwd();
|
|
17
|
-
// Simple history navigation reset function
|
|
18
|
-
const resetHistoryNavigation = useCallback(() => {
|
|
19
|
-
// This will be handled by InputManager through callbacks
|
|
20
|
-
}, []);
|
|
15
|
+
// Get current working directory - memoized to avoid repeated process.cwd() calls
|
|
16
|
+
const currentWorkdir = useMemo(() => workdir || process.cwd(), [workdir]);
|
|
21
17
|
// Input manager with all input state and functionality (including images)
|
|
22
|
-
const { inputText, cursorPosition,
|
|
18
|
+
const { inputText, cursorPosition,
|
|
23
19
|
// Image management
|
|
24
20
|
attachedImages, clearImages,
|
|
25
21
|
// File selector
|
|
26
|
-
showFileSelector, filteredFiles, fileSearchQuery: searchQuery, handleFileSelect
|
|
22
|
+
showFileSelector, filteredFiles, fileSearchQuery: searchQuery, handleFileSelect, handleCancelFileSelect,
|
|
27
23
|
// Command selector
|
|
28
|
-
showCommandSelector, commandSearchQuery, handleCommandSelect
|
|
24
|
+
showCommandSelector, commandSearchQuery, handleCommandSelect, handleCommandInsert, handleCancelCommandSelect,
|
|
29
25
|
// Bash history selector
|
|
30
|
-
showBashHistorySelector, bashHistorySearchQuery, handleBashHistorySelect
|
|
26
|
+
showBashHistorySelector, bashHistorySearchQuery, handleBashHistorySelect, handleCancelBashHistorySelect,
|
|
31
27
|
// Memory type selector
|
|
32
|
-
showMemoryTypeSelector, memoryMessage, handleMemoryTypeSelect
|
|
28
|
+
showMemoryTypeSelector, memoryMessage, handleMemoryTypeSelect, handleCancelMemoryTypeSelect,
|
|
33
29
|
// Bash/MCP Manager
|
|
34
30
|
showBashManager, showMcpManager, setShowBashManager, setShowMcpManager,
|
|
35
31
|
// Input history
|
|
36
32
|
setUserInputHistory,
|
|
33
|
+
// Complex handlers combining multiple operations
|
|
34
|
+
handleBashHistoryExecuteAndSend,
|
|
37
35
|
// Main handler
|
|
38
|
-
handleInput,
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
handleInput,
|
|
37
|
+
// Manager ready state
|
|
38
|
+
isManagerReady, } = useInputManager({
|
|
41
39
|
onSendMessage: sendMessage,
|
|
42
40
|
onHasSlashCommand: hasSlashCommand,
|
|
43
41
|
onSaveMemory: saveMemory,
|
|
44
42
|
onAbortMessage: abortMessage,
|
|
45
|
-
onResetHistoryNavigation: resetHistoryNavigation,
|
|
46
43
|
});
|
|
47
44
|
// Set user input history when it changes
|
|
48
45
|
useEffect(() => {
|
|
@@ -52,41 +49,11 @@ export const InputBox = ({ isLoading = false, isCommandRunning = false, workdir,
|
|
|
52
49
|
useInput(async (input, key) => {
|
|
53
50
|
await handleInput(input, key, attachedImages, isLoading, isCommandRunning, clearImages);
|
|
54
51
|
});
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
handleFileSelectorSelect(filePath);
|
|
58
|
-
}, [handleFileSelectorSelect]);
|
|
59
|
-
const handleCommandSelect = useCallback((command) => {
|
|
60
|
-
handleCommandSelectorSelect(command);
|
|
61
|
-
}, [handleCommandSelectorSelect]);
|
|
62
|
-
const handleBashHistorySelect = useCallback((command) => {
|
|
63
|
-
handleBashHistorySelectorSelect(command);
|
|
64
|
-
}, [handleBashHistorySelectorSelect]);
|
|
65
|
-
const keyboardHandleBashHistoryExecute = useCallback((command) => {
|
|
66
|
-
const commandToExecute = handleBashHistoryExecute(command);
|
|
67
|
-
// Clear input box and execute command, ensure command starts with !
|
|
68
|
-
const bashCommand = commandToExecute.startsWith("!")
|
|
69
|
-
? commandToExecute
|
|
70
|
-
: `!${commandToExecute}`;
|
|
71
|
-
clearInput();
|
|
72
|
-
sendMessage(bashCommand);
|
|
73
|
-
}, [handleBashHistoryExecute, clearInput, sendMessage]);
|
|
74
|
-
const handleMemoryTypeSelect = useCallback(async (type) => {
|
|
75
|
-
const currentMessage = inputText.trim();
|
|
76
|
-
if (currentMessage.startsWith("#")) {
|
|
77
|
-
await saveMemory(currentMessage, type);
|
|
78
|
-
}
|
|
79
|
-
// Call the handler function to close the selector
|
|
80
|
-
handleMemoryTypeSelectorSelect(type);
|
|
81
|
-
// Clear input box
|
|
82
|
-
clearInput();
|
|
83
|
-
}, [inputText, saveMemory, handleMemoryTypeSelectorSelect, clearInput]);
|
|
52
|
+
// These methods are already memoized in useInputManager, no need to wrap again
|
|
53
|
+
// These methods are already memoized in useInputManager and combine multiple operations
|
|
84
54
|
const isPlaceholder = !inputText;
|
|
85
55
|
const placeholderText = INPUT_PLACEHOLDER_TEXT;
|
|
86
|
-
//
|
|
87
|
-
const handleCommandInsert = useCallback((command) => {
|
|
88
|
-
handleCommandSelectorInsert(command);
|
|
89
|
-
}, [handleCommandSelectorInsert]);
|
|
56
|
+
// handleCommandSelectorInsert is already memoized in useInputManager, no need to wrap again
|
|
90
57
|
// Split text into three parts: before cursor, cursor position, after cursor
|
|
91
58
|
const displayText = isPlaceholder ? placeholderText : inputText;
|
|
92
59
|
const beforeCursor = displayText.substring(0, cursorPosition);
|
|
@@ -94,5 +61,9 @@ export const InputBox = ({ isLoading = false, isCommandRunning = false, workdir,
|
|
|
94
61
|
const afterCursor = displayText.substring(cursorPosition + 1);
|
|
95
62
|
// Always show cursor, allow user to continue input during loading
|
|
96
63
|
const shouldShowCursor = true;
|
|
97
|
-
|
|
64
|
+
// Only show the Box after InputManager is created on first mount
|
|
65
|
+
if (!isManagerReady) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return (_jsxs(Box, { flexDirection: "column", children: [showFileSelector && (_jsx(FileSelector, { files: filteredFiles, searchQuery: searchQuery, onSelect: handleFileSelect, onCancel: handleCancelFileSelect })), showCommandSelector && (_jsx(CommandSelector, { searchQuery: commandSearchQuery, onSelect: handleCommandSelect, onInsert: handleCommandInsert, onCancel: handleCancelCommandSelect, commands: slashCommands })), showBashHistorySelector && (_jsx(BashHistorySelector, { searchQuery: bashHistorySearchQuery, workdir: currentWorkdir, onSelect: handleBashHistorySelect, onExecute: handleBashHistoryExecuteAndSend, onCancel: handleCancelBashHistorySelect })), showMemoryTypeSelector && (_jsx(MemoryTypeSelector, { message: memoryMessage, onSelect: handleMemoryTypeSelect, onCancel: handleCancelMemoryTypeSelect })), showBashManager && (_jsx(BashShellManager, { onCancel: () => setShowBashManager(false) })), showMcpManager && (_jsx(McpManager, { onCancel: () => setShowMcpManager(false), servers: mcpServers, onConnectServer: connectMcpServer, onDisconnectServer: disconnectMcpServer })), showBashManager || showMcpManager || (_jsx(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, children: _jsx(Text, { color: isPlaceholder ? "gray" : "white", children: shouldShowCursor ? (_jsxs(_Fragment, { children: [beforeCursor, _jsx(Text, { backgroundColor: "white", color: "black", children: atCursor }), afterCursor] })) : (displayText) }) }))] }));
|
|
98
69
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Markdown.d.ts","sourceRoot":"","sources":["../../src/components/Markdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAKvC,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAGD,eAAO,MAAM,QAAQ,2CAA6B,aAAa,6CAe7D,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { useMemo } from "react";
|
|
3
|
+
import { Text } from "ink";
|
|
4
|
+
import { marked } from "marked";
|
|
5
|
+
import TerminalRenderer from "marked-terminal";
|
|
6
|
+
// Markdown component using marked-terminal with proper unescape option
|
|
7
|
+
export const Markdown = React.memo(({ children }) => {
|
|
8
|
+
const result = useMemo(() => {
|
|
9
|
+
// Configure marked with TerminalRenderer using default options
|
|
10
|
+
marked.setOptions({
|
|
11
|
+
renderer: new TerminalRenderer({
|
|
12
|
+
// Use official unescape option to handle HTML entities
|
|
13
|
+
unescape: true,
|
|
14
|
+
}),
|
|
15
|
+
});
|
|
16
|
+
const output = marked(children);
|
|
17
|
+
return typeof output === "string" ? output.trim() : "";
|
|
18
|
+
}, [children]);
|
|
19
|
+
return _jsx(Text, { children: result });
|
|
20
|
+
});
|
|
21
|
+
// Add display name for debugging
|
|
22
|
+
Markdown.displayName = "Markdown";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Message } from "wave-agent-sdk";
|
|
2
|
+
export interface MessageItemProps {
|
|
3
|
+
message: Message;
|
|
4
|
+
isExpanded: boolean;
|
|
5
|
+
shouldShowHeader: boolean;
|
|
6
|
+
isStatic?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare const MessageItem: ({ message, isExpanded, shouldShowHeader, isStatic, }: MessageItemProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
9
|
+
//# sourceMappingURL=MessageItem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageItem.d.ts","sourceRoot":"","sources":["../../src/components/MessageItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAU9C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,WAAW,GAAI,sDAKzB,gBAAgB,mDA+ElB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { MessageSource } from "wave-agent-sdk";
|
|
4
|
+
import { DiffViewer } from "./DiffViewer.js";
|
|
5
|
+
import { CommandOutputDisplay } from "./CommandOutputDisplay.js";
|
|
6
|
+
import { ToolResultDisplay } from "./ToolResultDisplay.js";
|
|
7
|
+
import { MemoryDisplay } from "./MemoryDisplay.js";
|
|
8
|
+
import { CompressDisplay } from "./CompressDisplay.js";
|
|
9
|
+
import { SubagentBlock } from "./SubagentBlock.js";
|
|
10
|
+
import { Markdown } from "./Markdown.js";
|
|
11
|
+
export const MessageItem = ({ message, isExpanded, shouldShowHeader, isStatic = true, }) => {
|
|
12
|
+
if (message.blocks.length === 0)
|
|
13
|
+
return null;
|
|
14
|
+
return (_jsxs(Box, { flexDirection: "column", gap: 1, marginTop: 1, children: [shouldShowHeader && (_jsx(Box, { children: _jsx(Text, { color: message.role === "user" ? "cyan" : "green", bold: true, children: message.role === "user" ? "👤 You" : "🤖 Assistant" }) })), _jsx(Box, { flexDirection: "column", gap: 1, children: message.blocks.map((block, blockIndex) => (_jsxs(Box, { children: [block.type === "text" && block.content.trim() && (_jsxs(Box, { children: [block.customCommandContent && (_jsxs(Text, { color: "cyan", bold: true, children: ["\u26A1", " "] })), block.source === MessageSource.HOOK && (_jsxs(Text, { color: "magenta", bold: true, children: ["\uD83D\uDD17", " "] })), isStatic ? (_jsx(Markdown, { children: block.content })) : (_jsx(Text, { children: block.content.split("\n").slice(-10).join("\n") }))] })), block.type === "error" && (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["\u274C Error: ", block.content] }) })), block.type === "diff" && (_jsx(DiffViewer, { block: block, isStatic: isStatic })), block.type === "command_output" && (_jsx(CommandOutputDisplay, { block: block, isExpanded: isExpanded })), block.type === "tool" && (_jsx(ToolResultDisplay, { block: block, isExpanded: isExpanded })), block.type === "image" && (_jsxs(Box, { children: [_jsx(Text, { color: "magenta", bold: true, children: "\uD83D\uDCF7 Image" }), block.imageUrls && block.imageUrls.length > 0 && (_jsxs(Text, { color: "gray", dimColor: true, children: [" ", "(", block.imageUrls.length, ")"] }))] })), block.type === "memory" && _jsx(MemoryDisplay, { block: block }), block.type === "compress" && (_jsx(CompressDisplay, { block: block, isExpanded: isExpanded })), block.type === "subagent" && _jsx(SubagentBlock, { block: block })] }, blockIndex))) })] }));
|
|
15
|
+
};
|
|
@@ -8,5 +8,5 @@ export interface MessageListProps {
|
|
|
8
8
|
latestTotalTokens?: number;
|
|
9
9
|
isExpanded?: boolean;
|
|
10
10
|
}
|
|
11
|
-
export declare const MessageList: React.
|
|
11
|
+
export declare const MessageList: React.MemoExoticComponent<({ messages, isLoading, isCommandRunning, isCompressing, latestTotalTokens, isExpanded, }: MessageListProps) => import("react/jsx-runtime").JSX.Element>;
|
|
12
12
|
//# sourceMappingURL=MessageList.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../src/components/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../src/components/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAG9C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,WAAW,uHAQnB,gBAAgB,6CA0IpB,CAAC"}
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
import { jsxs as _jsxs,
|
|
2
|
-
import
|
|
3
|
-
import { Box, Text } from "ink";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
import { CommandOutputDisplay } from "./CommandOutputDisplay.js";
|
|
7
|
-
import { ToolResultDisplay } from "./ToolResultDisplay.js";
|
|
8
|
-
import { MemoryDisplay } from "./MemoryDisplay.js";
|
|
9
|
-
import { CompressDisplay } from "./CompressDisplay.js";
|
|
10
|
-
import { SubagentBlock } from "./SubagentBlock.js";
|
|
11
|
-
import { usePagination } from "../hooks/usePagination.js";
|
|
12
|
-
// Function to render a single message
|
|
13
|
-
const renderMessageItem = (message, originalIndex, isExpanded, previousMessage) => {
|
|
14
|
-
const shouldShowHeader = previousMessage?.role !== message.role;
|
|
15
|
-
return (_jsxs(Box, { flexDirection: "column", children: [shouldShowHeader && (_jsx(Box, { children: _jsxs(Text, { color: message.role === "user" ? "cyan" : "green", bold: true, children: [message.role === "user" ? "👤 You" : "🤖 Assistant", _jsxs(Text, { color: "gray", dimColor: true, children: [" ", "#", originalIndex + 1] })] }) })), _jsx(Box, { marginLeft: 2, flexDirection: "column", gap: 1, marginTop: shouldShowHeader ? 1 : 0, children: message.blocks.map((block, blockIndex) => (_jsxs(Box, { children: [block.type === "text" && block.content.trim() && (_jsx(Box, { children: _jsxs(Text, { children: [block.customCommandContent && (_jsxs(Text, { color: "cyan", bold: true, children: ["\u26A1", " "] })), block.source === MessageSource.HOOK && (_jsxs(Text, { color: "magenta", bold: true, children: ["\uD83D\uDD17", " "] })), block.content] }) })), block.type === "error" && (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["\u274C Error: ", block.content] }) })), block.type === "diff" && (_jsx(DiffViewer, { block: block, isExpanded: isExpanded })), block.type === "command_output" && (_jsx(CommandOutputDisplay, { block: block, isExpanded: isExpanded })), block.type === "tool" && (_jsx(ToolResultDisplay, { block: block, isExpanded: isExpanded })), block.type === "image" && (_jsxs(Box, { children: [_jsx(Text, { color: "magenta", bold: true, children: "\uD83D\uDCF7 Image" }), block.imageUrls && block.imageUrls.length > 0 && (_jsxs(Text, { color: "gray", dimColor: true, children: [" ", "(", block.imageUrls.length, ")"] }))] })), block.type === "memory" && _jsx(MemoryDisplay, { block: block }), block.type === "compress" && (_jsx(CompressDisplay, { block: block, isExpanded: isExpanded })), block.type === "subagent" && (_jsx(SubagentBlock, { block: block, isExpanded: isExpanded }))] }, blockIndex))) })] }, `message-${originalIndex}`));
|
|
16
|
-
};
|
|
17
|
-
export const MessageList = ({ messages, isLoading = false, isCommandRunning = false, isCompressing = false, latestTotalTokens = 0, isExpanded = false, }) => {
|
|
18
|
-
// Use original messages for pagination calculation
|
|
19
|
-
const { displayInfo } = usePagination(messages);
|
|
20
|
-
// Get current page messages while preserving original index information
|
|
21
|
-
const currentMessagesWithIndex = useMemo(() => {
|
|
22
|
-
return messages
|
|
23
|
-
.slice(displayInfo.startIndex, displayInfo.endIndex)
|
|
24
|
-
.map((message, index) => ({
|
|
25
|
-
message,
|
|
26
|
-
originalIndex: displayInfo.startIndex + index,
|
|
27
|
-
}));
|
|
28
|
-
}, [messages, displayInfo.startIndex, displayInfo.endIndex]);
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Box, Text, Static } from "ink";
|
|
4
|
+
import { MessageItem } from "./MessageItem.js";
|
|
5
|
+
export const MessageList = React.memo(({ messages, isLoading = false, isCommandRunning = false, isCompressing = false, latestTotalTokens = 0, isExpanded = false, }) => {
|
|
29
6
|
// Empty message state
|
|
30
7
|
if (messages.length === 0) {
|
|
31
8
|
return (_jsx(Box, { flexDirection: "column", paddingY: 1, children: _jsx(Text, { color: "gray", children: "Welcome to WAVE Code Assistant!" }) }));
|
|
32
9
|
}
|
|
33
|
-
|
|
10
|
+
// Limit messages when expanded to prevent long rendering times
|
|
11
|
+
const maxExpandedMessages = 20;
|
|
12
|
+
const shouldLimitMessages = isExpanded && messages.length > maxExpandedMessages;
|
|
13
|
+
const displayMessages = shouldLimitMessages
|
|
14
|
+
? messages.slice(-maxExpandedMessages)
|
|
15
|
+
: messages;
|
|
16
|
+
const omittedCount = shouldLimitMessages
|
|
17
|
+
? messages.length - maxExpandedMessages
|
|
18
|
+
: 0;
|
|
19
|
+
// Compute which messages to render statically vs dynamically
|
|
20
|
+
const shouldRenderLastDynamic = isLoading || isCommandRunning;
|
|
21
|
+
const staticMessages = shouldRenderLastDynamic
|
|
22
|
+
? displayMessages.slice(0, -1)
|
|
23
|
+
: displayMessages;
|
|
24
|
+
const dynamicMessages = shouldRenderLastDynamic && displayMessages.length > 0
|
|
25
|
+
? [displayMessages[displayMessages.length - 1]]
|
|
26
|
+
: [];
|
|
27
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, gap: 1, children: [omittedCount > 0 && (_jsx(Box, { children: _jsxs(Text, { color: "gray", dimColor: true, children: ["... ", omittedCount, " earlier message", omittedCount !== 1 ? "s" : "", " ", "omitted (showing latest ", maxExpandedMessages, ")"] }) })), _jsx(Static, { items: staticMessages, children: (message, key) => {
|
|
34
28
|
// Get previous message
|
|
35
|
-
const previousMessage =
|
|
36
|
-
return
|
|
37
|
-
}
|
|
38
|
-
|
|
29
|
+
const previousMessage = key > 0 ? staticMessages[key - 1] : undefined;
|
|
30
|
+
return (_jsx(MessageItem, { message: message, shouldShowHeader: previousMessage?.role !== message.role, isExpanded: isExpanded, isStatic: true }, key));
|
|
31
|
+
} }), dynamicMessages.map((message, index) => {
|
|
32
|
+
const messageIndex = staticMessages.length + index;
|
|
33
|
+
const previousMessage = messageIndex > 0 ? displayMessages[messageIndex - 1] : undefined;
|
|
34
|
+
return (_jsx(Box, { marginTop: -1, children: _jsx(MessageItem, { message: message, shouldShowHeader: previousMessage?.role !== message.role, isExpanded: isExpanded, isStatic: false }) }, `dynamic-${index}`));
|
|
35
|
+
}), (isLoading || isCommandRunning || isCompressing) && (_jsxs(Box, { flexDirection: "column", gap: 1, children: [isLoading && (_jsxs(Box, { children: [_jsx(Text, { color: "yellow", children: "\uD83D\uDCAD AI is thinking... " }), _jsxs(Text, { color: "gray", dimColor: true, children: ["|", " "] }), _jsx(Text, { color: "red", bold: true, children: "Esc" }), _jsxs(Text, { color: "gray", dimColor: true, children: [" ", "to abort"] })] })), isCommandRunning && (_jsx(Text, { color: "blue", children: "\uD83D\uDE80 Command is running..." })), isCompressing && (_jsx(Text, { color: "magenta", children: "\uD83D\uDDDC\uFE0F Compressing message history..." }))] })), messages.length > 0 && (_jsx(Box, { children: _jsxs(Box, { justifyContent: "space-between", width: "100%", children: [_jsx(Box, { children: _jsxs(Text, { color: "gray", children: ["Messages ", messages.length, latestTotalTokens > 0 && (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "gray", dimColor: true, children: [" ", "|", " "] }), _jsx(Text, { color: "blue", bold: true, children: latestTotalTokens.toLocaleString() }), _jsxs(Text, { color: "gray", dimColor: true, children: [" ", "tokens"] })] }))] }) }), _jsxs(Text, { color: "gray", dimColor: true, children: [_jsx(Text, { color: "cyan", children: "Ctrl+O" }), " Toggle", " ", isExpanded ? "Collapse" : "Expand"] })] }) }))] }));
|
|
36
|
+
});
|
|
37
|
+
// Add display name for debugging
|
|
38
|
+
MessageList.displayName = "MessageList";
|
|
@@ -2,7 +2,6 @@ import React from "react";
|
|
|
2
2
|
import type { SubagentBlock as SubagentBlockType } from "wave-agent-sdk";
|
|
3
3
|
interface SubagentBlockProps {
|
|
4
4
|
block: SubagentBlockType;
|
|
5
|
-
isExpanded?: boolean;
|
|
6
5
|
}
|
|
7
6
|
export declare const SubagentBlock: React.FC<SubagentBlockProps>;
|
|
8
7
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubagentBlock.d.ts","sourceRoot":"","sources":["../../src/components/SubagentBlock.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"SubagentBlock.d.ts","sourceRoot":"","sources":["../../src/components/SubagentBlock.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,aAAa,IAAI,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGzE,UAAU,kBAAkB;IAC1B,KAAK,EAAE,iBAAiB,CAAC;CAC1B;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAoGtD,CAAC"}
|
|
@@ -1,29 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
-
import {
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return text;
|
|
9
|
-
}
|
|
10
|
-
return lines.slice(0, maxLines).join("\n") + "\n...";
|
|
11
|
-
};
|
|
12
|
-
switch (block.type) {
|
|
13
|
-
case "text": {
|
|
14
|
-
const maxLines = isExpanded ? 50 : 10;
|
|
15
|
-
const truncatedContent = truncateText(block.content, maxLines);
|
|
16
|
-
return _jsx(Text, { children: truncatedContent });
|
|
17
|
-
}
|
|
18
|
-
case "error":
|
|
19
|
-
return _jsxs(Text, { color: "red", children: ["\u274C Error: ", block.content] });
|
|
20
|
-
case "tool":
|
|
21
|
-
return _jsx(ToolResultDisplay, { block: block, isExpanded: isExpanded });
|
|
22
|
-
default:
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
export const SubagentBlock = ({ block, isExpanded = false, }) => {
|
|
3
|
+
import { useChat } from "../contexts/useChat.js";
|
|
4
|
+
export const SubagentBlock = ({ block }) => {
|
|
5
|
+
const { subagentMessages } = useChat();
|
|
6
|
+
// Get messages for this subagent from context
|
|
7
|
+
const messages = subagentMessages[block.subagentId] || [];
|
|
27
8
|
// Status indicator mapping
|
|
28
9
|
const getStatusIndicator = (status) => {
|
|
29
10
|
switch (status) {
|
|
@@ -40,9 +21,27 @@ export const SubagentBlock = ({ block, isExpanded = false, }) => {
|
|
|
40
21
|
}
|
|
41
22
|
};
|
|
42
23
|
const statusInfo = getStatusIndicator(block.status);
|
|
43
|
-
//
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
24
|
+
// Find the last 2 tool names and their compact params, and count total tools
|
|
25
|
+
const getLastTwoTools = () => {
|
|
26
|
+
const tools = [];
|
|
27
|
+
let totalToolCount = 0;
|
|
28
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
29
|
+
const message = messages[i];
|
|
30
|
+
for (let j = message.blocks.length - 1; j >= 0; j--) {
|
|
31
|
+
const messageBlock = message.blocks[j];
|
|
32
|
+
if (messageBlock.type === "tool" && messageBlock.name) {
|
|
33
|
+
totalToolCount++;
|
|
34
|
+
if (tools.length < 2) {
|
|
35
|
+
tools.push({
|
|
36
|
+
name: messageBlock.name,
|
|
37
|
+
compactParams: messageBlock.compactParams,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return { tools: tools.reverse(), totalToolCount }; // Reverse to show oldest first, newest last
|
|
44
|
+
};
|
|
45
|
+
const { tools: lastTwoTools, totalToolCount } = getLastTwoTools();
|
|
46
|
+
return (_jsxs(Box, { borderRight: false, borderTop: false, borderBottom: false, borderStyle: "classic", borderColor: "magenta", paddingX: 1, paddingY: 0, flexDirection: "column", marginBottom: 1, children: [_jsx(Box, { flexDirection: "row", gap: 1, children: _jsxs(Box, { flexDirection: "row", alignItems: "center", children: [_jsxs(Text, { color: "cyan", children: ["\uD83E\uDD16 ", block.subagentName] }), _jsxs(Text, { color: statusInfo.color, dimColor: false, children: [" ", statusInfo.icon] }), _jsxs(Text, { color: "gray", dimColor: true, children: [" ", "(", messages.length, " messages)"] })] }) }), lastTwoTools.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, gap: 1, children: [totalToolCount > 2 && (_jsx(Text, { color: "gray", dimColor: true, children: "..." })), lastTwoTools.map((tool, index) => (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: "magenta", children: "\uD83D\uDD27 " }), _jsx(Text, { color: "white", children: tool.name }), tool.compactParams && (_jsxs(Text, { color: "gray", children: [" ", tool.compactParams] }))] }, index)))] }))] }));
|
|
48
47
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
export const ToolResultDisplay = ({ block, isExpanded = false, }) => {
|
|
4
|
-
const { parameters, result, compactParams,
|
|
4
|
+
const { parameters, result, compactParams, stage, success, error, name } = block;
|
|
5
5
|
// Directly use compactParams
|
|
6
6
|
// (no change needed as we destructured it above)
|
|
7
7
|
const getStatusColor = () => {
|
|
8
|
-
if (
|
|
8
|
+
if (stage === "running")
|
|
9
9
|
return "yellow";
|
|
10
10
|
if (success)
|
|
11
11
|
return "green";
|
|
@@ -14,12 +14,12 @@ export const ToolResultDisplay = ({ block, isExpanded = false, }) => {
|
|
|
14
14
|
return "gray"; // Unknown state or no state information
|
|
15
15
|
};
|
|
16
16
|
const getStatusText = () => {
|
|
17
|
-
if (
|
|
17
|
+
if (stage === "running")
|
|
18
18
|
return "🔄";
|
|
19
19
|
if (success)
|
|
20
20
|
return "";
|
|
21
21
|
if (error || success === false)
|
|
22
|
-
return "❌
|
|
22
|
+
return "❌";
|
|
23
23
|
return ""; // Don't display text for unknown state
|
|
24
24
|
};
|
|
25
25
|
const hasImages = () => {
|
|
@@ -48,5 +48,5 @@ export const ToolResultDisplay = ({ block, isExpanded = false, }) => {
|
|
|
48
48
|
return null;
|
|
49
49
|
};
|
|
50
50
|
const shortResult = getShortResult();
|
|
51
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: "magenta", children: "\uD83D\uDD27 " }), _jsx(Text, { color: "white", children: toolName }), !isExpanded && compactParams && (_jsxs(Text, { color: "gray", children: ["
|
|
51
|
+
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: "magenta", children: "\uD83D\uDD27 " }), _jsx(Text, { color: "white", children: toolName }), !isExpanded && compactParams && (_jsxs(Text, { color: "gray", children: [" ", compactParams] })), _jsxs(Text, { color: getStatusColor(), children: [" ", getStatusText()] }), hasImages() && _jsxs(Text, { color: "blue", children: [" ", getImageIndicator()] })] }), !isExpanded && shortResult && !error && (_jsx(Box, { paddingLeft: 2, borderLeft: true, borderColor: "gray", flexDirection: "column", children: shortResult.split("\n").map((line, index) => (_jsx(Text, { color: "white", children: line }, index))) })), isExpanded && parameters && (_jsxs(Box, { paddingLeft: 2, borderLeft: true, borderColor: "gray", flexDirection: "column", children: [_jsx(Text, { color: "cyan", bold: true, children: "Parameters:" }), _jsx(Text, { color: "gray", children: parameters })] })), isExpanded && result && (_jsx(Box, { flexDirection: "column", children: _jsxs(Box, { paddingLeft: 2, borderLeft: true, borderColor: "green", flexDirection: "column", children: [_jsx(Text, { color: "cyan", bold: true, children: "Result:" }), _jsx(Text, { color: "white", children: result })] }) })), error && (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["Error: ", typeof error === "string" ? error : String(error)] }) }))] }));
|
|
52
52
|
};
|