wave-code 0.4.0 → 0.6.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/App.d.ts.map +1 -1
- package/dist/components/App.js +38 -2
- package/dist/components/BackgroundTaskManager.d.ts +6 -0
- package/dist/components/BackgroundTaskManager.d.ts.map +1 -0
- package/dist/components/BackgroundTaskManager.js +114 -0
- package/dist/components/ChatInterface.d.ts.map +1 -1
- package/dist/components/ChatInterface.js +39 -5
- package/dist/components/CommandSelector.d.ts.map +1 -1
- package/dist/components/CommandSelector.js +13 -5
- 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} +92 -101
- package/dist/components/DiffDisplay.d.ts +0 -1
- package/dist/components/DiffDisplay.d.ts.map +1 -1
- package/dist/components/DiffDisplay.js +82 -60
- 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 -3
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +9 -18
- 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 -120
- 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/PluginDetail.js +1 -1
- package/dist/components/RewindCommand.d.ts +4 -0
- package/dist/components/RewindCommand.d.ts.map +1 -1
- package/dist/components/RewindCommand.js +19 -2
- package/dist/components/SubagentBlock.d.ts.map +1 -1
- package/dist/components/SubagentBlock.js +12 -5
- 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.d.ts.map +1 -1
- package/dist/components/ToolResultDisplay.js +2 -1
- package/dist/contexts/useChat.d.ts +15 -6
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +52 -43
- package/dist/hooks/useInputManager.d.ts +2 -13
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +8 -57
- package/dist/hooks/usePluginManager.d.ts.map +1 -1
- package/dist/hooks/usePluginManager.js +8 -4
- 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 +5 -28
- package/dist/managers/InputManager.d.ts.map +1 -1
- package/dist/managers/InputManager.js +26 -127
- package/package.json +9 -10
- package/src/commands/plugin/uninstall.ts +1 -1
- package/src/components/App.tsx +50 -3
- package/src/components/{BashShellManager.tsx → BackgroundTaskManager.tsx} +79 -73
- package/src/components/ChatInterface.tsx +79 -23
- package/src/components/CommandSelector.tsx +38 -20
- package/src/components/CompressDisplay.tsx +5 -22
- package/src/components/ConfirmationDetails.tsx +108 -0
- package/src/components/{Confirmation.tsx → ConfirmationSelector.tsx} +162 -187
- package/src/components/DiffDisplay.tsx +122 -107
- package/src/components/FileSelector.tsx +0 -2
- package/src/components/HistorySearch.tsx +45 -21
- package/src/components/InputBox.tsx +14 -34
- package/src/components/LoadingIndicator.tsx +56 -0
- package/src/components/Markdown.tsx +126 -318
- package/src/components/MessageItem.tsx +1 -3
- package/src/components/MessageList.tsx +10 -67
- package/src/components/PlanDisplay.tsx +5 -33
- package/src/components/PluginDetail.tsx +1 -1
- package/src/components/RewindCommand.tsx +38 -1
- package/src/components/SubagentBlock.tsx +28 -14
- package/src/components/TaskList.tsx +70 -0
- package/src/components/ToolResultDisplay.tsx +6 -2
- package/src/contexts/useChat.tsx +82 -60
- package/src/hooks/useInputManager.ts +9 -73
- package/src/hooks/usePluginManager.ts +10 -4
- package/src/hooks/useTasks.ts +6 -0
- package/src/managers/InputManager.ts +30 -157
- package/dist/components/BashShellManager.d.ts +0 -6
- package/dist/components/BashShellManager.d.ts.map +0 -1
- package/dist/components/BashShellManager.js +0 -116
- 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/src/components/MemoryDisplay.tsx +0 -62
- package/src/components/MemoryTypeSelector.tsx +0 -98
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useMemo } from "react";
|
|
2
|
-
import { Box, Text
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { Renderer, marked, type Tokens } from "marked";
|
|
4
|
+
import chalk from "chalk";
|
|
5
5
|
|
|
6
6
|
export interface MarkdownProps {
|
|
7
7
|
children: string;
|
|
@@ -17,334 +17,142 @@ const unescapeHtml = (html: string) => {
|
|
|
17
17
|
.replace(/'/g, "'");
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const t = token as Tokens.Text;
|
|
27
|
-
if (t.tokens) {
|
|
28
|
-
return <InlineRenderer key={index} tokens={t.tokens} />;
|
|
29
|
-
}
|
|
30
|
-
return <Text key={index}>{unescapeHtml(t.text)}</Text>;
|
|
31
|
-
}
|
|
32
|
-
case "strong":
|
|
33
|
-
return (
|
|
34
|
-
<Text key={index} bold>
|
|
35
|
-
{token.tokens ? (
|
|
36
|
-
<InlineRenderer tokens={token.tokens} />
|
|
37
|
-
) : (
|
|
38
|
-
unescapeHtml((token as Tokens.Strong).text)
|
|
39
|
-
)}
|
|
40
|
-
</Text>
|
|
41
|
-
);
|
|
42
|
-
case "em":
|
|
43
|
-
return (
|
|
44
|
-
<Text key={index} italic>
|
|
45
|
-
{token.tokens ? (
|
|
46
|
-
<InlineRenderer tokens={token.tokens} />
|
|
47
|
-
) : (
|
|
48
|
-
unescapeHtml((token as Tokens.Em).text)
|
|
49
|
-
)}
|
|
50
|
-
</Text>
|
|
51
|
-
);
|
|
52
|
-
case "codespan":
|
|
53
|
-
return (
|
|
54
|
-
<Text key={index} color="yellow">
|
|
55
|
-
{unescapeHtml((token as Tokens.Codespan).text)}
|
|
56
|
-
</Text>
|
|
57
|
-
);
|
|
58
|
-
case "link": {
|
|
59
|
-
const t = token as Tokens.Link;
|
|
60
|
-
return (
|
|
61
|
-
<Text key={index}>
|
|
62
|
-
<Text color="blue" underline>
|
|
63
|
-
{t.tokens ? (
|
|
64
|
-
<InlineRenderer tokens={t.tokens} />
|
|
65
|
-
) : (
|
|
66
|
-
unescapeHtml(t.text)
|
|
67
|
-
)}
|
|
68
|
-
</Text>
|
|
69
|
-
<Text color="gray"> ({t.href})</Text>
|
|
70
|
-
</Text>
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
case "br":
|
|
74
|
-
return <Text key={index}>{"\n"}</Text>;
|
|
75
|
-
case "del":
|
|
76
|
-
return (
|
|
77
|
-
<Text key={index} strikethrough>
|
|
78
|
-
{token.tokens ? (
|
|
79
|
-
<InlineRenderer tokens={token.tokens} />
|
|
80
|
-
) : (
|
|
81
|
-
unescapeHtml((token as Tokens.Del).text)
|
|
82
|
-
)}
|
|
83
|
-
</Text>
|
|
84
|
-
);
|
|
85
|
-
default:
|
|
86
|
-
return <Text key={index}>{token.raw}</Text>;
|
|
87
|
-
}
|
|
88
|
-
})}
|
|
89
|
-
</>
|
|
90
|
-
);
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const TableRenderer = ({ token }: { token: Tokens.Table }) => {
|
|
94
|
-
const { stdout } = useStdout();
|
|
95
|
-
const terminalWidth = (stdout?.columns || 80) - 2;
|
|
20
|
+
class AnsiRenderer extends Renderer<string> {
|
|
21
|
+
override code({ text, lang }: Tokens.Code): string {
|
|
22
|
+
const prefix = lang ? `\`\`\`${lang}` : "```";
|
|
23
|
+
const suffix = "```";
|
|
24
|
+
return `\n${chalk.gray(prefix)}\n${text}\n${chalk.gray(suffix)}\n`;
|
|
25
|
+
}
|
|
96
26
|
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
27
|
+
override blockquote({ tokens }: Tokens.Blockquote): string {
|
|
28
|
+
const body = this.parser.parse(tokens);
|
|
29
|
+
return (
|
|
30
|
+
"\n" +
|
|
31
|
+
body
|
|
32
|
+
.trim()
|
|
33
|
+
.split("\n")
|
|
34
|
+
.map((line) => chalk.gray("> ") + line)
|
|
35
|
+
.join("\n") +
|
|
36
|
+
"\n"
|
|
103
37
|
);
|
|
38
|
+
}
|
|
104
39
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
);
|
|
111
|
-
});
|
|
112
|
-
});
|
|
40
|
+
override heading({ tokens, depth }: Tokens.Heading): string {
|
|
41
|
+
const text = this.parser.parseInline(tokens);
|
|
42
|
+
const hashes = "#".repeat(depth);
|
|
43
|
+
return `\n${chalk.cyan(`${hashes} ${text}`)}\n`;
|
|
44
|
+
}
|
|
113
45
|
|
|
114
|
-
|
|
115
|
-
|
|
46
|
+
override hr(): string {
|
|
47
|
+
return `\n${chalk.gray("─".repeat(20))}\n`;
|
|
48
|
+
}
|
|
116
49
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
50
|
+
override list(token: Tokens.List): string {
|
|
51
|
+
const body = token.items
|
|
52
|
+
.map((item, i) => {
|
|
53
|
+
const text = this.listitem(item);
|
|
54
|
+
const prefix = token.ordered
|
|
55
|
+
? chalk.gray(`${(token.start || 1) + i}. `)
|
|
56
|
+
: chalk.gray("• ");
|
|
57
|
+
const lines = text.split("\n");
|
|
58
|
+
const firstLine = prefix + lines[0];
|
|
59
|
+
const restLines = lines
|
|
60
|
+
.slice(1)
|
|
61
|
+
.filter((line) => line.length > 0)
|
|
62
|
+
.map((line) => " " + line);
|
|
63
|
+
return [firstLine, ...restLines].join("\n") + "\n";
|
|
64
|
+
})
|
|
65
|
+
.join("");
|
|
66
|
+
return `\n${body}`;
|
|
67
|
+
}
|
|
120
68
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return paddedWidths.map((w) =>
|
|
125
|
-
Math.max(minWidth, Math.floor(w * scaleFactor)),
|
|
126
|
-
);
|
|
127
|
-
}, [token, terminalWidth]);
|
|
69
|
+
override listitem(item: Tokens.ListItem): string {
|
|
70
|
+
return `${this.parser.parse(item.tokens).trim()}\n`;
|
|
71
|
+
}
|
|
128
72
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
marginBottom={1}
|
|
133
|
-
borderStyle="single"
|
|
134
|
-
borderColor="gray"
|
|
135
|
-
width={columnWidths.reduce((a, b) => a + b, 0) + token.header.length + 1}
|
|
136
|
-
>
|
|
137
|
-
{/* Header */}
|
|
138
|
-
<Box
|
|
139
|
-
flexDirection="row"
|
|
140
|
-
borderStyle="single"
|
|
141
|
-
borderBottom
|
|
142
|
-
borderTop={false}
|
|
143
|
-
borderLeft={false}
|
|
144
|
-
borderRight={false}
|
|
145
|
-
borderColor="gray"
|
|
146
|
-
>
|
|
147
|
-
{token.header.map((cell, i) => (
|
|
148
|
-
<Box
|
|
149
|
-
key={i}
|
|
150
|
-
width={columnWidths[i]}
|
|
151
|
-
paddingX={1}
|
|
152
|
-
borderStyle="single"
|
|
153
|
-
borderLeft={i > 0}
|
|
154
|
-
borderRight={false}
|
|
155
|
-
borderTop={false}
|
|
156
|
-
borderBottom={false}
|
|
157
|
-
borderColor="gray"
|
|
158
|
-
>
|
|
159
|
-
<Text bold wrap="wrap">
|
|
160
|
-
<InlineRenderer tokens={cell.tokens} />
|
|
161
|
-
</Text>
|
|
162
|
-
</Box>
|
|
163
|
-
))}
|
|
164
|
-
</Box>
|
|
165
|
-
{/* Rows */}
|
|
166
|
-
{token.rows.map((row, rowIndex) => (
|
|
167
|
-
<Box key={rowIndex} flexDirection="row">
|
|
168
|
-
{row.map((cell, i) => (
|
|
169
|
-
<Box
|
|
170
|
-
key={i}
|
|
171
|
-
width={columnWidths[i]}
|
|
172
|
-
paddingX={1}
|
|
173
|
-
borderStyle="single"
|
|
174
|
-
borderLeft={i > 0}
|
|
175
|
-
borderRight={false}
|
|
176
|
-
borderTop={false}
|
|
177
|
-
borderBottom={false}
|
|
178
|
-
borderColor="gray"
|
|
179
|
-
>
|
|
180
|
-
<Text wrap="wrap">
|
|
181
|
-
<InlineRenderer tokens={cell.tokens} />
|
|
182
|
-
</Text>
|
|
183
|
-
</Box>
|
|
184
|
-
))}
|
|
185
|
-
</Box>
|
|
186
|
-
))}
|
|
187
|
-
</Box>
|
|
188
|
-
);
|
|
189
|
-
};
|
|
73
|
+
override checkbox({ checked }: Tokens.Checkbox): string {
|
|
74
|
+
return checked ? chalk.green("[x] ") : chalk.gray("[ ] ");
|
|
75
|
+
}
|
|
190
76
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
case "list": {
|
|
257
|
-
const t = token as Tokens.List;
|
|
258
|
-
return (
|
|
259
|
-
<Box
|
|
260
|
-
key={index}
|
|
261
|
-
flexDirection="column"
|
|
262
|
-
marginBottom={1}
|
|
263
|
-
paddingLeft={2}
|
|
264
|
-
>
|
|
265
|
-
{t.items.map((item, i) => {
|
|
266
|
-
const start = t.start || 1;
|
|
267
|
-
return (
|
|
268
|
-
<Box key={i} flexDirection="row">
|
|
269
|
-
<Text color="gray">
|
|
270
|
-
{t.ordered ? `${start + i}. ` : "• "}
|
|
271
|
-
</Text>
|
|
272
|
-
<Box flexDirection="column" flexGrow={1}>
|
|
273
|
-
{item.tokens.map((itemToken, itemIndex) => {
|
|
274
|
-
if (itemToken.type === "text") {
|
|
275
|
-
const it = itemToken as Tokens.Text;
|
|
276
|
-
return (
|
|
277
|
-
<Box key={itemIndex} flexDirection="row">
|
|
278
|
-
<Text>
|
|
279
|
-
<InlineRenderer
|
|
280
|
-
tokens={it.tokens || [itemToken]}
|
|
281
|
-
/>
|
|
282
|
-
</Text>
|
|
283
|
-
</Box>
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
|
-
return (
|
|
287
|
-
<BlockRenderer
|
|
288
|
-
key={itemIndex}
|
|
289
|
-
tokens={[itemToken]}
|
|
290
|
-
/>
|
|
291
|
-
);
|
|
292
|
-
})}
|
|
293
|
-
</Box>
|
|
294
|
-
</Box>
|
|
295
|
-
);
|
|
296
|
-
})}
|
|
297
|
-
</Box>
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
case "blockquote": {
|
|
301
|
-
const t = token as Tokens.Blockquote;
|
|
302
|
-
return (
|
|
303
|
-
<Box
|
|
304
|
-
key={index}
|
|
305
|
-
flexDirection="column"
|
|
306
|
-
paddingLeft={2}
|
|
307
|
-
borderStyle="single"
|
|
308
|
-
borderLeft
|
|
309
|
-
borderRight={false}
|
|
310
|
-
borderTop={false}
|
|
311
|
-
borderBottom={false}
|
|
312
|
-
borderColor="gray"
|
|
313
|
-
marginBottom={1}
|
|
314
|
-
>
|
|
315
|
-
<BlockRenderer tokens={t.tokens} />
|
|
316
|
-
</Box>
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
case "hr":
|
|
320
|
-
return (
|
|
321
|
-
<Box key={index} marginBottom={1}>
|
|
322
|
-
<Text color="gray">{"─".repeat(20)}</Text>
|
|
323
|
-
</Box>
|
|
324
|
-
);
|
|
325
|
-
case "table":
|
|
326
|
-
return <TableRenderer key={index} token={token as Tokens.Table} />;
|
|
327
|
-
case "space":
|
|
328
|
-
return null;
|
|
329
|
-
default:
|
|
330
|
-
return (
|
|
331
|
-
<Box key={index} marginBottom={1}>
|
|
332
|
-
<Text>{token.raw}</Text>
|
|
333
|
-
</Box>
|
|
334
|
-
);
|
|
335
|
-
}
|
|
336
|
-
})}
|
|
337
|
-
</>
|
|
338
|
-
);
|
|
339
|
-
};
|
|
77
|
+
override paragraph({ tokens }: Tokens.Paragraph): string {
|
|
78
|
+
const text = this.parser.parseInline(tokens);
|
|
79
|
+
return `\n${text}\n`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
override table(token: Tokens.Table): string {
|
|
83
|
+
const header = token.header.map((cell) => this.tablecell(cell)).join("");
|
|
84
|
+
const body = token.rows
|
|
85
|
+
.map((row) => row.map((cell) => this.tablecell(cell)).join("") + "\n")
|
|
86
|
+
.join("");
|
|
87
|
+
return `\n${header}\n${body}\n`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
override tablerow({ text }: Tokens.TableRow): string {
|
|
91
|
+
return text + "\n";
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
override tablecell(token: Tokens.TableCell): string {
|
|
95
|
+
const text = token.header ? chalk.bold(token.text) : token.text;
|
|
96
|
+
return text + " | ";
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
override strong({ tokens }: Tokens.Strong): string {
|
|
100
|
+
const text = this.parser.parseInline(tokens);
|
|
101
|
+
return chalk.bold(text);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
override em({ tokens }: Tokens.Em): string {
|
|
105
|
+
const text = this.parser.parseInline(tokens);
|
|
106
|
+
return chalk.italic(text);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
override codespan({ text }: Tokens.Codespan): string {
|
|
110
|
+
return chalk.yellow(text);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
override br(): string {
|
|
114
|
+
return "\n";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
override del({ tokens }: Tokens.Del): string {
|
|
118
|
+
const text = this.parser.parseInline(tokens);
|
|
119
|
+
return chalk.strikethrough(text);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
override link({ href, tokens }: Tokens.Link): string {
|
|
123
|
+
const text = this.parser.parseInline(tokens);
|
|
124
|
+
const linkText = chalk.blue.underline(text);
|
|
125
|
+
const hrefText = chalk.gray(`(${href})`);
|
|
126
|
+
return `${linkText} ${hrefText}`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
override image({ href, tokens, text }: Tokens.Image): string {
|
|
130
|
+
const alt = this.parser.parseInline(tokens) || text;
|
|
131
|
+
return chalk.gray(``);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
override text(token: Tokens.Text | Tokens.Escape): string {
|
|
135
|
+
return "tokens" in token && token.tokens
|
|
136
|
+
? this.parser.parseInline(token.tokens)
|
|
137
|
+
: unescapeHtml(token.text);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const renderer = new AnsiRenderer();
|
|
340
142
|
|
|
341
|
-
// Markdown component using custom
|
|
143
|
+
// Markdown component using custom ANSI renderer
|
|
342
144
|
export const Markdown = React.memo(({ children }: MarkdownProps) => {
|
|
343
|
-
const
|
|
145
|
+
const ansiContent = useMemo(() => {
|
|
146
|
+
return marked.parse(children, {
|
|
147
|
+
renderer,
|
|
148
|
+
gfm: true,
|
|
149
|
+
breaks: true,
|
|
150
|
+
}) as string;
|
|
151
|
+
}, [children]);
|
|
344
152
|
|
|
345
153
|
return (
|
|
346
154
|
<Box flexDirection="column">
|
|
347
|
-
<
|
|
155
|
+
<Text>{ansiContent.trim()}</Text>
|
|
348
156
|
</Box>
|
|
349
157
|
);
|
|
350
158
|
});
|
|
@@ -4,7 +4,6 @@ import type { Message } from "wave-agent-sdk";
|
|
|
4
4
|
import { MessageSource } from "wave-agent-sdk";
|
|
5
5
|
import { CommandOutputDisplay } from "./CommandOutputDisplay.js";
|
|
6
6
|
import { ToolResultDisplay } from "./ToolResultDisplay.js";
|
|
7
|
-
import { MemoryDisplay } from "./MemoryDisplay.js";
|
|
8
7
|
import { CompressDisplay } from "./CompressDisplay.js";
|
|
9
8
|
import { SubagentBlock } from "./SubagentBlock.js";
|
|
10
9
|
import { ReasoningDisplay } from "./ReasoningDisplay.js";
|
|
@@ -22,6 +21,7 @@ export const MessageItem = ({
|
|
|
22
21
|
shouldShowHeader,
|
|
23
22
|
}: MessageItemProps) => {
|
|
24
23
|
if (message.blocks.length === 0) return null;
|
|
24
|
+
|
|
25
25
|
return (
|
|
26
26
|
<Box flexDirection="column" gap={1} marginTop={1}>
|
|
27
27
|
{shouldShowHeader && (
|
|
@@ -79,8 +79,6 @@ export const MessageItem = ({
|
|
|
79
79
|
</Box>
|
|
80
80
|
)}
|
|
81
81
|
|
|
82
|
-
{block.type === "memory" && <MemoryDisplay block={block} />}
|
|
83
|
-
|
|
84
82
|
{block.type === "compress" && (
|
|
85
83
|
<CompressDisplay block={block} isExpanded={isExpanded} />
|
|
86
84
|
)}
|
|
@@ -7,9 +7,8 @@ export interface MessageListProps {
|
|
|
7
7
|
messages: Message[];
|
|
8
8
|
isLoading?: boolean;
|
|
9
9
|
isCommandRunning?: boolean;
|
|
10
|
-
isCompressing?: boolean;
|
|
11
|
-
latestTotalTokens?: number;
|
|
12
10
|
isExpanded?: boolean;
|
|
11
|
+
forceStaticLastMessage?: boolean;
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
export const MessageList = React.memo(
|
|
@@ -17,15 +16,16 @@ export const MessageList = React.memo(
|
|
|
17
16
|
messages,
|
|
18
17
|
isLoading = false,
|
|
19
18
|
isCommandRunning = false,
|
|
20
|
-
isCompressing = false,
|
|
21
|
-
latestTotalTokens = 0,
|
|
22
19
|
isExpanded = false,
|
|
20
|
+
forceStaticLastMessage = false,
|
|
23
21
|
}: MessageListProps) => {
|
|
24
22
|
// Empty message state
|
|
25
23
|
if (messages.length === 0) {
|
|
26
24
|
return (
|
|
27
|
-
<Box flexDirection="column"
|
|
28
|
-
<
|
|
25
|
+
<Box flexDirection="column" gap={1}>
|
|
26
|
+
<Box flexDirection="column" paddingY={1}>
|
|
27
|
+
<Text color="gray">Welcome to WAVE Code Assistant!</Text>
|
|
28
|
+
</Box>
|
|
29
29
|
</Box>
|
|
30
30
|
);
|
|
31
31
|
}
|
|
@@ -42,7 +42,8 @@ export const MessageList = React.memo(
|
|
|
42
42
|
: 0;
|
|
43
43
|
|
|
44
44
|
// Compute which messages to render statically vs dynamically
|
|
45
|
-
const shouldRenderLastDynamic =
|
|
45
|
+
const shouldRenderLastDynamic =
|
|
46
|
+
!forceStaticLastMessage && (isLoading || isCommandRunning);
|
|
46
47
|
const staticMessages = shouldRenderLastDynamic
|
|
47
48
|
? displayMessages.slice(0, -1)
|
|
48
49
|
: displayMessages;
|
|
@@ -52,7 +53,7 @@ export const MessageList = React.memo(
|
|
|
52
53
|
: [];
|
|
53
54
|
|
|
54
55
|
return (
|
|
55
|
-
<Box flexDirection="column" gap={1}>
|
|
56
|
+
<Box flexDirection="column" gap={1} paddingBottom={1}>
|
|
56
57
|
{/* Show omitted message count when limiting */}
|
|
57
58
|
{omittedCount > 0 && (
|
|
58
59
|
<Box>
|
|
@@ -86,7 +87,7 @@ export const MessageList = React.memo(
|
|
|
86
87
|
const previousMessage =
|
|
87
88
|
messageIndex > 0 ? displayMessages[messageIndex - 1] : undefined;
|
|
88
89
|
return (
|
|
89
|
-
<Box key={`dynamic-${index}`}
|
|
90
|
+
<Box key={`dynamic-${index}`}>
|
|
90
91
|
<MessageItem
|
|
91
92
|
message={message}
|
|
92
93
|
shouldShowHeader={previousMessage?.role !== message.role}
|
|
@@ -95,64 +96,6 @@ export const MessageList = React.memo(
|
|
|
95
96
|
</Box>
|
|
96
97
|
);
|
|
97
98
|
})}
|
|
98
|
-
|
|
99
|
-
{(isLoading || isCommandRunning || isCompressing) && (
|
|
100
|
-
<Box flexDirection="column" gap={1}>
|
|
101
|
-
{isLoading && (
|
|
102
|
-
<Box>
|
|
103
|
-
<Text color="yellow">💭 AI is thinking... </Text>
|
|
104
|
-
<Text color="gray" dimColor>
|
|
105
|
-
|{" "}
|
|
106
|
-
</Text>
|
|
107
|
-
<Text color="red" bold>
|
|
108
|
-
Esc
|
|
109
|
-
</Text>
|
|
110
|
-
<Text color="gray" dimColor>
|
|
111
|
-
{" "}
|
|
112
|
-
to abort
|
|
113
|
-
</Text>
|
|
114
|
-
</Box>
|
|
115
|
-
)}
|
|
116
|
-
{isCommandRunning && (
|
|
117
|
-
<Text color="blue">🚀 Command is running...</Text>
|
|
118
|
-
)}
|
|
119
|
-
{isCompressing && (
|
|
120
|
-
<Text color="magenta">🗜️ Compressing message history...</Text>
|
|
121
|
-
)}
|
|
122
|
-
</Box>
|
|
123
|
-
)}
|
|
124
|
-
|
|
125
|
-
{/* Bottom info and shortcut key hints */}
|
|
126
|
-
{messages.length > 0 && (
|
|
127
|
-
<Box>
|
|
128
|
-
<Box justifyContent="space-between" width="100%">
|
|
129
|
-
<Box>
|
|
130
|
-
<Text color="gray">
|
|
131
|
-
Messages {messages.length}
|
|
132
|
-
{latestTotalTokens > 0 && (
|
|
133
|
-
<>
|
|
134
|
-
<Text color="gray" dimColor>
|
|
135
|
-
{" "}
|
|
136
|
-
|{" "}
|
|
137
|
-
</Text>
|
|
138
|
-
<Text color="blue" bold>
|
|
139
|
-
{latestTotalTokens.toLocaleString()}
|
|
140
|
-
</Text>
|
|
141
|
-
<Text color="gray" dimColor>
|
|
142
|
-
{" "}
|
|
143
|
-
tokens
|
|
144
|
-
</Text>
|
|
145
|
-
</>
|
|
146
|
-
)}
|
|
147
|
-
</Text>
|
|
148
|
-
</Box>
|
|
149
|
-
<Text color="gray" dimColor>
|
|
150
|
-
<Text color="cyan">Ctrl+O</Text> Toggle{" "}
|
|
151
|
-
{isExpanded ? "Collapse" : "Expand"}
|
|
152
|
-
</Text>
|
|
153
|
-
</Box>
|
|
154
|
-
</Box>
|
|
155
|
-
)}
|
|
156
99
|
</Box>
|
|
157
100
|
);
|
|
158
101
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import { Box
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box } from "ink";
|
|
3
3
|
import { Markdown } from "./Markdown.js";
|
|
4
4
|
|
|
5
5
|
interface PlanDisplayProps {
|
|
@@ -7,39 +7,11 @@ interface PlanDisplayProps {
|
|
|
7
7
|
isExpanded?: boolean;
|
|
8
8
|
}
|
|
9
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
|
-
|
|
10
|
+
export const PlanDisplay: React.FC<PlanDisplayProps> = ({ plan }) => {
|
|
23
11
|
return (
|
|
24
12
|
<Box flexDirection="column" marginTop={1}>
|
|
25
|
-
<Box
|
|
26
|
-
<
|
|
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
|
-
)}
|
|
13
|
+
<Box flexDirection="column">
|
|
14
|
+
<Markdown>{plan}</Markdown>
|
|
43
15
|
</Box>
|
|
44
16
|
</Box>
|
|
45
17
|
);
|
|
@@ -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;
|