wave-code 0.0.16 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/commands/plugin/disable.d.ts +5 -0
- package/dist/commands/plugin/disable.d.ts.map +1 -0
- package/dist/commands/plugin/disable.js +21 -0
- package/dist/commands/plugin/enable.d.ts +5 -0
- package/dist/commands/plugin/enable.d.ts.map +1 -0
- package/dist/commands/plugin/enable.js +21 -0
- package/dist/commands/plugin/install.d.ts +5 -0
- package/dist/commands/plugin/install.d.ts.map +1 -0
- package/dist/commands/plugin/install.js +28 -0
- package/dist/commands/plugin/list.d.ts +2 -0
- package/dist/commands/plugin/list.d.ts.map +1 -0
- package/dist/commands/plugin/list.js +53 -0
- package/dist/commands/plugin/marketplace.d.ts +8 -0
- package/dist/commands/plugin/marketplace.d.ts.map +1 -0
- package/dist/commands/plugin/marketplace.js +73 -0
- 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 +1 -0
- package/dist/components/BashHistorySelector.d.ts.map +1 -1
- package/dist/components/BashHistorySelector.js +15 -5
- package/dist/components/BashShellManager.d.ts.map +1 -1
- package/dist/components/BashShellManager.js +4 -4
- package/dist/components/ChatInterface.d.ts.map +1 -1
- package/dist/components/ChatInterface.js +1 -2
- package/dist/components/CommandSelector.d.ts.map +1 -1
- package/dist/components/CommandSelector.js +2 -2
- package/dist/components/Confirmation.d.ts +1 -0
- package/dist/components/Confirmation.d.ts.map +1 -1
- package/dist/components/Confirmation.js +151 -48
- package/dist/components/DiffDisplay.d.ts +3 -2
- package/dist/components/DiffDisplay.d.ts.map +1 -1
- package/dist/components/DiffDisplay.js +87 -82
- 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 +2 -2
- package/dist/components/McpManager.d.ts.map +1 -1
- package/dist/components/McpManager.js +3 -3
- package/dist/components/MemoryTypeSelector.d.ts.map +1 -1
- package/dist/components/MemoryTypeSelector.js +1 -1
- package/dist/components/MessageList.js +1 -1
- package/dist/components/PlanDisplay.d.ts +8 -0
- package/dist/components/PlanDisplay.d.ts.map +1 -0
- package/dist/components/PlanDisplay.js +14 -0
- package/dist/components/ToolResultDisplay.d.ts.map +1 -1
- package/dist/components/ToolResultDisplay.js +1 -1
- package/dist/contexts/useChat.d.ts +1 -0
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +3 -1
- package/dist/hooks/useInputManager.d.ts +1 -0
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +103 -0
- package/dist/managers/InputManager.d.ts +1 -0
- package/dist/managers/InputManager.d.ts.map +1 -1
- package/dist/managers/InputManager.js +7 -2
- package/dist/print-cli.d.ts +1 -0
- package/dist/print-cli.d.ts.map +1 -1
- package/dist/print-cli.js +2 -1
- package/package.json +2 -2
- package/src/cli.tsx +8 -1
- package/src/commands/plugin/disable.ts +31 -0
- package/src/commands/plugin/enable.ts +31 -0
- package/src/commands/plugin/install.ts +42 -0
- package/src/commands/plugin/list.ts +64 -0
- package/src/commands/plugin/marketplace.ts +72 -0
- package/src/components/App.tsx +11 -5
- package/src/components/BashHistorySelector.tsx +25 -7
- package/src/components/BashShellManager.tsx +16 -8
- package/src/components/ChatInterface.tsx +29 -27
- package/src/components/CommandSelector.tsx +8 -4
- package/src/components/Confirmation.tsx +312 -106
- package/src/components/DiffDisplay.tsx +167 -149
- package/src/components/FileSelector.tsx +8 -4
- package/src/components/InputBox.tsx +14 -4
- package/src/components/McpManager.tsx +12 -6
- package/src/components/MemoryTypeSelector.tsx +4 -2
- package/src/components/MessageList.tsx +1 -1
- package/src/components/PlanDisplay.tsx +46 -0
- package/src/components/ToolResultDisplay.tsx +4 -2
- package/src/contexts/useChat.tsx +4 -0
- package/src/hooks/useInputManager.ts +8 -0
- package/src/index.ts +178 -0
- package/src/managers/InputManager.ts +12 -1
- package/src/print-cli.ts +3 -0
|
@@ -1,30 +1,44 @@
|
|
|
1
1
|
import React, { useMemo } from "react";
|
|
2
|
-
import { Box, Text } from "ink";
|
|
2
|
+
import { Box, Text, useStdout } from "ink";
|
|
3
|
+
import {
|
|
4
|
+
WRITE_TOOL_NAME,
|
|
5
|
+
EDIT_TOOL_NAME,
|
|
6
|
+
MULTI_EDIT_TOOL_NAME,
|
|
7
|
+
} from "wave-agent-sdk";
|
|
3
8
|
import { transformToolBlockToChanges } from "../utils/toolParameterTransforms.js";
|
|
4
9
|
import { diffLines, diffWords } from "diff";
|
|
5
|
-
import type { ToolBlock } from "wave-agent-sdk";
|
|
6
10
|
|
|
7
11
|
interface DiffDisplayProps {
|
|
8
|
-
|
|
12
|
+
toolName?: string;
|
|
13
|
+
parameters?: string;
|
|
14
|
+
isExpanded?: boolean;
|
|
9
15
|
}
|
|
10
16
|
|
|
11
|
-
export const DiffDisplay: React.FC<DiffDisplayProps> = ({
|
|
17
|
+
export const DiffDisplay: React.FC<DiffDisplayProps> = ({
|
|
18
|
+
toolName,
|
|
19
|
+
parameters,
|
|
20
|
+
isExpanded = false,
|
|
21
|
+
}) => {
|
|
22
|
+
const { stdout } = useStdout();
|
|
23
|
+
const maxHeight = useMemo(() => {
|
|
24
|
+
return Math.max(5, (stdout?.rows || 24) - 20);
|
|
25
|
+
}, [stdout?.rows]);
|
|
26
|
+
|
|
12
27
|
const showDiff =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
["Write", "Edit", "MultiEdit"].includes(toolBlock.name);
|
|
28
|
+
toolName &&
|
|
29
|
+
[WRITE_TOOL_NAME, EDIT_TOOL_NAME, MULTI_EDIT_TOOL_NAME].includes(toolName);
|
|
16
30
|
|
|
17
31
|
// Diff detection and transformation using typed parameters
|
|
18
32
|
const changes = useMemo(() => {
|
|
19
|
-
if (!showDiff || !
|
|
33
|
+
if (!showDiff || !toolName || !parameters) return [];
|
|
20
34
|
try {
|
|
21
35
|
// Use local transformation with JSON parsing and type guards
|
|
22
|
-
return transformToolBlockToChanges(
|
|
36
|
+
return transformToolBlockToChanges(toolName, parameters);
|
|
23
37
|
} catch (error) {
|
|
24
38
|
console.warn("Error transforming tool block to changes:", error);
|
|
25
39
|
return [];
|
|
26
40
|
}
|
|
27
|
-
}, [
|
|
41
|
+
}, [toolName, parameters, showDiff]);
|
|
28
42
|
|
|
29
43
|
// Render word-level diff between two lines of text
|
|
30
44
|
const renderWordLevelDiff = (
|
|
@@ -98,158 +112,162 @@ export const DiffDisplay: React.FC<DiffDisplayProps> = ({ toolBlock }) => {
|
|
|
98
112
|
try {
|
|
99
113
|
if (changes.length === 0) return null;
|
|
100
114
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
115
|
+
const allElements: React.ReactNode[] = [];
|
|
116
|
+
|
|
117
|
+
changes.forEach((change, changeIndex) => {
|
|
118
|
+
try {
|
|
119
|
+
// Get line-level diff to understand the structure
|
|
120
|
+
const lineDiffs = diffLines(
|
|
121
|
+
change.oldContent || "",
|
|
122
|
+
change.newContent || "",
|
|
123
|
+
);
|
|
110
124
|
|
|
111
|
-
|
|
125
|
+
const diffElements: React.ReactNode[] = [];
|
|
112
126
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
});
|
|
130
|
-
} else if (part.removed) {
|
|
131
|
-
const lines = part.value
|
|
132
|
-
.split("\n")
|
|
133
|
-
.filter((line) => line !== "");
|
|
134
|
-
lines.forEach((line, lineIndex) => {
|
|
135
|
-
diffElements.push(
|
|
136
|
-
<Box
|
|
137
|
-
key={`remove-${changeIndex}-${partIndex}-${lineIndex}`}
|
|
138
|
-
flexDirection="row"
|
|
139
|
-
>
|
|
140
|
-
<Text color="red">-</Text>
|
|
141
|
-
<Text color="red">{line}</Text>
|
|
142
|
-
</Box>,
|
|
143
|
-
);
|
|
144
|
-
});
|
|
145
|
-
} else {
|
|
146
|
-
// Context lines - show unchanged content
|
|
147
|
-
const lines = part.value
|
|
148
|
-
.split("\n")
|
|
149
|
-
.filter((line) => line !== "");
|
|
150
|
-
lines.forEach((line, lineIndex) => {
|
|
151
|
-
diffElements.push(
|
|
152
|
-
<Box
|
|
153
|
-
key={`context-${changeIndex}-${partIndex}-${lineIndex}`}
|
|
154
|
-
flexDirection="row"
|
|
155
|
-
>
|
|
156
|
-
<Text color="white"> </Text>
|
|
157
|
-
<Text color="white">{line}</Text>
|
|
158
|
-
</Box>,
|
|
159
|
-
);
|
|
160
|
-
});
|
|
161
|
-
}
|
|
127
|
+
// Process line diffs and apply word-level diff to changed lines
|
|
128
|
+
lineDiffs.forEach((part, partIndex) => {
|
|
129
|
+
if (part.added) {
|
|
130
|
+
const lines = part.value
|
|
131
|
+
.split("\n")
|
|
132
|
+
.filter((line) => line !== "");
|
|
133
|
+
lines.forEach((line, lineIndex) => {
|
|
134
|
+
diffElements.push(
|
|
135
|
+
<Box
|
|
136
|
+
key={`add-${changeIndex}-${partIndex}-${lineIndex}`}
|
|
137
|
+
flexDirection="row"
|
|
138
|
+
>
|
|
139
|
+
<Text color="green">+</Text>
|
|
140
|
+
<Text color="green">{line}</Text>
|
|
141
|
+
</Box>,
|
|
142
|
+
);
|
|
162
143
|
});
|
|
144
|
+
} else if (part.removed) {
|
|
145
|
+
const lines = part.value
|
|
146
|
+
.split("\n")
|
|
147
|
+
.filter((line) => line !== "");
|
|
148
|
+
lines.forEach((line, lineIndex) => {
|
|
149
|
+
diffElements.push(
|
|
150
|
+
<Box
|
|
151
|
+
key={`remove-${changeIndex}-${partIndex}-${lineIndex}`}
|
|
152
|
+
flexDirection="row"
|
|
153
|
+
>
|
|
154
|
+
<Text color="red">-</Text>
|
|
155
|
+
<Text color="red">{line}</Text>
|
|
156
|
+
</Box>,
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
} else {
|
|
160
|
+
// Context lines - show unchanged content
|
|
161
|
+
const lines = part.value
|
|
162
|
+
.split("\n")
|
|
163
|
+
.filter((line) => line !== "");
|
|
164
|
+
lines.forEach((line, lineIndex) => {
|
|
165
|
+
diffElements.push(
|
|
166
|
+
<Box
|
|
167
|
+
key={`context-${changeIndex}-${partIndex}-${lineIndex}`}
|
|
168
|
+
flexDirection="row"
|
|
169
|
+
>
|
|
170
|
+
<Text color="white"> </Text>
|
|
171
|
+
<Text color="white">{line}</Text>
|
|
172
|
+
</Box>,
|
|
173
|
+
);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
});
|
|
163
177
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
let i = 0;
|
|
178
|
+
// Now look for pairs of removed/added lines that can be word-diffed
|
|
179
|
+
let i = 0;
|
|
167
180
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
181
|
+
while (i < diffElements.length) {
|
|
182
|
+
const current = diffElements[i];
|
|
183
|
+
const next =
|
|
184
|
+
i + 1 < diffElements.length ? diffElements[i + 1] : null;
|
|
172
185
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
: "";
|
|
177
|
-
const nextKey = React.isValidElement(next) ? next.key : "";
|
|
186
|
+
// Check if we have a removed line followed by an added line
|
|
187
|
+
const currentKey = React.isValidElement(current) ? current.key : "";
|
|
188
|
+
const nextKey = React.isValidElement(next) ? next.key : "";
|
|
178
189
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
typeof nextKey === "string" && nextKey.includes("add-");
|
|
190
|
+
const isCurrentRemoved =
|
|
191
|
+
typeof currentKey === "string" && currentKey.includes("remove-");
|
|
192
|
+
const isNextAdded =
|
|
193
|
+
typeof nextKey === "string" && nextKey.includes("add-");
|
|
184
194
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
195
|
+
if (
|
|
196
|
+
isCurrentRemoved &&
|
|
197
|
+
isNextAdded &&
|
|
198
|
+
React.isValidElement(current) &&
|
|
199
|
+
React.isValidElement(next)
|
|
200
|
+
) {
|
|
201
|
+
// Extract the text content from the removed and added lines
|
|
202
|
+
const removedText = extractTextFromElement(current);
|
|
203
|
+
const addedText = extractTextFromElement(next);
|
|
194
204
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
205
|
+
if (removedText && addedText) {
|
|
206
|
+
// Apply word-level diff
|
|
207
|
+
const { removedParts, addedParts } = renderWordLevelDiff(
|
|
208
|
+
removedText,
|
|
209
|
+
addedText,
|
|
210
|
+
`word-${changeIndex}-${i}`,
|
|
211
|
+
);
|
|
202
212
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
213
|
+
allElements.push(
|
|
214
|
+
<Box
|
|
215
|
+
key={`word-diff-removed-${changeIndex}-${i}`}
|
|
216
|
+
flexDirection="row"
|
|
217
|
+
>
|
|
218
|
+
<Text color="red">-</Text>
|
|
219
|
+
{removedParts}
|
|
220
|
+
</Box>,
|
|
221
|
+
);
|
|
222
|
+
allElements.push(
|
|
223
|
+
<Box
|
|
224
|
+
key={`word-diff-added-${changeIndex}-${i}`}
|
|
225
|
+
flexDirection="row"
|
|
226
|
+
>
|
|
227
|
+
<Text color="green">+</Text>
|
|
228
|
+
{addedParts}
|
|
229
|
+
</Box>,
|
|
230
|
+
);
|
|
221
231
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
} else {
|
|
229
|
-
processedElements.push(current);
|
|
230
|
-
i += 1;
|
|
231
|
-
}
|
|
232
|
+
i += 2; // Skip the next element since we processed it
|
|
233
|
+
} else {
|
|
234
|
+
// Fallback to original elements
|
|
235
|
+
allElements.push(current);
|
|
236
|
+
i += 1;
|
|
232
237
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
{processedElements}
|
|
237
|
-
</Box>
|
|
238
|
-
);
|
|
239
|
-
} catch (error) {
|
|
240
|
-
console.warn(
|
|
241
|
-
`Error rendering diff for change ${changeIndex}:`,
|
|
242
|
-
error,
|
|
243
|
-
);
|
|
244
|
-
// Fallback to simple display
|
|
245
|
-
return (
|
|
246
|
-
<Box key={changeIndex} flexDirection="column">
|
|
247
|
-
<Text color="red">-{change.oldContent || ""}</Text>
|
|
248
|
-
<Text color="green">+{change.newContent || ""}</Text>
|
|
249
|
-
</Box>
|
|
250
|
-
);
|
|
238
|
+
} else {
|
|
239
|
+
allElements.push(current);
|
|
240
|
+
i += 1;
|
|
251
241
|
}
|
|
252
|
-
}
|
|
242
|
+
}
|
|
243
|
+
} catch (error) {
|
|
244
|
+
console.warn(
|
|
245
|
+
`Error rendering diff for change ${changeIndex}:`,
|
|
246
|
+
error,
|
|
247
|
+
);
|
|
248
|
+
// Fallback to simple display
|
|
249
|
+
allElements.push(
|
|
250
|
+
<Box key={`fallback-${changeIndex}`} flexDirection="column">
|
|
251
|
+
<Text color="red">-{change.oldContent || ""}</Text>
|
|
252
|
+
<Text color="green">+{change.newContent || ""}</Text>
|
|
253
|
+
</Box>,
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
const isTruncated = !isExpanded && allElements.length > maxHeight;
|
|
259
|
+
const displayElements = isTruncated
|
|
260
|
+
? allElements.slice(0, maxHeight - 1)
|
|
261
|
+
: allElements;
|
|
262
|
+
|
|
263
|
+
return (
|
|
264
|
+
<Box flexDirection="column">
|
|
265
|
+
{displayElements}
|
|
266
|
+
{isTruncated && (
|
|
267
|
+
<Text color="yellow" dimColor>
|
|
268
|
+
... (truncated {allElements.length - (maxHeight - 1)} more lines)
|
|
269
|
+
</Text>
|
|
270
|
+
)}
|
|
253
271
|
</Box>
|
|
254
272
|
);
|
|
255
273
|
} catch (error) {
|
|
@@ -49,8 +49,10 @@ export const FileSelector: React.FC<FileSelectorProps> = ({
|
|
|
49
49
|
flexDirection="column"
|
|
50
50
|
borderStyle="single"
|
|
51
51
|
borderColor="yellow"
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
borderBottom={false}
|
|
53
|
+
borderLeft={false}
|
|
54
|
+
borderRight={false}
|
|
55
|
+
paddingTop={1}
|
|
54
56
|
>
|
|
55
57
|
<Text color="yellow">📁 No files found for "{searchQuery}"</Text>
|
|
56
58
|
<Text dimColor>Press Escape to cancel</Text>
|
|
@@ -86,8 +88,10 @@ export const FileSelector: React.FC<FileSelectorProps> = ({
|
|
|
86
88
|
flexDirection="column"
|
|
87
89
|
borderStyle="single"
|
|
88
90
|
borderColor="cyan"
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
borderBottom={false}
|
|
92
|
+
borderLeft={false}
|
|
93
|
+
borderRight={false}
|
|
94
|
+
paddingTop={1}
|
|
91
95
|
>
|
|
92
96
|
<Text color="cyan" bold>
|
|
93
97
|
📁 Select File/Directory{" "}
|
|
@@ -103,6 +103,7 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
103
103
|
setUserInputHistory,
|
|
104
104
|
// Complex handlers combining multiple operations
|
|
105
105
|
handleBashHistoryExecuteAndSend,
|
|
106
|
+
handleBashHistoryDelete,
|
|
106
107
|
// Main handler
|
|
107
108
|
handleInput,
|
|
108
109
|
// Manager ready state
|
|
@@ -188,6 +189,7 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
188
189
|
workdir={currentWorkdir}
|
|
189
190
|
onSelect={handleBashHistorySelect}
|
|
190
191
|
onExecute={handleBashHistoryExecuteAndSend}
|
|
192
|
+
onDelete={handleBashHistoryDelete}
|
|
191
193
|
onCancel={handleCancelBashHistorySelect}
|
|
192
194
|
/>
|
|
193
195
|
)}
|
|
@@ -214,7 +216,12 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
214
216
|
)}
|
|
215
217
|
{showBashManager || showMcpManager || (
|
|
216
218
|
<Box flexDirection="column">
|
|
217
|
-
<Box
|
|
219
|
+
<Box
|
|
220
|
+
borderStyle="single"
|
|
221
|
+
borderColor="gray"
|
|
222
|
+
borderLeft={false}
|
|
223
|
+
borderRight={false}
|
|
224
|
+
>
|
|
218
225
|
<Text color={isPlaceholder ? "gray" : "white"}>
|
|
219
226
|
{shouldShowCursor ? (
|
|
220
227
|
<>
|
|
@@ -229,10 +236,13 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
229
236
|
)}
|
|
230
237
|
</Text>
|
|
231
238
|
</Box>
|
|
232
|
-
<Box
|
|
239
|
+
<Box paddingRight={1}>
|
|
233
240
|
<Text color="gray">
|
|
234
|
-
Mode:
|
|
235
|
-
|
|
241
|
+
Mode:{" "}
|
|
242
|
+
<Text color={permissionMode === "plan" ? "yellow" : "cyan"}>
|
|
243
|
+
{permissionMode}
|
|
244
|
+
</Text>{" "}
|
|
245
|
+
(Shift+Tab to cycle)
|
|
236
246
|
</Text>
|
|
237
247
|
</Box>
|
|
238
248
|
</Box>
|
|
@@ -144,9 +144,11 @@ export const McpManager: React.FC<McpManagerProps> = ({
|
|
|
144
144
|
flexDirection="column"
|
|
145
145
|
borderStyle="single"
|
|
146
146
|
borderColor="cyan"
|
|
147
|
-
|
|
147
|
+
borderBottom={false}
|
|
148
|
+
borderLeft={false}
|
|
149
|
+
borderRight={false}
|
|
150
|
+
paddingTop={1}
|
|
148
151
|
gap={1}
|
|
149
|
-
marginBottom={1}
|
|
150
152
|
>
|
|
151
153
|
<Box>
|
|
152
154
|
<Text color="cyan" bold>
|
|
@@ -247,8 +249,10 @@ export const McpManager: React.FC<McpManagerProps> = ({
|
|
|
247
249
|
flexDirection="column"
|
|
248
250
|
borderStyle="single"
|
|
249
251
|
borderColor="cyan"
|
|
250
|
-
|
|
251
|
-
|
|
252
|
+
borderBottom={false}
|
|
253
|
+
borderLeft={false}
|
|
254
|
+
borderRight={false}
|
|
255
|
+
paddingTop={1}
|
|
252
256
|
>
|
|
253
257
|
<Text color="cyan" bold>
|
|
254
258
|
Manage MCP servers
|
|
@@ -267,9 +271,11 @@ export const McpManager: React.FC<McpManagerProps> = ({
|
|
|
267
271
|
flexDirection="column"
|
|
268
272
|
borderStyle="single"
|
|
269
273
|
borderColor="cyan"
|
|
270
|
-
|
|
274
|
+
borderBottom={false}
|
|
275
|
+
borderLeft={false}
|
|
276
|
+
borderRight={false}
|
|
277
|
+
paddingTop={1}
|
|
271
278
|
gap={1}
|
|
272
|
-
marginBottom={1}
|
|
273
279
|
>
|
|
274
280
|
<Box>
|
|
275
281
|
<Text color="cyan" bold>
|
|
@@ -55,9 +55,11 @@ export const MemoryTypeSelector: React.FC<MemoryTypeSelectorProps> = ({
|
|
|
55
55
|
flexDirection="column"
|
|
56
56
|
borderStyle="single"
|
|
57
57
|
borderColor="green"
|
|
58
|
-
|
|
58
|
+
borderBottom={false}
|
|
59
|
+
borderLeft={false}
|
|
60
|
+
borderRight={false}
|
|
61
|
+
paddingTop={1}
|
|
59
62
|
gap={1}
|
|
60
|
-
marginBottom={1}
|
|
61
63
|
>
|
|
62
64
|
<Box>
|
|
63
65
|
<Text color="green" bold>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
import { Box, Text, useStdout } from "ink";
|
|
3
|
+
import { Markdown } from "./Markdown.js";
|
|
4
|
+
|
|
5
|
+
interface PlanDisplayProps {
|
|
6
|
+
plan: string;
|
|
7
|
+
isExpanded?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const PlanDisplay: React.FC<PlanDisplayProps> = ({
|
|
11
|
+
plan,
|
|
12
|
+
isExpanded = false,
|
|
13
|
+
}) => {
|
|
14
|
+
const { stdout } = useStdout();
|
|
15
|
+
const maxHeight = useMemo(() => {
|
|
16
|
+
// Similar to DiffDisplay.tsx maxHeight calculation
|
|
17
|
+
return Math.max(5, (stdout?.rows || 24) - 20);
|
|
18
|
+
}, [stdout?.rows]);
|
|
19
|
+
|
|
20
|
+
const lines = useMemo(() => plan.split("\n"), [plan]);
|
|
21
|
+
const isOverflowing = !isExpanded && lines.length > maxHeight;
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Box flexDirection="column" marginTop={1}>
|
|
25
|
+
<Box paddingLeft={2} borderLeft borderColor="cyan" flexDirection="column">
|
|
26
|
+
<Text color="cyan" bold>
|
|
27
|
+
Plan Content:
|
|
28
|
+
</Text>
|
|
29
|
+
<Box
|
|
30
|
+
flexDirection="column"
|
|
31
|
+
height={isOverflowing ? maxHeight : undefined}
|
|
32
|
+
overflow="hidden"
|
|
33
|
+
>
|
|
34
|
+
<Markdown>{plan}</Markdown>
|
|
35
|
+
</Box>
|
|
36
|
+
{isOverflowing && (
|
|
37
|
+
<Box marginTop={1}>
|
|
38
|
+
<Text color="yellow" dimColor>
|
|
39
|
+
... (plan truncated, {lines.length} lines total)
|
|
40
|
+
</Text>
|
|
41
|
+
</Box>
|
|
42
|
+
)}
|
|
43
|
+
</Box>
|
|
44
|
+
</Box>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
@@ -135,8 +135,10 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
|
|
|
135
135
|
</Box>
|
|
136
136
|
)}
|
|
137
137
|
|
|
138
|
-
{/* Diff display -
|
|
139
|
-
|
|
138
|
+
{/* Diff display - only show after tool execution completes */}
|
|
139
|
+
{stage === "end" && (
|
|
140
|
+
<DiffDisplay toolName={name} parameters={parameters} />
|
|
141
|
+
)}
|
|
140
142
|
</Box>
|
|
141
143
|
);
|
|
142
144
|
};
|
package/src/contexts/useChat.tsx
CHANGED
|
@@ -93,11 +93,13 @@ export const useChat = () => {
|
|
|
93
93
|
export interface ChatProviderProps {
|
|
94
94
|
children: React.ReactNode;
|
|
95
95
|
bypassPermissions?: boolean;
|
|
96
|
+
pluginDirs?: string[];
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
99
100
|
children,
|
|
100
101
|
bypassPermissions,
|
|
102
|
+
pluginDirs,
|
|
101
103
|
}) => {
|
|
102
104
|
const { restoreSessionId, continueLastSession } = useAppConfig();
|
|
103
105
|
|
|
@@ -260,6 +262,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
260
262
|
permissionMode: bypassPermissions ? "bypassPermissions" : undefined,
|
|
261
263
|
canUseTool: permissionCallback,
|
|
262
264
|
stream: false, // 关闭流式模式
|
|
265
|
+
plugins: pluginDirs?.map((path) => ({ type: "local", path })),
|
|
263
266
|
});
|
|
264
267
|
|
|
265
268
|
agentRef.current = agent;
|
|
@@ -292,6 +295,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
292
295
|
continueLastSession,
|
|
293
296
|
bypassPermissions,
|
|
294
297
|
showConfirmation,
|
|
298
|
+
pluginDirs,
|
|
295
299
|
]);
|
|
296
300
|
|
|
297
301
|
// Cleanup on unmount
|
|
@@ -324,6 +324,13 @@ export const useInputManager = (
|
|
|
324
324
|
managerRef.current?.handleBashHistoryExecuteAndSend(command);
|
|
325
325
|
}, []);
|
|
326
326
|
|
|
327
|
+
const handleBashHistoryDelete = useCallback(
|
|
328
|
+
(command: string, workdir?: string) => {
|
|
329
|
+
managerRef.current?.handleBashHistoryDelete(command, workdir);
|
|
330
|
+
},
|
|
331
|
+
[],
|
|
332
|
+
);
|
|
333
|
+
|
|
327
334
|
return {
|
|
328
335
|
// State
|
|
329
336
|
inputText,
|
|
@@ -445,6 +452,7 @@ export const useInputManager = (
|
|
|
445
452
|
|
|
446
453
|
// Complex handlers combining multiple operations
|
|
447
454
|
handleBashHistoryExecuteAndSend,
|
|
455
|
+
handleBashHistoryDelete,
|
|
448
456
|
|
|
449
457
|
// Main input handler
|
|
450
458
|
handleInput: useCallback(
|