wave-code 0.4.0 → 0.5.1
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/commands/plugin/uninstall.js +1 -1
- package/dist/components/CommandSelector.js +3 -3
- package/dist/components/Confirmation.d.ts.map +1 -1
- package/dist/components/Confirmation.js +72 -19
- package/dist/components/DiffDisplay.d.ts +0 -1
- package/dist/components/DiffDisplay.d.ts.map +1 -1
- package/dist/components/DiffDisplay.js +38 -59
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +6 -5
- package/dist/components/Markdown.d.ts.map +1 -1
- package/dist/components/Markdown.js +4 -3
- package/dist/components/PlanDisplay.d.ts.map +1 -1
- package/dist/components/PlanDisplay.js +2 -2
- package/dist/components/PluginDetail.js +1 -1
- package/dist/components/SubagentBlock.d.ts.map +1 -1
- package/dist/components/SubagentBlock.js +4 -0
- package/dist/components/TaskManager.d.ts +6 -0
- package/dist/components/TaskManager.d.ts.map +1 -0
- package/dist/components/TaskManager.js +114 -0
- package/dist/components/ToolResultDisplay.d.ts.map +1 -1
- package/dist/components/ToolResultDisplay.js +2 -1
- package/dist/contexts/useChat.d.ts +5 -4
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +16 -12
- package/dist/hooks/useInputManager.d.ts +2 -2
- package/dist/hooks/useInputManager.js +10 -10
- package/dist/hooks/usePluginManager.d.ts.map +1 -1
- package/dist/hooks/usePluginManager.js +8 -4
- package/dist/managers/InputManager.d.ts +7 -6
- package/dist/managers/InputManager.d.ts.map +1 -1
- package/dist/managers/InputManager.js +17 -12
- package/package.json +6 -6
- package/src/commands/plugin/uninstall.ts +1 -1
- package/src/components/CommandSelector.tsx +3 -3
- package/src/components/Confirmation.tsx +114 -24
- package/src/components/DiffDisplay.tsx +60 -106
- package/src/components/InputBox.tsx +9 -7
- package/src/components/Markdown.tsx +10 -4
- package/src/components/PlanDisplay.tsx +14 -19
- package/src/components/PluginDetail.tsx +1 -1
- package/src/components/SubagentBlock.tsx +5 -0
- package/src/components/{BashShellManager.tsx → TaskManager.tsx} +79 -75
- package/src/components/ToolResultDisplay.tsx +4 -0
- package/src/contexts/useChat.tsx +25 -20
- package/src/hooks/useInputManager.ts +10 -10
- package/src/hooks/usePluginManager.ts +10 -4
- package/src/managers/InputManager.ts +22 -15
- package/dist/components/BashShellManager.d.ts +0 -6
- package/dist/components/BashShellManager.d.ts.map +0 -1
- package/dist/components/BashShellManager.js +0 -116
|
@@ -65,6 +65,7 @@ export interface ConfirmationProps {
|
|
|
65
65
|
interface ConfirmationState {
|
|
66
66
|
selectedOption: "allow" | "auto" | "alternative";
|
|
67
67
|
alternativeText: string;
|
|
68
|
+
alternativeCursorPosition: number;
|
|
68
69
|
hasUserInput: boolean; // to hide placeholder
|
|
69
70
|
}
|
|
70
71
|
|
|
@@ -81,6 +82,7 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
81
82
|
const [state, setState] = useState<ConfirmationState>({
|
|
82
83
|
selectedOption: "allow",
|
|
83
84
|
alternativeText: "",
|
|
85
|
+
alternativeCursorPosition: 0,
|
|
84
86
|
hasUserInput: false,
|
|
85
87
|
});
|
|
86
88
|
|
|
@@ -92,6 +94,7 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
92
94
|
>(new Set());
|
|
93
95
|
const [userAnswers, setUserAnswers] = useState<Record<string, string>>({});
|
|
94
96
|
const [otherText, setOtherText] = useState("");
|
|
97
|
+
const [otherCursorPosition, setOtherCursorPosition] = useState(0);
|
|
95
98
|
|
|
96
99
|
const questions =
|
|
97
100
|
(toolInput as unknown as AskUserQuestionInput)?.questions || [];
|
|
@@ -159,6 +162,7 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
159
162
|
setSelectedOptionIndex(0);
|
|
160
163
|
setSelectedOptionIndices(new Set());
|
|
161
164
|
setOtherText("");
|
|
165
|
+
setOtherCursorPosition(0);
|
|
162
166
|
} else {
|
|
163
167
|
// All questions answered
|
|
164
168
|
onDecision({
|
|
@@ -207,10 +211,38 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
207
211
|
}
|
|
208
212
|
|
|
209
213
|
if (isOtherFocused) {
|
|
214
|
+
if (key.leftArrow) {
|
|
215
|
+
setOtherCursorPosition((prev) => Math.max(0, prev - 1));
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (key.rightArrow) {
|
|
219
|
+
setOtherCursorPosition((prev) =>
|
|
220
|
+
Math.min(otherText.length, prev + 1),
|
|
221
|
+
);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
210
224
|
if (key.backspace || key.delete) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
225
|
+
if (otherCursorPosition > 0) {
|
|
226
|
+
setOtherText((prev) => {
|
|
227
|
+
const next =
|
|
228
|
+
prev.slice(0, otherCursorPosition - 1) +
|
|
229
|
+
prev.slice(otherCursorPosition);
|
|
230
|
+
return next;
|
|
231
|
+
});
|
|
232
|
+
setOtherCursorPosition((prev) => prev - 1);
|
|
233
|
+
}
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (input && !key.ctrl && !key.meta) {
|
|
237
|
+
setOtherText((prev) => {
|
|
238
|
+
const next =
|
|
239
|
+
prev.slice(0, otherCursorPosition) +
|
|
240
|
+
input +
|
|
241
|
+
prev.slice(otherCursorPosition);
|
|
242
|
+
return next;
|
|
243
|
+
});
|
|
244
|
+
setOtherCursorPosition((prev) => prev + input.length);
|
|
245
|
+
return;
|
|
214
246
|
}
|
|
215
247
|
return;
|
|
216
248
|
}
|
|
@@ -253,6 +285,29 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
253
285
|
return;
|
|
254
286
|
}
|
|
255
287
|
|
|
288
|
+
if (state.selectedOption === "alternative") {
|
|
289
|
+
if (key.leftArrow) {
|
|
290
|
+
setState((prev) => ({
|
|
291
|
+
...prev,
|
|
292
|
+
alternativeCursorPosition: Math.max(
|
|
293
|
+
0,
|
|
294
|
+
prev.alternativeCursorPosition - 1,
|
|
295
|
+
),
|
|
296
|
+
}));
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (key.rightArrow) {
|
|
300
|
+
setState((prev) => ({
|
|
301
|
+
...prev,
|
|
302
|
+
alternativeCursorPosition: Math.min(
|
|
303
|
+
prev.alternativeText.length,
|
|
304
|
+
prev.alternativeCursorPosition + 1,
|
|
305
|
+
),
|
|
306
|
+
}));
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
256
311
|
// Handle arrow keys for navigation
|
|
257
312
|
if (key.upArrow) {
|
|
258
313
|
setState((prev) => {
|
|
@@ -287,27 +342,42 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
287
342
|
// Handle text input for alternative option
|
|
288
343
|
if (input && !key.ctrl && !key.meta && !("alt" in key && key.alt)) {
|
|
289
344
|
// Focus on alternative option when user starts typing
|
|
290
|
-
setState((prev) => ({
|
|
291
|
-
selectedOption: "alternative",
|
|
292
|
-
alternativeText: prev.alternativeText + input,
|
|
293
|
-
hasUserInput: true,
|
|
294
|
-
}));
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Handle backspace and delete (same behavior - delete one character)
|
|
299
|
-
if (key.backspace || key.delete) {
|
|
300
345
|
setState((prev) => {
|
|
301
|
-
const
|
|
346
|
+
const nextText =
|
|
347
|
+
prev.alternativeText.slice(0, prev.alternativeCursorPosition) +
|
|
348
|
+
input +
|
|
349
|
+
prev.alternativeText.slice(prev.alternativeCursorPosition);
|
|
302
350
|
return {
|
|
303
351
|
...prev,
|
|
304
352
|
selectedOption: "alternative",
|
|
305
|
-
alternativeText:
|
|
306
|
-
|
|
353
|
+
alternativeText: nextText,
|
|
354
|
+
alternativeCursorPosition:
|
|
355
|
+
prev.alternativeCursorPosition + input.length,
|
|
356
|
+
hasUserInput: true,
|
|
307
357
|
};
|
|
308
358
|
});
|
|
309
359
|
return;
|
|
310
360
|
}
|
|
361
|
+
|
|
362
|
+
// Handle backspace and delete
|
|
363
|
+
if (key.backspace || key.delete) {
|
|
364
|
+
setState((prev) => {
|
|
365
|
+
if (prev.alternativeCursorPosition > 0) {
|
|
366
|
+
const nextText =
|
|
367
|
+
prev.alternativeText.slice(0, prev.alternativeCursorPosition - 1) +
|
|
368
|
+
prev.alternativeText.slice(prev.alternativeCursorPosition);
|
|
369
|
+
return {
|
|
370
|
+
...prev,
|
|
371
|
+
selectedOption: "alternative",
|
|
372
|
+
alternativeText: nextText,
|
|
373
|
+
alternativeCursorPosition: prev.alternativeCursorPosition - 1,
|
|
374
|
+
hasUserInput: nextText.length > 0,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
return prev;
|
|
378
|
+
});
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
311
381
|
});
|
|
312
382
|
|
|
313
383
|
const placeholderText = "Type here to tell Wave what to do differently";
|
|
@@ -329,11 +399,7 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
329
399
|
</Text>
|
|
330
400
|
<Text color="yellow">{getActionDescription(toolName, toolInput)}</Text>
|
|
331
401
|
|
|
332
|
-
<DiffDisplay
|
|
333
|
-
toolName={toolName}
|
|
334
|
-
parameters={JSON.stringify(toolInput)}
|
|
335
|
-
isExpanded={isExpanded}
|
|
336
|
-
/>
|
|
402
|
+
<DiffDisplay toolName={toolName} parameters={JSON.stringify(toolInput)} />
|
|
337
403
|
|
|
338
404
|
{toolName === ASK_USER_QUESTION_TOOL_NAME &&
|
|
339
405
|
currentQuestion &&
|
|
@@ -383,7 +449,15 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
383
449
|
{isOther && isSelected && (
|
|
384
450
|
<Text>
|
|
385
451
|
:{" "}
|
|
386
|
-
{otherText
|
|
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
|
+
) : (
|
|
387
461
|
<Text color="gray" dimColor>
|
|
388
462
|
[Type your answer...]
|
|
389
463
|
</Text>
|
|
@@ -474,8 +548,24 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
474
548
|
</Text>
|
|
475
549
|
) : (
|
|
476
550
|
<Text>
|
|
477
|
-
{state.alternativeText
|
|
478
|
-
|
|
551
|
+
{state.alternativeText ? (
|
|
552
|
+
<>
|
|
553
|
+
{state.alternativeText.slice(
|
|
554
|
+
0,
|
|
555
|
+
state.alternativeCursorPosition,
|
|
556
|
+
)}
|
|
557
|
+
<Text backgroundColor="white" color="black">
|
|
558
|
+
{state.alternativeText[
|
|
559
|
+
state.alternativeCursorPosition
|
|
560
|
+
] || " "}
|
|
561
|
+
</Text>
|
|
562
|
+
{state.alternativeText.slice(
|
|
563
|
+
state.alternativeCursorPosition + 1,
|
|
564
|
+
)}
|
|
565
|
+
</>
|
|
566
|
+
) : (
|
|
567
|
+
"Type here to tell Wave what to do differently"
|
|
568
|
+
)}
|
|
479
569
|
</Text>
|
|
480
570
|
)}
|
|
481
571
|
</Text>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useMemo } from "react";
|
|
2
|
-
import { Box, Text
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
3
|
import {
|
|
4
4
|
WRITE_TOOL_NAME,
|
|
5
5
|
EDIT_TOOL_NAME,
|
|
@@ -11,19 +11,12 @@ import { diffLines, diffWords } from "diff";
|
|
|
11
11
|
interface DiffDisplayProps {
|
|
12
12
|
toolName?: string;
|
|
13
13
|
parameters?: string;
|
|
14
|
-
isExpanded?: boolean;
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
export const DiffDisplay: React.FC<DiffDisplayProps> = ({
|
|
18
17
|
toolName,
|
|
19
18
|
parameters,
|
|
20
|
-
isExpanded = false,
|
|
21
19
|
}) => {
|
|
22
|
-
const { stdout } = useStdout();
|
|
23
|
-
const maxHeight = useMemo(() => {
|
|
24
|
-
return Math.max(5, (stdout?.rows || 24) - 20);
|
|
25
|
-
}, [stdout?.rows]);
|
|
26
|
-
|
|
27
20
|
const showDiff =
|
|
28
21
|
toolName &&
|
|
29
22
|
[WRITE_TOOL_NAME, EDIT_TOOL_NAME, MULTI_EDIT_TOOL_NAME].includes(toolName);
|
|
@@ -107,7 +100,7 @@ export const DiffDisplay: React.FC<DiffDisplayProps> = ({
|
|
|
107
100
|
}
|
|
108
101
|
};
|
|
109
102
|
|
|
110
|
-
// Render expanded diff display
|
|
103
|
+
// Render expanded diff display
|
|
111
104
|
const renderExpandedDiff = () => {
|
|
112
105
|
try {
|
|
113
106
|
if (changes.length === 0) return null;
|
|
@@ -122,9 +115,8 @@ export const DiffDisplay: React.FC<DiffDisplayProps> = ({
|
|
|
122
115
|
change.newContent || "",
|
|
123
116
|
);
|
|
124
117
|
|
|
118
|
+
// Process line diffs
|
|
125
119
|
const diffElements: React.ReactNode[] = [];
|
|
126
|
-
|
|
127
|
-
// Process line diffs and apply word-level diff to changed lines
|
|
128
120
|
lineDiffs.forEach((part, partIndex) => {
|
|
129
121
|
if (part.added) {
|
|
130
122
|
const lines = part.value
|
|
@@ -175,70 +167,46 @@ export const DiffDisplay: React.FC<DiffDisplayProps> = ({
|
|
|
175
167
|
}
|
|
176
168
|
});
|
|
177
169
|
|
|
178
|
-
//
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
const isCurrentRemoved =
|
|
191
|
-
typeof currentKey === "string" && currentKey.includes("remove-");
|
|
192
|
-
const isNextAdded =
|
|
193
|
-
typeof nextKey === "string" && nextKey.includes("add-");
|
|
170
|
+
// If it's a single line change (one removed, one added), use word-level diff
|
|
171
|
+
if (
|
|
172
|
+
diffElements.length === 2 &&
|
|
173
|
+
React.isValidElement(diffElements[0]) &&
|
|
174
|
+
React.isValidElement(diffElements[1]) &&
|
|
175
|
+
typeof diffElements[0].key === "string" &&
|
|
176
|
+
diffElements[0].key.includes("remove-") &&
|
|
177
|
+
typeof diffElements[1].key === "string" &&
|
|
178
|
+
diffElements[1].key.includes("add-")
|
|
179
|
+
) {
|
|
180
|
+
const removedText = extractTextFromElement(diffElements[0]);
|
|
181
|
+
const addedText = extractTextFromElement(diffElements[1]);
|
|
194
182
|
|
|
195
|
-
if (
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
// Extract the text content from the removed and added lines
|
|
202
|
-
const removedText = extractTextFromElement(current);
|
|
203
|
-
const addedText = extractTextFromElement(next);
|
|
204
|
-
|
|
205
|
-
if (removedText && addedText) {
|
|
206
|
-
// Apply word-level diff
|
|
207
|
-
const { removedParts, addedParts } = renderWordLevelDiff(
|
|
208
|
-
removedText,
|
|
209
|
-
addedText,
|
|
210
|
-
`word-${changeIndex}-${i}`,
|
|
211
|
-
);
|
|
212
|
-
|
|
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
|
-
);
|
|
183
|
+
if (removedText && addedText) {
|
|
184
|
+
const { removedParts, addedParts } = renderWordLevelDiff(
|
|
185
|
+
removedText,
|
|
186
|
+
addedText,
|
|
187
|
+
`word-${changeIndex}`,
|
|
188
|
+
);
|
|
231
189
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
190
|
+
allElements.push(
|
|
191
|
+
<Box
|
|
192
|
+
key={`word-diff-removed-${changeIndex}`}
|
|
193
|
+
flexDirection="row"
|
|
194
|
+
>
|
|
195
|
+
<Text color="red">-</Text>
|
|
196
|
+
{removedParts}
|
|
197
|
+
</Box>,
|
|
198
|
+
);
|
|
199
|
+
allElements.push(
|
|
200
|
+
<Box key={`word-diff-added-${changeIndex}`} flexDirection="row">
|
|
201
|
+
<Text color="green">+</Text>
|
|
202
|
+
{addedParts}
|
|
203
|
+
</Box>,
|
|
204
|
+
);
|
|
238
205
|
} else {
|
|
239
|
-
allElements.push(
|
|
240
|
-
i += 1;
|
|
206
|
+
allElements.push(...diffElements);
|
|
241
207
|
}
|
|
208
|
+
} else {
|
|
209
|
+
allElements.push(...diffElements);
|
|
242
210
|
}
|
|
243
211
|
} catch (error) {
|
|
244
212
|
console.warn(
|
|
@@ -255,21 +223,7 @@ export const DiffDisplay: React.FC<DiffDisplayProps> = ({
|
|
|
255
223
|
}
|
|
256
224
|
});
|
|
257
225
|
|
|
258
|
-
|
|
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
|
-
)}
|
|
271
|
-
</Box>
|
|
272
|
-
);
|
|
226
|
+
return <Box flexDirection="column">{allElements}</Box>;
|
|
273
227
|
} catch (error) {
|
|
274
228
|
console.warn("Error rendering expanded diff:", error);
|
|
275
229
|
return (
|
|
@@ -280,26 +234,6 @@ export const DiffDisplay: React.FC<DiffDisplayProps> = ({
|
|
|
280
234
|
}
|
|
281
235
|
};
|
|
282
236
|
|
|
283
|
-
// Helper function to extract text content from a React element
|
|
284
|
-
const extractTextFromElement = (element: React.ReactNode): string | null => {
|
|
285
|
-
if (!React.isValidElement(element)) return null;
|
|
286
|
-
|
|
287
|
-
// Navigate through Box -> Text structure
|
|
288
|
-
const children = (
|
|
289
|
-
element.props as unknown as { children?: React.ReactNode[] }
|
|
290
|
-
).children;
|
|
291
|
-
if (Array.isArray(children) && children.length >= 2) {
|
|
292
|
-
const textElement = children[1]; // Second child should be the Text with content
|
|
293
|
-
if (
|
|
294
|
-
React.isValidElement(textElement) &&
|
|
295
|
-
(textElement.props as unknown as { children?: string }).children
|
|
296
|
-
) {
|
|
297
|
-
return (textElement.props as unknown as { children: string }).children;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
return null;
|
|
301
|
-
};
|
|
302
|
-
|
|
303
237
|
// Don't render anything if no diff should be shown
|
|
304
238
|
if (!showDiff) {
|
|
305
239
|
return null;
|
|
@@ -316,3 +250,23 @@ export const DiffDisplay: React.FC<DiffDisplayProps> = ({
|
|
|
316
250
|
</Box>
|
|
317
251
|
);
|
|
318
252
|
};
|
|
253
|
+
|
|
254
|
+
// Helper function to extract text content from a React element
|
|
255
|
+
const extractTextFromElement = (element: React.ReactNode): string | null => {
|
|
256
|
+
if (!React.isValidElement(element)) return null;
|
|
257
|
+
|
|
258
|
+
// Navigate through Box -> Text structure
|
|
259
|
+
const children = (
|
|
260
|
+
element.props as unknown as { children?: React.ReactNode[] }
|
|
261
|
+
).children;
|
|
262
|
+
if (Array.isArray(children) && children.length >= 2) {
|
|
263
|
+
const textElement = children[1]; // Second child should be the Text with content
|
|
264
|
+
if (
|
|
265
|
+
React.isValidElement(textElement) &&
|
|
266
|
+
(textElement.props as unknown as { children?: string }).children
|
|
267
|
+
) {
|
|
268
|
+
return (textElement.props as unknown as { children: string }).children;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return null;
|
|
272
|
+
};
|
|
@@ -5,7 +5,7 @@ import { FileSelector } from "./FileSelector.js";
|
|
|
5
5
|
import { CommandSelector } from "./CommandSelector.js";
|
|
6
6
|
import { HistorySearch } from "./HistorySearch.js";
|
|
7
7
|
import { MemoryTypeSelector } from "./MemoryTypeSelector.js";
|
|
8
|
-
import {
|
|
8
|
+
import { TaskManager } from "./TaskManager.js";
|
|
9
9
|
import { McpManager } from "./McpManager.js";
|
|
10
10
|
import { RewindCommand } from "./RewindCommand.js";
|
|
11
11
|
import { useInputManager } from "../hooks/useInputManager.js";
|
|
@@ -58,6 +58,7 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
58
58
|
permissionMode: chatPermissionMode,
|
|
59
59
|
setPermissionMode: setChatPermissionMode,
|
|
60
60
|
handleRewindSelect,
|
|
61
|
+
backgroundCurrentTask,
|
|
61
62
|
messages,
|
|
62
63
|
} = useChat();
|
|
63
64
|
|
|
@@ -90,11 +91,11 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
90
91
|
// History search
|
|
91
92
|
showHistorySearch,
|
|
92
93
|
historySearchQuery,
|
|
93
|
-
//
|
|
94
|
-
|
|
94
|
+
// Task/MCP Manager
|
|
95
|
+
showTaskManager,
|
|
95
96
|
showMcpManager,
|
|
96
97
|
showRewindManager,
|
|
97
|
-
|
|
98
|
+
setShowTaskManager,
|
|
98
99
|
setShowMcpManager,
|
|
99
100
|
setShowRewindManager,
|
|
100
101
|
// Permission mode
|
|
@@ -111,6 +112,7 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
111
112
|
onHasSlashCommand: hasSlashCommand,
|
|
112
113
|
onSaveMemory: saveMemory,
|
|
113
114
|
onAbortMessage: abortMessage,
|
|
115
|
+
onBackgroundCurrentTask: backgroundCurrentTask,
|
|
114
116
|
onPermissionModeChange: setChatPermissionMode,
|
|
115
117
|
});
|
|
116
118
|
|
|
@@ -216,8 +218,8 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
216
218
|
/>
|
|
217
219
|
)}
|
|
218
220
|
|
|
219
|
-
{
|
|
220
|
-
<
|
|
221
|
+
{showTaskManager && (
|
|
222
|
+
<TaskManager onCancel={() => setShowTaskManager(false)} />
|
|
221
223
|
)}
|
|
222
224
|
|
|
223
225
|
{showMcpManager && (
|
|
@@ -229,7 +231,7 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
229
231
|
/>
|
|
230
232
|
)}
|
|
231
233
|
|
|
232
|
-
{
|
|
234
|
+
{showTaskManager || showMcpManager || showRewindManager || (
|
|
233
235
|
<Box flexDirection="column">
|
|
234
236
|
<Box
|
|
235
237
|
borderStyle="single"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useMemo } from "react";
|
|
2
2
|
import { Box, Text, useStdout } from "ink";
|
|
3
3
|
import { marked, type Token, type Tokens } from "marked";
|
|
4
|
-
import { highlight } from "cli-highlight";
|
|
4
|
+
import { highlight, supportsLanguage } from "cli-highlight";
|
|
5
5
|
|
|
6
6
|
export interface MarkdownProps {
|
|
7
7
|
children: string;
|
|
@@ -225,7 +225,8 @@ const BlockRenderer = ({ tokens }: { tokens: Token[] }) => {
|
|
|
225
225
|
const content = lines.slice(1, -1).join("\n");
|
|
226
226
|
const highlighted = content
|
|
227
227
|
? highlight(unescapeHtml(content), {
|
|
228
|
-
language:
|
|
228
|
+
language:
|
|
229
|
+
t.lang && supportsLanguage(t.lang) ? t.lang : undefined,
|
|
229
230
|
ignoreIllegals: true,
|
|
230
231
|
})
|
|
231
232
|
: "";
|
|
@@ -271,8 +272,13 @@ const BlockRenderer = ({ tokens }: { tokens: Token[] }) => {
|
|
|
271
272
|
</Text>
|
|
272
273
|
<Box flexDirection="column" flexGrow={1}>
|
|
273
274
|
{item.tokens.map((itemToken, itemIndex) => {
|
|
274
|
-
if (
|
|
275
|
-
|
|
275
|
+
if (
|
|
276
|
+
itemToken.type === "text" ||
|
|
277
|
+
itemToken.type === "paragraph"
|
|
278
|
+
) {
|
|
279
|
+
const it = itemToken as
|
|
280
|
+
| Tokens.Text
|
|
281
|
+
| Tokens.Paragraph;
|
|
276
282
|
return (
|
|
277
283
|
<Box key={itemIndex} flexDirection="row">
|
|
278
284
|
<Text>
|
|
@@ -14,7 +14,7 @@ export const PlanDisplay: React.FC<PlanDisplayProps> = ({
|
|
|
14
14
|
const { stdout } = useStdout();
|
|
15
15
|
const maxHeight = useMemo(() => {
|
|
16
16
|
// Similar to DiffDisplay.tsx maxHeight calculation
|
|
17
|
-
return Math.max(5, (stdout?.rows || 24) -
|
|
17
|
+
return Math.max(5, (stdout?.rows || 24) - 25);
|
|
18
18
|
}, [stdout?.rows]);
|
|
19
19
|
|
|
20
20
|
const lines = useMemo(() => plan.split("\n"), [plan]);
|
|
@@ -22,25 +22,20 @@ export const PlanDisplay: React.FC<PlanDisplayProps> = ({
|
|
|
22
22
|
|
|
23
23
|
return (
|
|
24
24
|
<Box flexDirection="column" marginTop={1}>
|
|
25
|
-
<Box
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
)}
|
|
25
|
+
<Box
|
|
26
|
+
flexDirection="column"
|
|
27
|
+
height={isOverflowing ? maxHeight : undefined}
|
|
28
|
+
overflow="hidden"
|
|
29
|
+
>
|
|
30
|
+
<Markdown>{plan}</Markdown>
|
|
43
31
|
</Box>
|
|
32
|
+
{isOverflowing && (
|
|
33
|
+
<Box marginTop={1}>
|
|
34
|
+
<Text color="yellow" dimColor>
|
|
35
|
+
... (plan truncated, {lines.length} lines total)
|
|
36
|
+
</Text>
|
|
37
|
+
</Box>
|
|
38
|
+
)}
|
|
44
39
|
</Box>
|
|
45
40
|
);
|
|
46
41
|
};
|
|
@@ -23,8 +23,8 @@ export const PluginDetail: React.FC = () => {
|
|
|
23
23
|
);
|
|
24
24
|
|
|
25
25
|
const INSTALLED_ACTIONS = [
|
|
26
|
-
{ id: "uninstall", label: "Uninstall plugin" },
|
|
27
26
|
{ id: "update", label: "Update plugin (reinstall)" },
|
|
27
|
+
{ id: "uninstall", label: "Uninstall plugin" },
|
|
28
28
|
] as const;
|
|
29
29
|
|
|
30
30
|
const isInstalledAndEnabled = plugin && "enabled" in plugin && plugin.enabled;
|
|
@@ -11,6 +11,11 @@ interface SubagentBlockProps {
|
|
|
11
11
|
export const SubagentBlock: React.FC<SubagentBlockProps> = ({ block }) => {
|
|
12
12
|
const { subagentMessages } = useChat();
|
|
13
13
|
|
|
14
|
+
// If the subagent is running in the background, don't show the block
|
|
15
|
+
if (block.runInBackground) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
14
19
|
// Get messages for this subagent from context
|
|
15
20
|
const messages = subagentMessages[block.subagentId] || [];
|
|
16
21
|
|