wave-code 0.5.0 → 0.6.0
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/components/BackgroundTaskManager.d.ts +6 -0
- package/dist/components/BackgroundTaskManager.d.ts.map +1 -0
- package/dist/components/{TaskManager.js → BackgroundTaskManager.js} +1 -1
- package/dist/components/ChatInterface.d.ts.map +1 -1
- package/dist/components/ChatInterface.js +55 -5
- package/dist/components/CommandSelector.d.ts.map +1 -1
- package/dist/components/CommandSelector.js +10 -2
- package/dist/components/CompressDisplay.d.ts.map +1 -1
- package/dist/components/CompressDisplay.js +6 -10
- package/dist/components/ConfirmationDetails.d.ts +9 -0
- package/dist/components/ConfirmationDetails.d.ts.map +1 -0
- package/dist/components/ConfirmationDetails.js +53 -0
- package/dist/components/{Confirmation.d.ts → ConfirmationSelector.d.ts} +3 -3
- package/dist/components/ConfirmationSelector.d.ts.map +1 -0
- package/dist/components/{Confirmation.js → ConfirmationSelector.js} +34 -96
- package/dist/components/DiffDisplay.d.ts.map +1 -1
- package/dist/components/DiffDisplay.js +44 -1
- package/dist/components/FileSelector.d.ts.map +1 -1
- package/dist/components/FileSelector.js +2 -2
- package/dist/components/HistorySearch.d.ts.map +1 -1
- package/dist/components/HistorySearch.js +12 -4
- package/dist/components/InputBox.d.ts +1 -2
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +5 -9
- package/dist/components/LoadingIndicator.d.ts +11 -0
- package/dist/components/LoadingIndicator.d.ts.map +1 -0
- package/dist/components/LoadingIndicator.js +6 -0
- package/dist/components/Markdown.d.ts.map +1 -1
- package/dist/components/Markdown.js +114 -121
- package/dist/components/MessageItem.d.ts.map +1 -1
- package/dist/components/MessageItem.js +1 -2
- package/dist/components/MessageList.d.ts +2 -3
- package/dist/components/MessageList.d.ts.map +1 -1
- package/dist/components/MessageList.js +7 -7
- package/dist/components/PlanDisplay.d.ts.map +1 -1
- package/dist/components/PlanDisplay.js +4 -12
- package/dist/components/SubagentBlock.d.ts.map +1 -1
- package/dist/components/SubagentBlock.js +9 -6
- package/dist/components/TaskList.d.ts +3 -0
- package/dist/components/TaskList.d.ts.map +1 -0
- package/dist/components/TaskList.js +49 -0
- package/dist/components/ToolResultDisplay.js +1 -1
- package/dist/contexts/useChat.d.ts +5 -2
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +25 -25
- package/dist/hooks/useInputManager.d.ts +2 -7
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +8 -40
- package/dist/hooks/useTasks.d.ts +2 -0
- package/dist/hooks/useTasks.d.ts.map +1 -0
- package/dist/hooks/useTasks.js +5 -0
- package/dist/managers/InputManager.d.ts +4 -19
- package/dist/managers/InputManager.d.ts.map +1 -1
- package/dist/managers/InputManager.js +22 -65
- package/package.json +5 -6
- package/src/components/{TaskManager.tsx → BackgroundTaskManager.tsx} +4 -2
- package/src/components/ChatInterface.tsx +100 -20
- package/src/components/CommandSelector.tsx +35 -17
- package/src/components/CompressDisplay.tsx +5 -22
- package/src/components/ConfirmationDetails.tsx +108 -0
- package/src/components/{Confirmation.tsx → ConfirmationSelector.tsx} +69 -184
- package/src/components/DiffDisplay.tsx +62 -1
- package/src/components/FileSelector.tsx +0 -2
- package/src/components/HistorySearch.tsx +45 -21
- package/src/components/InputBox.tsx +9 -24
- package/src/components/LoadingIndicator.tsx +56 -0
- package/src/components/Markdown.tsx +126 -323
- package/src/components/MessageItem.tsx +1 -3
- package/src/components/MessageList.tsx +10 -67
- package/src/components/PlanDisplay.tsx +4 -27
- package/src/components/SubagentBlock.tsx +25 -16
- package/src/components/TaskList.tsx +70 -0
- package/src/components/ToolResultDisplay.tsx +2 -2
- package/src/contexts/useChat.tsx +38 -33
- package/src/hooks/useInputManager.ts +9 -47
- package/src/hooks/useTasks.ts +6 -0
- package/src/managers/InputManager.ts +25 -83
- package/dist/components/Confirmation.d.ts.map +0 -1
- package/dist/components/MemoryDisplay.d.ts +0 -8
- package/dist/components/MemoryDisplay.d.ts.map +0 -1
- package/dist/components/MemoryDisplay.js +0 -25
- package/dist/components/MemoryTypeSelector.d.ts +0 -8
- package/dist/components/MemoryTypeSelector.d.ts.map +0 -1
- package/dist/components/MemoryTypeSelector.js +0 -38
- package/dist/components/TaskManager.d.ts +0 -6
- package/dist/components/TaskManager.d.ts.map +0 -1
- package/src/components/MemoryDisplay.tsx +0 -62
- package/src/components/MemoryTypeSelector.tsx +0 -98
|
@@ -3,44 +3,9 @@ import { Box, Text, useInput } from "ink";
|
|
|
3
3
|
import type { PermissionDecision, AskUserQuestionInput } from "wave-agent-sdk";
|
|
4
4
|
import {
|
|
5
5
|
BASH_TOOL_NAME,
|
|
6
|
-
EDIT_TOOL_NAME,
|
|
7
|
-
MULTI_EDIT_TOOL_NAME,
|
|
8
|
-
DELETE_FILE_TOOL_NAME,
|
|
9
|
-
WRITE_TOOL_NAME,
|
|
10
6
|
EXIT_PLAN_MODE_TOOL_NAME,
|
|
11
7
|
ASK_USER_QUESTION_TOOL_NAME,
|
|
12
8
|
} from "wave-agent-sdk";
|
|
13
|
-
import { DiffDisplay } from "./DiffDisplay.js";
|
|
14
|
-
import { PlanDisplay } from "./PlanDisplay.js";
|
|
15
|
-
|
|
16
|
-
// Helper function to generate descriptive action text
|
|
17
|
-
const getActionDescription = (
|
|
18
|
-
toolName: string,
|
|
19
|
-
toolInput?: Record<string, unknown>,
|
|
20
|
-
): string => {
|
|
21
|
-
if (!toolInput) {
|
|
22
|
-
return "Execute operation";
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
switch (toolName) {
|
|
26
|
-
case BASH_TOOL_NAME:
|
|
27
|
-
return `Execute command: ${toolInput.command || "unknown command"}`;
|
|
28
|
-
case EDIT_TOOL_NAME:
|
|
29
|
-
return `Edit file: ${toolInput.file_path || "unknown file"}`;
|
|
30
|
-
case MULTI_EDIT_TOOL_NAME:
|
|
31
|
-
return `Edit multiple sections in: ${toolInput.file_path || "unknown file"}`;
|
|
32
|
-
case DELETE_FILE_TOOL_NAME:
|
|
33
|
-
return `Delete file: ${toolInput.target_file || "unknown file"}`;
|
|
34
|
-
case WRITE_TOOL_NAME:
|
|
35
|
-
return `Write to file: ${toolInput.file_path || "unknown file"}`;
|
|
36
|
-
case EXIT_PLAN_MODE_TOOL_NAME:
|
|
37
|
-
return "Review and approve the plan";
|
|
38
|
-
case ASK_USER_QUESTION_TOOL_NAME:
|
|
39
|
-
return "Answer questions to clarify intent";
|
|
40
|
-
default:
|
|
41
|
-
return "Execute operation";
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
9
|
|
|
45
10
|
const getHeaderColor = (header: string) => {
|
|
46
11
|
const colors = ["red", "green", "blue", "magenta", "cyan"] as const;
|
|
@@ -51,7 +16,7 @@ const getHeaderColor = (header: string) => {
|
|
|
51
16
|
return colors[Math.abs(hash) % colors.length];
|
|
52
17
|
};
|
|
53
18
|
|
|
54
|
-
export interface
|
|
19
|
+
export interface ConfirmationSelectorProps {
|
|
55
20
|
toolName: string;
|
|
56
21
|
toolInput?: Record<string, unknown>;
|
|
57
22
|
suggestedPrefix?: string;
|
|
@@ -66,10 +31,10 @@ interface ConfirmationState {
|
|
|
66
31
|
selectedOption: "allow" | "auto" | "alternative";
|
|
67
32
|
alternativeText: string;
|
|
68
33
|
alternativeCursorPosition: number;
|
|
69
|
-
hasUserInput: boolean;
|
|
34
|
+
hasUserInput: boolean;
|
|
70
35
|
}
|
|
71
36
|
|
|
72
|
-
export const
|
|
37
|
+
export const ConfirmationSelector: React.FC<ConfirmationSelectorProps> = ({
|
|
73
38
|
toolName,
|
|
74
39
|
toolInput,
|
|
75
40
|
suggestedPrefix,
|
|
@@ -86,7 +51,6 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
86
51
|
hasUserInput: false,
|
|
87
52
|
});
|
|
88
53
|
|
|
89
|
-
// Specialized state for AskUserQuestion
|
|
90
54
|
const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
|
|
91
55
|
const [selectedOptionIndex, setSelectedOptionIndex] = useState(0);
|
|
92
56
|
const [selectedOptionIndices, setSelectedOptionIndices] = useState<
|
|
@@ -114,7 +78,6 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
114
78
|
};
|
|
115
79
|
|
|
116
80
|
useInput((input, key) => {
|
|
117
|
-
// Handle ESC to cancel and abort
|
|
118
81
|
if (key.escape) {
|
|
119
82
|
onCancel();
|
|
120
83
|
onAbort();
|
|
@@ -123,10 +86,8 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
123
86
|
|
|
124
87
|
if (toolName === ASK_USER_QUESTION_TOOL_NAME) {
|
|
125
88
|
if (!currentQuestion) return;
|
|
126
|
-
|
|
127
89
|
const options = [...currentQuestion.options, { label: "Other" }];
|
|
128
|
-
const isMultiSelect =
|
|
129
|
-
|
|
90
|
+
const isMultiSelect = currentQuestion.multiSelect;
|
|
130
91
|
const isOtherFocused = selectedOptionIndex === options.length - 1;
|
|
131
92
|
|
|
132
93
|
if (key.return) {
|
|
@@ -135,7 +96,6 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
135
96
|
const selectedLabels = Array.from(selectedOptionIndices)
|
|
136
97
|
.filter((i) => i < currentQuestion.options.length)
|
|
137
98
|
.map((i) => currentQuestion.options[i].label);
|
|
138
|
-
|
|
139
99
|
const isOtherChecked = selectedOptionIndices.has(options.length - 1);
|
|
140
100
|
if (isOtherChecked && otherText.trim()) {
|
|
141
101
|
selectedLabels.push(otherText.trim());
|
|
@@ -148,15 +108,12 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
148
108
|
answer = options[selectedOptionIndex].label;
|
|
149
109
|
}
|
|
150
110
|
}
|
|
151
|
-
|
|
152
111
|
if (!answer) return;
|
|
153
|
-
|
|
154
112
|
const newAnswers = {
|
|
155
113
|
...userAnswers,
|
|
156
114
|
[currentQuestion.question]: answer,
|
|
157
115
|
};
|
|
158
116
|
setUserAnswers(newAnswers);
|
|
159
|
-
|
|
160
117
|
if (currentQuestionIndex < questions.length - 1) {
|
|
161
118
|
setCurrentQuestionIndex(currentQuestionIndex + 1);
|
|
162
119
|
setSelectedOptionIndex(0);
|
|
@@ -164,7 +121,6 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
164
121
|
setOtherText("");
|
|
165
122
|
setOtherCursorPosition(0);
|
|
166
123
|
} else {
|
|
167
|
-
// All questions answered
|
|
168
124
|
onDecision({
|
|
169
125
|
behavior: "allow",
|
|
170
126
|
message: JSON.stringify(newAnswers),
|
|
@@ -180,33 +136,23 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
180
136
|
) {
|
|
181
137
|
setSelectedOptionIndices((prev) => {
|
|
182
138
|
const next = new Set(prev);
|
|
183
|
-
if (next.has(selectedOptionIndex))
|
|
184
|
-
|
|
185
|
-
} else {
|
|
186
|
-
next.add(selectedOptionIndex);
|
|
187
|
-
}
|
|
139
|
+
if (next.has(selectedOptionIndex)) next.delete(selectedOptionIndex);
|
|
140
|
+
else next.add(selectedOptionIndex);
|
|
188
141
|
return next;
|
|
189
142
|
});
|
|
190
143
|
return;
|
|
191
144
|
}
|
|
192
|
-
|
|
193
|
-
if (!isOtherFocused) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
// If isOtherFocused is true, fall through to handle space as text input
|
|
145
|
+
if (!isOtherFocused) return;
|
|
197
146
|
}
|
|
198
147
|
|
|
199
148
|
if (key.upArrow) {
|
|
200
|
-
if (selectedOptionIndex > 0)
|
|
149
|
+
if (selectedOptionIndex > 0)
|
|
201
150
|
setSelectedOptionIndex(selectedOptionIndex - 1);
|
|
202
|
-
}
|
|
203
151
|
return;
|
|
204
152
|
}
|
|
205
|
-
|
|
206
153
|
if (key.downArrow) {
|
|
207
|
-
if (selectedOptionIndex < options.length - 1)
|
|
154
|
+
if (selectedOptionIndex < options.length - 1)
|
|
208
155
|
setSelectedOptionIndex(selectedOptionIndex + 1);
|
|
209
|
-
}
|
|
210
156
|
return;
|
|
211
157
|
}
|
|
212
158
|
|
|
@@ -223,34 +169,29 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
223
169
|
}
|
|
224
170
|
if (key.backspace || key.delete) {
|
|
225
171
|
if (otherCursorPosition > 0) {
|
|
226
|
-
setOtherText(
|
|
227
|
-
|
|
172
|
+
setOtherText(
|
|
173
|
+
(prev) =>
|
|
228
174
|
prev.slice(0, otherCursorPosition - 1) +
|
|
229
|
-
prev.slice(otherCursorPosition)
|
|
230
|
-
|
|
231
|
-
});
|
|
175
|
+
prev.slice(otherCursorPosition),
|
|
176
|
+
);
|
|
232
177
|
setOtherCursorPosition((prev) => prev - 1);
|
|
233
178
|
}
|
|
234
179
|
return;
|
|
235
180
|
}
|
|
236
181
|
if (input && !key.ctrl && !key.meta) {
|
|
237
|
-
setOtherText(
|
|
238
|
-
|
|
182
|
+
setOtherText(
|
|
183
|
+
(prev) =>
|
|
239
184
|
prev.slice(0, otherCursorPosition) +
|
|
240
185
|
input +
|
|
241
|
-
prev.slice(otherCursorPosition)
|
|
242
|
-
|
|
243
|
-
});
|
|
186
|
+
prev.slice(otherCursorPosition),
|
|
187
|
+
);
|
|
244
188
|
setOtherCursorPosition((prev) => prev + input.length);
|
|
245
189
|
return;
|
|
246
190
|
}
|
|
247
|
-
return;
|
|
248
191
|
}
|
|
249
|
-
|
|
250
192
|
return;
|
|
251
193
|
}
|
|
252
194
|
|
|
253
|
-
// Handle Enter to confirm selection
|
|
254
195
|
if (key.return) {
|
|
255
196
|
if (state.selectedOption === "allow") {
|
|
256
197
|
if (toolName === EXIT_PLAN_MODE_TOOL_NAME) {
|
|
@@ -263,24 +204,12 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
263
204
|
const rule = suggestedPrefix
|
|
264
205
|
? `Bash(${suggestedPrefix}*)`
|
|
265
206
|
: `Bash(${toolInput?.command})`;
|
|
266
|
-
onDecision({
|
|
267
|
-
behavior: "allow",
|
|
268
|
-
newPermissionRule: rule,
|
|
269
|
-
});
|
|
207
|
+
onDecision({ behavior: "allow", newPermissionRule: rule });
|
|
270
208
|
} else {
|
|
271
|
-
onDecision({
|
|
272
|
-
behavior: "allow",
|
|
273
|
-
newPermissionMode: "acceptEdits",
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
} else {
|
|
277
|
-
// For alternative option, require text input
|
|
278
|
-
if (state.alternativeText.trim()) {
|
|
279
|
-
onDecision({
|
|
280
|
-
behavior: "deny",
|
|
281
|
-
message: state.alternativeText.trim(),
|
|
282
|
-
});
|
|
209
|
+
onDecision({ behavior: "allow", newPermissionMode: "acceptEdits" });
|
|
283
210
|
}
|
|
211
|
+
} else if (state.alternativeText.trim()) {
|
|
212
|
+
onDecision({ behavior: "deny", message: state.alternativeText.trim() });
|
|
284
213
|
}
|
|
285
214
|
return;
|
|
286
215
|
}
|
|
@@ -308,15 +237,13 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
308
237
|
}
|
|
309
238
|
}
|
|
310
239
|
|
|
311
|
-
// Handle arrow keys for navigation
|
|
312
240
|
if (key.upArrow) {
|
|
313
241
|
setState((prev) => {
|
|
314
|
-
if (prev.selectedOption === "alternative")
|
|
242
|
+
if (prev.selectedOption === "alternative")
|
|
315
243
|
return {
|
|
316
244
|
...prev,
|
|
317
245
|
selectedOption: hidePersistentOption ? "allow" : "auto",
|
|
318
246
|
};
|
|
319
|
-
}
|
|
320
247
|
if (prev.selectedOption === "auto")
|
|
321
248
|
return { ...prev, selectedOption: "allow" };
|
|
322
249
|
return prev;
|
|
@@ -326,12 +253,11 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
326
253
|
|
|
327
254
|
if (key.downArrow) {
|
|
328
255
|
setState((prev) => {
|
|
329
|
-
if (prev.selectedOption === "allow")
|
|
256
|
+
if (prev.selectedOption === "allow")
|
|
330
257
|
return {
|
|
331
258
|
...prev,
|
|
332
259
|
selectedOption: hidePersistentOption ? "alternative" : "auto",
|
|
333
260
|
};
|
|
334
|
-
}
|
|
335
261
|
if (prev.selectedOption === "auto")
|
|
336
262
|
return { ...prev, selectedOption: "alternative" };
|
|
337
263
|
return prev;
|
|
@@ -339,9 +265,7 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
339
265
|
return;
|
|
340
266
|
}
|
|
341
267
|
|
|
342
|
-
// Handle text input for alternative option
|
|
343
268
|
if (input && !key.ctrl && !key.meta && !("alt" in key && key.alt)) {
|
|
344
|
-
// Focus on alternative option when user starts typing
|
|
345
269
|
setState((prev) => {
|
|
346
270
|
const nextText =
|
|
347
271
|
prev.alternativeText.slice(0, prev.alternativeCursorPosition) +
|
|
@@ -359,7 +283,6 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
359
283
|
return;
|
|
360
284
|
}
|
|
361
285
|
|
|
362
|
-
// Handle backspace and delete
|
|
363
286
|
if (key.backspace || key.delete) {
|
|
364
287
|
setState((prev) => {
|
|
365
288
|
if (prev.alternativeCursorPosition > 0) {
|
|
@@ -385,22 +308,7 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
385
308
|
state.selectedOption === "alternative" && !state.hasUserInput;
|
|
386
309
|
|
|
387
310
|
return (
|
|
388
|
-
<Box
|
|
389
|
-
flexDirection="column"
|
|
390
|
-
borderStyle="single"
|
|
391
|
-
borderColor="yellow"
|
|
392
|
-
borderBottom={false}
|
|
393
|
-
borderLeft={false}
|
|
394
|
-
borderRight={false}
|
|
395
|
-
paddingTop={1}
|
|
396
|
-
>
|
|
397
|
-
<Text color="yellow" bold>
|
|
398
|
-
Tool: {toolName}
|
|
399
|
-
</Text>
|
|
400
|
-
<Text color="yellow">{getActionDescription(toolName, toolInput)}</Text>
|
|
401
|
-
|
|
402
|
-
<DiffDisplay toolName={toolName} parameters={JSON.stringify(toolInput)} />
|
|
403
|
-
|
|
311
|
+
<Box flexDirection="column">
|
|
404
312
|
{toolName === ASK_USER_QUESTION_TOOL_NAME &&
|
|
405
313
|
currentQuestion &&
|
|
406
314
|
!isExpanded && (
|
|
@@ -417,61 +325,52 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
417
325
|
</Box>
|
|
418
326
|
<Text bold>{currentQuestion.question}</Text>
|
|
419
327
|
</Box>
|
|
420
|
-
|
|
421
328
|
<Box flexDirection="column">
|
|
422
|
-
{
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
:{" "}
|
|
452
|
-
{otherText ? (
|
|
453
|
-
<>
|
|
454
|
-
{otherText.slice(0, otherCursorPosition)}
|
|
455
|
-
<Text backgroundColor="white" color="black">
|
|
456
|
-
{otherText[otherCursorPosition] || " "}
|
|
457
|
-
</Text>
|
|
458
|
-
{otherText.slice(otherCursorPosition + 1)}
|
|
459
|
-
</>
|
|
460
|
-
) : (
|
|
461
|
-
<Text color="gray" dimColor>
|
|
462
|
-
[Type your answer...]
|
|
329
|
+
{[...currentQuestion.options, { label: "Other" }].map(
|
|
330
|
+
(option, index) => {
|
|
331
|
+
const isSelected = selectedOptionIndex === index;
|
|
332
|
+
const isChecked = currentQuestion.multiSelect
|
|
333
|
+
? selectedOptionIndices.has(index)
|
|
334
|
+
: isSelected;
|
|
335
|
+
const isOther = index === currentQuestion.options.length;
|
|
336
|
+
return (
|
|
337
|
+
<Box key={index}>
|
|
338
|
+
<Text
|
|
339
|
+
color={isSelected ? "black" : "white"}
|
|
340
|
+
backgroundColor={isSelected ? "yellow" : undefined}
|
|
341
|
+
>
|
|
342
|
+
{isSelected ? "> " : " "}
|
|
343
|
+
{currentQuestion.multiSelect
|
|
344
|
+
? isChecked
|
|
345
|
+
? "[x] "
|
|
346
|
+
: "[ ] "
|
|
347
|
+
: ""}
|
|
348
|
+
{option.label}
|
|
349
|
+
{option.description ? ` - ${option.description}` : ""}
|
|
350
|
+
{isOther && isSelected && (
|
|
351
|
+
<Text>
|
|
352
|
+
:{" "}
|
|
353
|
+
{otherText ? (
|
|
354
|
+
<>
|
|
355
|
+
{otherText.slice(0, otherCursorPosition)}
|
|
356
|
+
<Text backgroundColor="white" color="black">
|
|
357
|
+
{otherText[otherCursorPosition] || " "}
|
|
463
358
|
</Text>
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
359
|
+
{otherText.slice(otherCursorPosition + 1)}
|
|
360
|
+
</>
|
|
361
|
+
) : (
|
|
362
|
+
<Text color="gray" dimColor>
|
|
363
|
+
[Type your answer...]
|
|
364
|
+
</Text>
|
|
365
|
+
)}
|
|
366
|
+
</Text>
|
|
367
|
+
)}
|
|
368
|
+
</Text>
|
|
369
|
+
</Box>
|
|
370
|
+
);
|
|
371
|
+
},
|
|
372
|
+
)}
|
|
473
373
|
</Box>
|
|
474
|
-
|
|
475
374
|
<Box marginTop={1}>
|
|
476
375
|
<Text dimColor>
|
|
477
376
|
Question {currentQuestionIndex + 1} of {questions.length} •
|
|
@@ -482,23 +381,12 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
482
381
|
</Box>
|
|
483
382
|
)}
|
|
484
383
|
|
|
485
|
-
{toolName !== ASK_USER_QUESTION_TOOL_NAME &&
|
|
486
|
-
toolName === EXIT_PLAN_MODE_TOOL_NAME &&
|
|
487
|
-
!!toolInput?.plan_content && (
|
|
488
|
-
<PlanDisplay
|
|
489
|
-
plan={toolInput.plan_content as string}
|
|
490
|
-
isExpanded={isExpanded}
|
|
491
|
-
/>
|
|
492
|
-
)}
|
|
493
|
-
|
|
494
384
|
{toolName !== ASK_USER_QUESTION_TOOL_NAME && !isExpanded && (
|
|
495
385
|
<>
|
|
496
386
|
<Box marginTop={1}>
|
|
497
387
|
<Text>Do you want to proceed?</Text>
|
|
498
388
|
</Box>
|
|
499
|
-
|
|
500
389
|
<Box marginTop={1} flexDirection="column">
|
|
501
|
-
{/* Option 1: Yes */}
|
|
502
390
|
<Box key="allow-option">
|
|
503
391
|
<Text
|
|
504
392
|
color={state.selectedOption === "allow" ? "black" : "white"}
|
|
@@ -513,8 +401,6 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
513
401
|
: "Yes"}
|
|
514
402
|
</Text>
|
|
515
403
|
</Box>
|
|
516
|
-
|
|
517
|
-
{/* Option 2: Auto-accept/Persistent */}
|
|
518
404
|
{!hidePersistentOption && (
|
|
519
405
|
<Box key="auto-option">
|
|
520
406
|
<Text
|
|
@@ -529,8 +415,6 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
529
415
|
</Text>
|
|
530
416
|
</Box>
|
|
531
417
|
)}
|
|
532
|
-
|
|
533
|
-
{/* Option 3: Alternative */}
|
|
534
418
|
<Box key="alternative-option">
|
|
535
419
|
<Text
|
|
536
420
|
color={
|
|
@@ -571,7 +455,6 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
571
455
|
</Text>
|
|
572
456
|
</Box>
|
|
573
457
|
</Box>
|
|
574
|
-
|
|
575
458
|
<Box marginTop={1}>
|
|
576
459
|
<Text dimColor>Use ↑↓ to navigate • ESC to cancel</Text>
|
|
577
460
|
</Box>
|
|
@@ -580,3 +463,5 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
580
463
|
</Box>
|
|
581
464
|
);
|
|
582
465
|
};
|
|
466
|
+
|
|
467
|
+
ConfirmationSelector.displayName = "ConfirmationSelector";
|
|
@@ -153,7 +153,60 @@ export const DiffDisplay: React.FC<DiffDisplayProps> = ({
|
|
|
153
153
|
const lines = part.value
|
|
154
154
|
.split("\n")
|
|
155
155
|
.filter((line) => line !== "");
|
|
156
|
-
|
|
156
|
+
|
|
157
|
+
const isFirstBlock = partIndex === 0;
|
|
158
|
+
const isLastBlock = partIndex === lineDiffs.length - 1;
|
|
159
|
+
|
|
160
|
+
let linesToDisplay = lines;
|
|
161
|
+
let showEllipsisTop = false;
|
|
162
|
+
let showEllipsisBottom = false;
|
|
163
|
+
|
|
164
|
+
if (isFirstBlock && !isLastBlock) {
|
|
165
|
+
// First block: keep last 3
|
|
166
|
+
if (lines.length > 3) {
|
|
167
|
+
linesToDisplay = lines.slice(-3);
|
|
168
|
+
showEllipsisTop = true;
|
|
169
|
+
}
|
|
170
|
+
} else if (isLastBlock && !isFirstBlock) {
|
|
171
|
+
// Last block: keep first 3
|
|
172
|
+
if (lines.length > 3) {
|
|
173
|
+
linesToDisplay = lines.slice(0, 3);
|
|
174
|
+
showEllipsisBottom = true;
|
|
175
|
+
}
|
|
176
|
+
} else if (!isFirstBlock && !isLastBlock) {
|
|
177
|
+
// Middle block: keep first 3 and last 3
|
|
178
|
+
if (lines.length > 6) {
|
|
179
|
+
linesToDisplay = [...lines.slice(0, 3), ...lines.slice(-3)];
|
|
180
|
+
showEllipsisTop = false; // We'll put ellipsis in the middle
|
|
181
|
+
}
|
|
182
|
+
} else if (isFirstBlock && isLastBlock) {
|
|
183
|
+
// Only one block (no changes?) - keep all or apply a general limit
|
|
184
|
+
// For now, let's keep all if it's the only block
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (showEllipsisTop) {
|
|
188
|
+
diffElements.push(
|
|
189
|
+
<Box key={`ellipsis-top-${changeIndex}-${partIndex}`}>
|
|
190
|
+
<Text color="gray"> ...</Text>
|
|
191
|
+
</Box>,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
linesToDisplay.forEach((line, lineIndex) => {
|
|
196
|
+
// If it's a middle block and we are at the split point
|
|
197
|
+
if (
|
|
198
|
+
!isFirstBlock &&
|
|
199
|
+
!isLastBlock &&
|
|
200
|
+
lines.length > 6 &&
|
|
201
|
+
lineIndex === 3
|
|
202
|
+
) {
|
|
203
|
+
diffElements.push(
|
|
204
|
+
<Box key={`ellipsis-mid-${changeIndex}-${partIndex}`}>
|
|
205
|
+
<Text color="gray"> ...</Text>
|
|
206
|
+
</Box>,
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
157
210
|
diffElements.push(
|
|
158
211
|
<Box
|
|
159
212
|
key={`context-${changeIndex}-${partIndex}-${lineIndex}`}
|
|
@@ -164,6 +217,14 @@ export const DiffDisplay: React.FC<DiffDisplayProps> = ({
|
|
|
164
217
|
</Box>,
|
|
165
218
|
);
|
|
166
219
|
});
|
|
220
|
+
|
|
221
|
+
if (showEllipsisBottom) {
|
|
222
|
+
diffElements.push(
|
|
223
|
+
<Box key={`ellipsis-bottom-${changeIndex}-${partIndex}`}>
|
|
224
|
+
<Text color="gray"> ...</Text>
|
|
225
|
+
</Box>,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
167
228
|
}
|
|
168
229
|
});
|
|
169
230
|
|
|
@@ -52,7 +52,6 @@ export const FileSelector: React.FC<FileSelectorProps> = ({
|
|
|
52
52
|
borderBottom={false}
|
|
53
53
|
borderLeft={false}
|
|
54
54
|
borderRight={false}
|
|
55
|
-
paddingTop={1}
|
|
56
55
|
>
|
|
57
56
|
<Text color="yellow">📁 No files found for "{searchQuery}"</Text>
|
|
58
57
|
<Text dimColor>Press Escape to cancel</Text>
|
|
@@ -91,7 +90,6 @@ export const FileSelector: React.FC<FileSelectorProps> = ({
|
|
|
91
90
|
borderBottom={false}
|
|
92
91
|
borderLeft={false}
|
|
93
92
|
borderRight={false}
|
|
94
|
-
paddingTop={1}
|
|
95
93
|
>
|
|
96
94
|
<Text color="cyan" bold>
|
|
97
95
|
📁 Select File/Directory{" "}
|
|
@@ -13,6 +13,7 @@ export const HistorySearch: React.FC<HistorySearchProps> = ({
|
|
|
13
13
|
onSelect,
|
|
14
14
|
onCancel,
|
|
15
15
|
}) => {
|
|
16
|
+
const MAX_VISIBLE_ITEMS = 5;
|
|
16
17
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
17
18
|
const [entries, setEntries] = useState<PromptEntry[]>([]);
|
|
18
19
|
|
|
@@ -30,8 +31,8 @@ export const HistorySearch: React.FC<HistorySearchProps> = ({
|
|
|
30
31
|
useEffect(() => {
|
|
31
32
|
const fetchHistory = async () => {
|
|
32
33
|
const results = await PromptHistoryManager.searchHistory(searchQuery);
|
|
33
|
-
const limitedResults = results.slice(0,
|
|
34
|
-
setEntries(limitedResults); // Limit to
|
|
34
|
+
const limitedResults = results.slice(0, 20);
|
|
35
|
+
setEntries(limitedResults); // Limit to 20 results
|
|
35
36
|
setSelectedIndex(0);
|
|
36
37
|
};
|
|
37
38
|
fetchHistory();
|
|
@@ -75,7 +76,6 @@ export const HistorySearch: React.FC<HistorySearchProps> = ({
|
|
|
75
76
|
borderBottom={false}
|
|
76
77
|
borderLeft={false}
|
|
77
78
|
borderRight={false}
|
|
78
|
-
paddingTop={1}
|
|
79
79
|
>
|
|
80
80
|
<Text color="yellow">
|
|
81
81
|
No history found {searchQuery && `for "${searchQuery}"`}
|
|
@@ -102,6 +102,19 @@ export const HistorySearch: React.FC<HistorySearchProps> = ({
|
|
|
102
102
|
}
|
|
103
103
|
};
|
|
104
104
|
|
|
105
|
+
// Calculate visible window
|
|
106
|
+
const startIndex = Math.max(
|
|
107
|
+
0,
|
|
108
|
+
Math.min(
|
|
109
|
+
selectedIndex - Math.floor(MAX_VISIBLE_ITEMS / 2),
|
|
110
|
+
Math.max(0, entries.length - MAX_VISIBLE_ITEMS),
|
|
111
|
+
),
|
|
112
|
+
);
|
|
113
|
+
const visibleEntries = entries.slice(
|
|
114
|
+
startIndex,
|
|
115
|
+
startIndex + MAX_VISIBLE_ITEMS,
|
|
116
|
+
);
|
|
117
|
+
|
|
105
118
|
return (
|
|
106
119
|
<Box
|
|
107
120
|
flexDirection="column"
|
|
@@ -110,7 +123,6 @@ export const HistorySearch: React.FC<HistorySearchProps> = ({
|
|
|
110
123
|
borderBottom={false}
|
|
111
124
|
borderLeft={false}
|
|
112
125
|
borderRight={false}
|
|
113
|
-
paddingTop={1}
|
|
114
126
|
gap={1}
|
|
115
127
|
>
|
|
116
128
|
<Box>
|
|
@@ -119,24 +131,36 @@ export const HistorySearch: React.FC<HistorySearchProps> = ({
|
|
|
119
131
|
</Text>
|
|
120
132
|
</Box>
|
|
121
133
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
<Box flexDirection="column">
|
|
135
|
+
{visibleEntries.map((entry, index) => {
|
|
136
|
+
const actualIndex = startIndex + index;
|
|
137
|
+
const isSelected = actualIndex === selectedIndex;
|
|
138
|
+
return (
|
|
139
|
+
<Box
|
|
140
|
+
key={actualIndex}
|
|
141
|
+
flexDirection="row"
|
|
142
|
+
justifyContent="space-between"
|
|
143
|
+
>
|
|
144
|
+
<Box flexShrink={1}>
|
|
145
|
+
<Text
|
|
146
|
+
color={isSelected ? "black" : "white"}
|
|
147
|
+
backgroundColor={isSelected ? "blue" : undefined}
|
|
148
|
+
wrap="truncate-end"
|
|
149
|
+
>
|
|
150
|
+
{entry.prompt.replace(/\n/g, " ")}
|
|
151
|
+
</Text>
|
|
152
|
+
</Box>
|
|
153
|
+
{isSelected && (
|
|
154
|
+
<Box marginLeft={2} flexShrink={0}>
|
|
155
|
+
<Text color="gray" dimColor>
|
|
156
|
+
{formatTimestamp(entry.timestamp)}
|
|
157
|
+
</Text>
|
|
158
|
+
</Box>
|
|
159
|
+
)}
|
|
136
160
|
</Box>
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
|
|
161
|
+
);
|
|
162
|
+
})}
|
|
163
|
+
</Box>
|
|
140
164
|
|
|
141
165
|
<Box>
|
|
142
166
|
<Text dimColor>
|