wave-code 0.0.5 → 0.0.8
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 +3 -3
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/components/App.d.ts +1 -0
- package/dist/components/App.d.ts.map +1 -1
- package/dist/components/App.js +4 -4
- package/dist/components/BashHistorySelector.d.ts.map +1 -1
- package/dist/components/BashHistorySelector.js +17 -3
- package/dist/components/ChatInterface.d.ts.map +1 -1
- package/dist/components/ChatInterface.js +6 -24
- package/dist/components/CommandSelector.js +4 -4
- package/dist/components/Confirmation.d.ts +11 -0
- package/dist/components/Confirmation.d.ts.map +1 -0
- package/dist/components/Confirmation.js +148 -0
- package/dist/components/DiffDisplay.d.ts +8 -0
- package/dist/components/DiffDisplay.d.ts.map +1 -0
- package/dist/components/DiffDisplay.js +168 -0
- package/dist/components/FileSelector.d.ts +2 -4
- package/dist/components/FileSelector.d.ts.map +1 -1
- package/dist/components/FileSelector.js +2 -2
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +30 -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/MemoryDisplay.js +1 -1
- package/dist/components/MessageItem.d.ts +8 -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/ReasoningDisplay.d.ts +8 -0
- package/dist/components/ReasoningDisplay.d.ts.map +1 -0
- package/dist/components/ReasoningDisplay.js +10 -0
- 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.d.ts.map +1 -1
- package/dist/components/ToolResultDisplay.js +6 -5
- package/dist/contexts/useChat.d.ts +14 -2
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +128 -17
- package/dist/hooks/useInputManager.d.ts +6 -1
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +32 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -5
- package/dist/managers/InputManager.d.ts +11 -1
- package/dist/managers/InputManager.d.ts.map +1 -1
- package/dist/managers/InputManager.js +77 -26
- package/dist/print-cli.d.ts +2 -0
- package/dist/print-cli.d.ts.map +1 -1
- package/dist/print-cli.js +121 -23
- package/dist/utils/toolParameterTransforms.d.ts +23 -0
- package/dist/utils/toolParameterTransforms.d.ts.map +1 -0
- package/dist/utils/toolParameterTransforms.js +77 -0
- 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 +13 -8
- package/src/cli.tsx +3 -1
- package/src/components/App.tsx +7 -3
- package/src/components/BashHistorySelector.tsx +26 -3
- package/src/components/ChatInterface.tsx +38 -54
- package/src/components/CommandSelector.tsx +5 -5
- package/src/components/Confirmation.tsx +253 -0
- package/src/components/DiffDisplay.tsx +300 -0
- package/src/components/FileSelector.tsx +4 -6
- package/src/components/InputBox.tsx +58 -87
- package/src/components/Markdown.tsx +29 -0
- package/src/components/MemoryDisplay.tsx +1 -1
- package/src/components/MessageItem.tsx +96 -0
- package/src/components/MessageList.tsx +140 -202
- package/src/components/ReasoningDisplay.tsx +33 -0
- package/src/components/SubagentBlock.tsx +56 -84
- package/src/components/ToolResultDisplay.tsx +9 -5
- package/src/contexts/useChat.tsx +194 -21
- package/src/hooks/useInputManager.ts +40 -3
- package/src/index.ts +45 -5
- package/src/managers/InputManager.ts +101 -27
- package/src/print-cli.ts +143 -21
- package/src/utils/toolParameterTransforms.ts +104 -0
- package/src/utils/usageSummary.ts +109 -0
- package/dist/components/DiffViewer.d.ts +0 -9
- package/dist/components/DiffViewer.d.ts.map +0 -1
- package/dist/components/DiffViewer.js +0 -221
- package/dist/utils/fileSearch.d.ts +0 -20
- package/dist/utils/fileSearch.d.ts.map +0 -1
- package/dist/utils/fileSearch.js +0 -102
- package/src/components/DiffViewer.tsx +0 -321
- package/src/utils/fileSearch.ts +0 -133
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ This is the frontend UI package of the Wave workspace, providing an interactive
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
npm install wave-code
|
|
19
|
+
npm install wave-code -g
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
## Environment Configuration
|
|
@@ -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
|
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,UAAU;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,UAAU;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAwEjE"}
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { render } from "ink";
|
|
|
3
3
|
import { App } from "./components/App.js";
|
|
4
4
|
import { cleanupLogs } from "./utils/logger.js";
|
|
5
5
|
export async function startCli(options) {
|
|
6
|
-
const { restoreSessionId, continueLastSession } = options;
|
|
6
|
+
const { restoreSessionId, continueLastSession, bypassPermissions } = options;
|
|
7
7
|
// Continue with ink-based UI for normal mode
|
|
8
8
|
// Global cleanup tracker
|
|
9
9
|
let isCleaningUp = false;
|
|
@@ -45,7 +45,7 @@ export async function startCli(options) {
|
|
|
45
45
|
cleanup();
|
|
46
46
|
});
|
|
47
47
|
// Render the application
|
|
48
|
-
const { unmount } = render(_jsx(App, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession }));
|
|
48
|
+
const { unmount } = render(_jsx(App, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, bypassPermissions: bypassPermissions }));
|
|
49
49
|
// Store unmount function for cleanup when process exits normally
|
|
50
50
|
process.on("exit", () => {
|
|
51
51
|
if (!appUnmounted) {
|
package/dist/components/App.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/components/App.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,UAAU,QAAQ;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/components/App.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,UAAU,QAAQ;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAYD,eAAO,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CAalC,CAAC"}
|
package/dist/components/App.js
CHANGED
|
@@ -2,9 +2,9 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { ChatInterface } from "./ChatInterface.js";
|
|
3
3
|
import { ChatProvider } from "../contexts/useChat.js";
|
|
4
4
|
import { AppProvider } from "../contexts/useAppConfig.js";
|
|
5
|
-
const AppWithProviders = () => {
|
|
6
|
-
return (_jsx(ChatProvider, { children: _jsx(ChatInterface, {}) }));
|
|
5
|
+
const AppWithProviders = ({ bypassPermissions, }) => {
|
|
6
|
+
return (_jsx(ChatProvider, { bypassPermissions: bypassPermissions, children: _jsx(ChatInterface, {}) }));
|
|
7
7
|
};
|
|
8
|
-
export const App = ({ restoreSessionId, continueLastSession, }) => {
|
|
9
|
-
return (_jsx(AppProvider, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, children: _jsx(AppWithProviders, {}) }));
|
|
8
|
+
export const App = ({ restoreSessionId, continueLastSession, bypassPermissions, }) => {
|
|
9
|
+
return (_jsx(AppProvider, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, children: _jsx(AppWithProviders, { bypassPermissions: bypassPermissions }) }));
|
|
10
10
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BashHistorySelector.d.ts","sourceRoot":"","sources":["../../src/components/BashHistorySelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"BashHistorySelector.d.ts","sourceRoot":"","sources":["../../src/components/BashHistorySelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AASnD,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAwKlE,CAAC"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useEffect } from "react";
|
|
3
3
|
import { Box, Text, useInput } from "ink";
|
|
4
|
-
import { searchBashHistory } from "wave-agent-sdk";
|
|
4
|
+
import { searchBashHistory, deleteBashCommandFromHistory, } from "wave-agent-sdk";
|
|
5
5
|
import { logger } from "../utils/logger.js";
|
|
6
6
|
export const BashHistorySelector = ({ searchQuery, workdir, onSelect, onExecute, onCancel, }) => {
|
|
7
7
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
8
8
|
const [commands, setCommands] = useState([]);
|
|
9
|
+
const [refreshCounter, setRefreshCounter] = useState(0);
|
|
9
10
|
// Search bash history
|
|
10
11
|
useEffect(() => {
|
|
11
12
|
const results = searchBashHistory(searchQuery, 10, workdir);
|
|
@@ -15,8 +16,9 @@ export const BashHistorySelector = ({ searchQuery, workdir, onSelect, onExecute,
|
|
|
15
16
|
searchQuery,
|
|
16
17
|
workdir,
|
|
17
18
|
resultCount: results.length,
|
|
19
|
+
refreshCounter,
|
|
18
20
|
});
|
|
19
|
-
}, [searchQuery, workdir]);
|
|
21
|
+
}, [searchQuery, workdir, refreshCounter]);
|
|
20
22
|
useInput((input, key) => {
|
|
21
23
|
logger.debug("BashHistorySelector useInput:", {
|
|
22
24
|
input,
|
|
@@ -58,6 +60,18 @@ export const BashHistorySelector = ({ searchQuery, workdir, onSelect, onExecute,
|
|
|
58
60
|
setSelectedIndex(Math.min(commands.length - 1, selectedIndex + 1));
|
|
59
61
|
return;
|
|
60
62
|
}
|
|
63
|
+
if (key.delete) {
|
|
64
|
+
if (commands.length > 0 && selectedIndex < commands.length) {
|
|
65
|
+
const selectedCommand = commands[selectedIndex];
|
|
66
|
+
deleteBashCommandFromHistory(selectedCommand.command, selectedCommand.workdir);
|
|
67
|
+
setRefreshCounter((prev) => prev + 1);
|
|
68
|
+
// Adjust selectedIndex if we deleted the last item
|
|
69
|
+
if (selectedIndex >= commands.length - 1 && selectedIndex > 0) {
|
|
70
|
+
setSelectedIndex(selectedIndex - 1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
61
75
|
});
|
|
62
76
|
if (commands.length === 0) {
|
|
63
77
|
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", padding: 1, marginBottom: 1, children: [_jsxs(Text, { color: "yellow", children: ["No bash history found ", searchQuery && `for "${searchQuery}"`] }), searchQuery.trim() && (_jsxs(Text, { color: "green", children: ["Press Enter to execute: ", searchQuery] })), searchQuery.trim() && (_jsxs(Text, { color: "blue", children: ["Press Tab to insert: ", searchQuery] })), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] }));
|
|
@@ -79,5 +93,5 @@ export const BashHistorySelector = ({ searchQuery, workdir, onSelect, onExecute,
|
|
|
79
93
|
return diffMinutes > 0 ? `${diffMinutes}m ago` : "just now";
|
|
80
94
|
}
|
|
81
95
|
};
|
|
82
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "blue", padding: 1, gap: 1, marginBottom: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "blue", bold: true, children: ["Bash History ", searchQuery && `(filtering: "${searchQuery}")`] }) }), commands.map((cmd, index) => (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: index === selectedIndex ? "black" : "white", backgroundColor: index === selectedIndex ? "blue" : undefined, children: cmd.command }), index === selectedIndex && (_jsx(Box, { marginLeft: 4, flexDirection: "column", children: _jsxs(Text, { color: "gray", dimColor: true, children: [formatTimestamp(cmd.timestamp), cmd.workdir !== workdir && ` • in ${cmd.workdir}`] }) }))] }, index))), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "Use \u2191\u2193 to navigate, Enter to execute, Tab to insert, Escape to cancel" }) })] }));
|
|
96
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "blue", padding: 1, gap: 1, marginBottom: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "blue", bold: true, children: ["Bash History ", searchQuery && `(filtering: "${searchQuery}")`] }) }), commands.map((cmd, index) => (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: index === selectedIndex ? "black" : "white", backgroundColor: index === selectedIndex ? "blue" : undefined, children: cmd.command }), index === selectedIndex && (_jsx(Box, { marginLeft: 4, flexDirection: "column", children: _jsxs(Text, { color: "gray", dimColor: true, children: [formatTimestamp(cmd.timestamp), cmd.workdir !== workdir && ` • in ${cmd.workdir}`] }) }))] }, index))), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "Use \u2191\u2193 to navigate, Enter to execute, Tab to insert, Delete to remove, Escape to cancel" }) })] }));
|
|
83
97
|
};
|
|
@@ -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;AAO1B,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAgEjC,CAAC"}
|
|
@@ -1,31 +1,13 @@
|
|
|
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";
|
|
5
|
+
import { Confirmation } from "./Confirmation.js";
|
|
6
6
|
import { useChat } from "../contexts/useChat.js";
|
|
7
7
|
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
|
-
|
|
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 }))] }));
|
|
8
|
+
const { messages, isLoading, isCommandRunning, userInputHistory, isCompressing, sendMessage, abortMessage, saveMemory, mcpServers, connectMcpServer, disconnectMcpServer, isExpanded, sessionId, latestTotalTokens, slashCommands, hasSlashCommand, isConfirmationVisible, confirmingTool, handleConfirmationDecision, handleConfirmationCancel, } = useChat();
|
|
9
|
+
if (!sessionId)
|
|
10
|
+
return null;
|
|
11
|
+
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 &&
|
|
12
|
+
(isConfirmationVisible ? (_jsx(Confirmation, { toolName: confirmingTool.name, toolInput: confirmingTool.input, onDecision: handleConfirmationDecision, onCancel: handleConfirmationCancel, onAbort: abortMessage })) : (_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
13
|
};
|
|
@@ -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
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { PermissionDecision } from "wave-agent-sdk";
|
|
3
|
+
export interface ConfirmationProps {
|
|
4
|
+
toolName: string;
|
|
5
|
+
toolInput?: Record<string, unknown>;
|
|
6
|
+
onDecision: (decision: PermissionDecision) => void;
|
|
7
|
+
onCancel: () => void;
|
|
8
|
+
onAbort: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare const Confirmation: React.FC<ConfirmationProps>;
|
|
11
|
+
//# sourceMappingURL=Confirmation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Confirmation.d.ts","sourceRoot":"","sources":["../../src/components/Confirmation.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AA2BzD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,UAAU,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACnD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAQD,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAiNpD,CAAC"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { Box, Text, useInput } from "ink";
|
|
4
|
+
// Helper function to generate descriptive action text
|
|
5
|
+
const getActionDescription = (toolName, toolInput) => {
|
|
6
|
+
if (!toolInput) {
|
|
7
|
+
return "Execute operation";
|
|
8
|
+
}
|
|
9
|
+
switch (toolName) {
|
|
10
|
+
case "Bash":
|
|
11
|
+
return `Execute command: ${toolInput.command || "unknown command"}`;
|
|
12
|
+
case "Edit":
|
|
13
|
+
return `Edit file: ${toolInput.file_path || "unknown file"}`;
|
|
14
|
+
case "MultiEdit":
|
|
15
|
+
return `Edit multiple sections in: ${toolInput.file_path || "unknown file"}`;
|
|
16
|
+
case "Delete":
|
|
17
|
+
return `Delete file: ${toolInput.target_file || "unknown file"}`;
|
|
18
|
+
case "Write":
|
|
19
|
+
return `Write to file: ${toolInput.file_path || "unknown file"}`;
|
|
20
|
+
default:
|
|
21
|
+
return "Execute operation";
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
export const Confirmation = ({ toolName, toolInput, onDecision, onCancel, onAbort, }) => {
|
|
25
|
+
const [state, setState] = useState({
|
|
26
|
+
selectedOption: "allow",
|
|
27
|
+
alternativeText: "",
|
|
28
|
+
hasUserInput: false,
|
|
29
|
+
});
|
|
30
|
+
const getAutoOptionText = () => {
|
|
31
|
+
if (toolName === "Bash") {
|
|
32
|
+
return `Yes, and don't ask again for ${toolInput?.command || "this"} commands in this workdir`;
|
|
33
|
+
}
|
|
34
|
+
return "Yes, and auto-accept edits";
|
|
35
|
+
};
|
|
36
|
+
useInput((input, key) => {
|
|
37
|
+
// Handle ESC to cancel and abort
|
|
38
|
+
if (key.escape) {
|
|
39
|
+
onCancel();
|
|
40
|
+
onAbort();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Handle Enter to confirm selection
|
|
44
|
+
if (key.return) {
|
|
45
|
+
if (state.selectedOption === "allow") {
|
|
46
|
+
onDecision({ behavior: "allow" });
|
|
47
|
+
}
|
|
48
|
+
else if (state.selectedOption === "auto") {
|
|
49
|
+
if (toolName === "Bash") {
|
|
50
|
+
onDecision({
|
|
51
|
+
behavior: "allow",
|
|
52
|
+
newPermissionRule: `Bash(${toolInput?.command})`,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
onDecision({
|
|
57
|
+
behavior: "allow",
|
|
58
|
+
newPermissionMode: "acceptEdits",
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
// For alternative option, require text input
|
|
64
|
+
if (state.alternativeText.trim()) {
|
|
65
|
+
onDecision({
|
|
66
|
+
behavior: "deny",
|
|
67
|
+
message: state.alternativeText.trim(),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// Handle numeric keys for quick selection (only if not typing in alternative)
|
|
74
|
+
if (state.selectedOption !== "alternative" || !state.hasUserInput) {
|
|
75
|
+
if (input === "1") {
|
|
76
|
+
onDecision({ behavior: "allow" });
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (input === "2") {
|
|
80
|
+
if (toolName === "Bash") {
|
|
81
|
+
onDecision({
|
|
82
|
+
behavior: "allow",
|
|
83
|
+
newPermissionRule: `Bash(${toolInput?.command})`,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
onDecision({
|
|
88
|
+
behavior: "allow",
|
|
89
|
+
newPermissionMode: "acceptEdits",
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (input === "3") {
|
|
95
|
+
setState((prev) => ({ ...prev, selectedOption: "alternative" }));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Handle arrow keys for navigation
|
|
100
|
+
if (key.upArrow) {
|
|
101
|
+
setState((prev) => {
|
|
102
|
+
if (prev.selectedOption === "alternative")
|
|
103
|
+
return { ...prev, selectedOption: "auto" };
|
|
104
|
+
if (prev.selectedOption === "auto")
|
|
105
|
+
return { ...prev, selectedOption: "allow" };
|
|
106
|
+
return prev;
|
|
107
|
+
});
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (key.downArrow) {
|
|
111
|
+
setState((prev) => {
|
|
112
|
+
if (prev.selectedOption === "allow")
|
|
113
|
+
return { ...prev, selectedOption: "auto" };
|
|
114
|
+
if (prev.selectedOption === "auto")
|
|
115
|
+
return { ...prev, selectedOption: "alternative" };
|
|
116
|
+
return prev;
|
|
117
|
+
});
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
// Handle text input for alternative option
|
|
121
|
+
if (input && !key.ctrl && !key.meta && !("alt" in key && key.alt)) {
|
|
122
|
+
// Focus on alternative option when user starts typing
|
|
123
|
+
setState((prev) => ({
|
|
124
|
+
selectedOption: "alternative",
|
|
125
|
+
alternativeText: prev.alternativeText + input,
|
|
126
|
+
hasUserInput: true,
|
|
127
|
+
}));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
// Handle backspace and delete (same behavior - delete one character)
|
|
131
|
+
if (key.backspace || key.delete) {
|
|
132
|
+
setState((prev) => {
|
|
133
|
+
const newText = prev.alternativeText.slice(0, -1);
|
|
134
|
+
return {
|
|
135
|
+
...prev,
|
|
136
|
+
selectedOption: "alternative",
|
|
137
|
+
alternativeText: newText,
|
|
138
|
+
hasUserInput: newText.length > 0,
|
|
139
|
+
};
|
|
140
|
+
});
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
const placeholderText = "Type here to tell Wave what to do differently";
|
|
145
|
+
const showPlaceholder = state.selectedOption === "alternative" && !state.hasUserInput;
|
|
146
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", padding: 1, marginBottom: 1, children: [_jsxs(Text, { color: "yellow", bold: true, children: ["Tool: ", toolName] }), _jsx(Text, { color: "yellow", children: getActionDescription(toolName, toolInput) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { children: "Do you want to proceed?" }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Box, { children: _jsxs(Text, { color: state.selectedOption === "allow" ? "black" : "white", backgroundColor: state.selectedOption === "allow" ? "yellow" : undefined, bold: state.selectedOption === "allow", children: [state.selectedOption === "allow" ? "> " : " ", "1. Yes"] }) }, "allow-option"), _jsx(Box, { children: _jsxs(Text, { color: state.selectedOption === "auto" ? "black" : "white", backgroundColor: state.selectedOption === "auto" ? "yellow" : undefined, bold: state.selectedOption === "auto", children: [state.selectedOption === "auto" ? "> " : " ", "2.", " ", getAutoOptionText()] }) }, "auto-option"), _jsx(Box, { children: _jsxs(Text, { color: state.selectedOption === "alternative" ? "black" : "white", backgroundColor: state.selectedOption === "alternative" ? "yellow" : undefined, bold: state.selectedOption === "alternative", children: [state.selectedOption === "alternative" ? "> " : " ", "3.", " ", showPlaceholder ? (_jsx(Text, { color: "gray", dimColor: true, children: placeholderText })) : (_jsx(Text, { children: state.alternativeText ||
|
|
147
|
+
"Type here to tell Wave what to do differently" }))] }) }, "alternative-option")] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Use \u2191\u2193 or 1-3 to navigate \u2022 ESC to cancel" }) })] }));
|
|
148
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DiffDisplay.d.ts","sourceRoot":"","sources":["../../src/components/DiffDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAIvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,UAAU,gBAAgB;IACxB,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAiSlD,CAAC"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useMemo } from "react";
|
|
3
|
+
import { Box, Text } from "ink";
|
|
4
|
+
import { transformToolBlockToChanges } from "../utils/toolParameterTransforms.js";
|
|
5
|
+
import { diffLines, diffWords } from "diff";
|
|
6
|
+
export const DiffDisplay = ({ toolBlock }) => {
|
|
7
|
+
const showDiff = ["running", "end"].includes(toolBlock.stage) &&
|
|
8
|
+
toolBlock.name &&
|
|
9
|
+
["Write", "Edit", "MultiEdit"].includes(toolBlock.name);
|
|
10
|
+
// Diff detection and transformation using typed parameters
|
|
11
|
+
const changes = useMemo(() => {
|
|
12
|
+
if (!showDiff || !toolBlock.name || !toolBlock.parameters)
|
|
13
|
+
return [];
|
|
14
|
+
try {
|
|
15
|
+
// Use local transformation with JSON parsing and type guards
|
|
16
|
+
return transformToolBlockToChanges(toolBlock.name, toolBlock.parameters);
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
console.warn("Error transforming tool block to changes:", error);
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
}, [toolBlock.name, toolBlock.parameters, showDiff]);
|
|
23
|
+
// Render word-level diff between two lines of text
|
|
24
|
+
const renderWordLevelDiff = (oldLine, newLine, keyPrefix) => {
|
|
25
|
+
try {
|
|
26
|
+
const changes = diffWords(oldLine, newLine);
|
|
27
|
+
const removedParts = [];
|
|
28
|
+
const addedParts = [];
|
|
29
|
+
changes.forEach((part, index) => {
|
|
30
|
+
if (part.removed) {
|
|
31
|
+
removedParts.push(_jsx(Text, { color: "black", backgroundColor: "red", children: part.value }, `removed-${keyPrefix}-${index}`));
|
|
32
|
+
}
|
|
33
|
+
else if (part.added) {
|
|
34
|
+
addedParts.push(_jsx(Text, { color: "black", backgroundColor: "green", children: part.value }, `added-${keyPrefix}-${index}`));
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// Unchanged parts
|
|
38
|
+
removedParts.push(_jsx(Text, { color: "red", children: part.value }, `removed-unchanged-${keyPrefix}-${index}`));
|
|
39
|
+
addedParts.push(_jsx(Text, { color: "green", children: part.value }, `added-unchanged-${keyPrefix}-${index}`));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return { removedParts, addedParts };
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.warn("Error rendering word-level diff:", error);
|
|
46
|
+
// Fallback to simple line display
|
|
47
|
+
return {
|
|
48
|
+
removedParts: [
|
|
49
|
+
_jsx(Text, { color: "red", children: oldLine }, `fallback-removed-${keyPrefix}`),
|
|
50
|
+
],
|
|
51
|
+
addedParts: [
|
|
52
|
+
_jsx(Text, { color: "green", children: newLine }, `fallback-added-${keyPrefix}`),
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
// Render expanded diff display using word-level diff for all changes
|
|
58
|
+
const renderExpandedDiff = () => {
|
|
59
|
+
try {
|
|
60
|
+
if (changes.length === 0)
|
|
61
|
+
return null;
|
|
62
|
+
return (_jsx(Box, { flexDirection: "column", children: changes.map((change, changeIndex) => {
|
|
63
|
+
try {
|
|
64
|
+
// Get line-level diff to understand the structure
|
|
65
|
+
const lineDiffs = diffLines(change.oldContent || "", change.newContent || "");
|
|
66
|
+
const diffElements = [];
|
|
67
|
+
// Process line diffs and apply word-level diff to changed lines
|
|
68
|
+
lineDiffs.forEach((part, partIndex) => {
|
|
69
|
+
if (part.added) {
|
|
70
|
+
const lines = part.value
|
|
71
|
+
.split("\n")
|
|
72
|
+
.filter((line) => line !== "");
|
|
73
|
+
lines.forEach((line, lineIndex) => {
|
|
74
|
+
diffElements.push(_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: "green", children: "+" }), _jsx(Text, { color: "green", children: line })] }, `add-${changeIndex}-${partIndex}-${lineIndex}`));
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
else if (part.removed) {
|
|
78
|
+
const lines = part.value
|
|
79
|
+
.split("\n")
|
|
80
|
+
.filter((line) => line !== "");
|
|
81
|
+
lines.forEach((line, lineIndex) => {
|
|
82
|
+
diffElements.push(_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: "red", children: "-" }), _jsx(Text, { color: "red", children: line })] }, `remove-${changeIndex}-${partIndex}-${lineIndex}`));
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Context lines - show unchanged content
|
|
87
|
+
const lines = part.value
|
|
88
|
+
.split("\n")
|
|
89
|
+
.filter((line) => line !== "");
|
|
90
|
+
lines.forEach((line, lineIndex) => {
|
|
91
|
+
diffElements.push(_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: "white", children: " " }), _jsx(Text, { color: "white", children: line })] }, `context-${changeIndex}-${partIndex}-${lineIndex}`));
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
// Now look for pairs of removed/added lines that can be word-diffed
|
|
96
|
+
const processedElements = [];
|
|
97
|
+
let i = 0;
|
|
98
|
+
while (i < diffElements.length) {
|
|
99
|
+
const current = diffElements[i];
|
|
100
|
+
const next = i + 1 < diffElements.length ? diffElements[i + 1] : null;
|
|
101
|
+
// Check if we have a removed line followed by an added line
|
|
102
|
+
const currentKey = React.isValidElement(current)
|
|
103
|
+
? current.key
|
|
104
|
+
: "";
|
|
105
|
+
const nextKey = React.isValidElement(next) ? next.key : "";
|
|
106
|
+
const isCurrentRemoved = typeof currentKey === "string" &&
|
|
107
|
+
currentKey.includes("remove-");
|
|
108
|
+
const isNextAdded = typeof nextKey === "string" && nextKey.includes("add-");
|
|
109
|
+
if (isCurrentRemoved &&
|
|
110
|
+
isNextAdded &&
|
|
111
|
+
React.isValidElement(current) &&
|
|
112
|
+
React.isValidElement(next)) {
|
|
113
|
+
// Extract the text content from the removed and added lines
|
|
114
|
+
const removedText = extractTextFromElement(current);
|
|
115
|
+
const addedText = extractTextFromElement(next);
|
|
116
|
+
if (removedText && addedText) {
|
|
117
|
+
// Apply word-level diff
|
|
118
|
+
const { removedParts, addedParts } = renderWordLevelDiff(removedText, addedText, `word-${changeIndex}-${i}`);
|
|
119
|
+
processedElements.push(_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: "red", children: "-" }), removedParts] }, `word-diff-removed-${changeIndex}-${i}`));
|
|
120
|
+
processedElements.push(_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: "green", children: "+" }), addedParts] }, `word-diff-added-${changeIndex}-${i}`));
|
|
121
|
+
i += 2; // Skip the next element since we processed it
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
// Fallback to original elements
|
|
125
|
+
processedElements.push(current);
|
|
126
|
+
i += 1;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
processedElements.push(current);
|
|
131
|
+
i += 1;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return (_jsx(Box, { flexDirection: "column", children: processedElements }, changeIndex));
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
console.warn(`Error rendering diff for change ${changeIndex}:`, error);
|
|
138
|
+
// Fallback to simple display
|
|
139
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: "red", children: ["-", change.oldContent || ""] }), _jsxs(Text, { color: "green", children: ["+", change.newContent || ""] })] }, changeIndex));
|
|
140
|
+
}
|
|
141
|
+
}) }));
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
console.warn("Error rendering expanded diff:", error);
|
|
145
|
+
return (_jsx(Box, { children: _jsx(Text, { color: "gray", children: "Error rendering diff display" }) }));
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
// Helper function to extract text content from a React element
|
|
149
|
+
const extractTextFromElement = (element) => {
|
|
150
|
+
if (!React.isValidElement(element))
|
|
151
|
+
return null;
|
|
152
|
+
// Navigate through Box -> Text structure
|
|
153
|
+
const children = element.props.children;
|
|
154
|
+
if (Array.isArray(children) && children.length >= 2) {
|
|
155
|
+
const textElement = children[1]; // Second child should be the Text with content
|
|
156
|
+
if (React.isValidElement(textElement) &&
|
|
157
|
+
textElement.props.children) {
|
|
158
|
+
return textElement.props.children;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return null;
|
|
162
|
+
};
|
|
163
|
+
// Don't render anything if no diff should be shown
|
|
164
|
+
if (!showDiff) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
return (_jsx(Box, { flexDirection: "column", children: _jsxs(Box, { paddingLeft: 2, borderLeft: true, borderColor: "cyan", flexDirection: "column", children: [_jsx(Text, { color: "cyan", bold: true, children: "Diff:" }), renderExpandedDiff()] }) }));
|
|
168
|
+
};
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
type: "file" | "directory";
|
|
5
|
-
}
|
|
2
|
+
import type { FileItem } from "wave-agent-sdk";
|
|
3
|
+
export { type FileItem } from "wave-agent-sdk";
|
|
6
4
|
export interface FileSelectorProps {
|
|
7
5
|
files: FileItem[];
|
|
8
6
|
searchQuery: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileSelector.d.ts","sourceRoot":"","sources":["../../src/components/FileSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"FileSelector.d.ts","sourceRoot":"","sources":["../../src/components/FileSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAyHpD,CAAC"}
|
|
@@ -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;AAYlD,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,CAuM5C,CAAC"}
|