wave-code 0.7.0 → 0.7.2

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.
Files changed (57) hide show
  1. package/dist/components/ChatInterface.d.ts.map +1 -1
  2. package/dist/components/ChatInterface.js +28 -15
  3. package/dist/components/ConfirmationDetails.d.ts +1 -0
  4. package/dist/components/ConfirmationDetails.d.ts.map +1 -1
  5. package/dist/components/ConfirmationDetails.js +6 -9
  6. package/dist/components/ConfirmationSelector.d.ts +1 -0
  7. package/dist/components/ConfirmationSelector.d.ts.map +1 -1
  8. package/dist/components/ConfirmationSelector.js +164 -117
  9. package/dist/components/DiffDisplay.d.ts +1 -0
  10. package/dist/components/DiffDisplay.d.ts.map +1 -1
  11. package/dist/components/DiffDisplay.js +92 -29
  12. package/dist/components/HistorySearch.d.ts.map +1 -1
  13. package/dist/components/HistorySearch.js +1 -1
  14. package/dist/components/Markdown.d.ts.map +1 -1
  15. package/dist/components/Markdown.js +3 -1
  16. package/dist/components/McpManager.d.ts.map +1 -1
  17. package/dist/components/McpManager.js +49 -52
  18. package/dist/components/MessageBlockItem.d.ts +9 -0
  19. package/dist/components/MessageBlockItem.d.ts.map +1 -0
  20. package/dist/components/MessageBlockItem.js +11 -0
  21. package/dist/components/MessageList.d.ts +2 -4
  22. package/dist/components/MessageList.d.ts.map +1 -1
  23. package/dist/components/MessageList.js +28 -23
  24. package/dist/components/PluginDetail.d.ts.map +1 -1
  25. package/dist/components/PluginDetail.js +19 -22
  26. package/dist/components/TaskList.d.ts.map +1 -1
  27. package/dist/components/TaskList.js +2 -5
  28. package/dist/components/ToolDisplay.d.ts.map +1 -1
  29. package/dist/components/ToolDisplay.js +1 -1
  30. package/dist/contexts/useChat.d.ts.map +1 -1
  31. package/dist/contexts/useChat.js +17 -2
  32. package/dist/utils/highlightUtils.d.ts +2 -0
  33. package/dist/utils/highlightUtils.d.ts.map +1 -0
  34. package/dist/utils/highlightUtils.js +69 -0
  35. package/dist/utils/toolParameterTransforms.d.ts +1 -1
  36. package/dist/utils/toolParameterTransforms.d.ts.map +1 -1
  37. package/dist/utils/toolParameterTransforms.js +10 -3
  38. package/package.json +4 -2
  39. package/src/components/ChatInterface.tsx +35 -23
  40. package/src/components/ConfirmationDetails.tsx +13 -9
  41. package/src/components/ConfirmationSelector.tsx +207 -128
  42. package/src/components/DiffDisplay.tsx +162 -59
  43. package/src/components/HistorySearch.tsx +1 -0
  44. package/src/components/Markdown.tsx +3 -1
  45. package/src/components/McpManager.tsx +51 -59
  46. package/src/components/MessageBlockItem.tsx +83 -0
  47. package/src/components/MessageList.tsx +55 -52
  48. package/src/components/PluginDetail.tsx +30 -31
  49. package/src/components/TaskList.tsx +2 -5
  50. package/src/components/ToolDisplay.tsx +5 -1
  51. package/src/contexts/useChat.tsx +18 -2
  52. package/src/utils/highlightUtils.ts +76 -0
  53. package/src/utils/toolParameterTransforms.ts +11 -2
  54. package/dist/components/MessageItem.d.ts +0 -8
  55. package/dist/components/MessageItem.d.ts.map +0 -1
  56. package/dist/components/MessageItem.js +0 -13
  57. package/src/components/MessageItem.tsx +0 -81
@@ -1,23 +1,19 @@
1
1
  import React from "react";
2
2
  import { Box, Text, Static } from "ink";
3
3
  import type { Message } from "wave-agent-sdk";
4
- import { MessageItem } from "./MessageItem.js";
4
+ import { MessageBlockItem } from "./MessageBlockItem.js";
5
5
 
6
6
  export interface MessageListProps {
7
7
  messages: Message[];
8
- isLoading?: boolean;
9
- isCommandRunning?: boolean;
10
8
  isExpanded?: boolean;
11
- forceStaticLastMessage?: boolean;
9
+ hideDynamicBlocks?: boolean;
12
10
  }
13
11
 
14
12
  export const MessageList = React.memo(
15
13
  ({
16
14
  messages,
17
- isLoading = false,
18
- isCommandRunning = false,
19
15
  isExpanded = false,
20
- forceStaticLastMessage = false,
16
+ hideDynamicBlocks = false,
21
17
  }: MessageListProps) => {
22
18
  // Empty message state
23
19
  if (messages.length === 0) {
@@ -38,59 +34,66 @@ export const MessageList = React.memo(
38
34
  ? messages.slice(-maxExpandedMessages)
39
35
  : messages;
40
36
 
41
- // Compute which messages to render statically vs dynamically
42
- const lastMessage = displayMessages[displayMessages.length - 1];
43
- const hasNonEndTool = lastMessage?.blocks.some(
44
- (block) => block.type === "tool" && block.stage !== "end",
45
- );
46
- const hasRunningCommand = lastMessage?.blocks.some(
47
- (block) => block.type === "command_output" && block.isRunning,
48
- );
49
- const shouldRenderLastDynamic =
50
- !forceStaticLastMessage &&
51
- (isLoading || isCommandRunning || hasNonEndTool || hasRunningCommand);
52
- const staticMessages = shouldRenderLastDynamic
53
- ? displayMessages.slice(0, -1)
54
- : displayMessages;
55
- const dynamicMessages =
56
- shouldRenderLastDynamic && displayMessages.length > 0
57
- ? [displayMessages[displayMessages.length - 1]]
58
- : [];
37
+ // Flatten messages into blocks with metadata
38
+ const allBlocks = displayMessages.flatMap((message, index) => {
39
+ const messageIndex = shouldLimitMessages
40
+ ? messages.length - maxExpandedMessages + index
41
+ : index;
42
+ return message.blocks.map((block, blockIndex) => ({
43
+ block,
44
+ message,
45
+ isLastMessage: messageIndex === messages.length - 1,
46
+ // Unique key for each block to help Static component
47
+ key: `${message.id || messageIndex}-${blockIndex}`,
48
+ }));
49
+ });
50
+
51
+ // Determine which blocks are static vs dynamic
52
+ const blocksWithStatus = allBlocks.map((item) => {
53
+ const { block, isLastMessage } = item;
54
+ const isDynamic =
55
+ isLastMessage &&
56
+ ((block.type === "tool" && block.stage !== "end") ||
57
+ (block.type === "command_output" && block.isRunning));
58
+ return { ...item, isDynamic };
59
+ });
60
+
61
+ const staticBlocks = blocksWithStatus.filter((b) => !b.isDynamic);
62
+ const dynamicBlocks = hideDynamicBlocks
63
+ ? []
64
+ : blocksWithStatus.filter((b) => b.isDynamic);
59
65
 
60
66
  return (
61
67
  <Box flexDirection="column" paddingBottom={1}>
62
- {/* Static messages */}
63
- <Static items={staticMessages}>
64
- {(message, key) => {
65
- // Get previous message
66
- const previousMessage =
67
- key > 0 ? staticMessages[key - 1] : undefined;
68
- return (
69
- <MessageItem
70
- key={key}
71
- message={message}
72
- shouldShowHeader={previousMessage?.role !== message.role}
68
+ {/* Static blocks */}
69
+ {staticBlocks.length > 0 && (
70
+ <Static items={staticBlocks}>
71
+ {(item) => (
72
+ <MessageBlockItem
73
+ key={item.key}
74
+ block={item.block}
75
+ message={item.message}
73
76
  isExpanded={isExpanded}
77
+ paddingTop={1}
74
78
  />
75
- );
76
- }}
77
- </Static>
79
+ )}
80
+ </Static>
81
+ )}
78
82
 
79
- {/* Dynamic messages */}
80
- {dynamicMessages.map((message, index) => {
81
- const messageIndex = staticMessages.length + index;
82
- const previousMessage =
83
- messageIndex > 0 ? displayMessages[messageIndex - 1] : undefined;
84
- return (
85
- <Box key={`dynamic-${index}`}>
86
- <MessageItem
87
- message={message}
88
- shouldShowHeader={previousMessage?.role !== message.role}
83
+ {/* Dynamic blocks */}
84
+ {dynamicBlocks.length > 0 && (
85
+ <Box flexDirection="column">
86
+ {dynamicBlocks.map((item) => (
87
+ <MessageBlockItem
88
+ key={item.key}
89
+ block={item.block}
90
+ message={item.message}
89
91
  isExpanded={isExpanded}
92
+ paddingTop={1}
90
93
  />
91
- </Box>
92
- );
93
- })}
94
+ ))}
95
+ </Box>
96
+ )}
94
97
  </Box>
95
98
  );
96
99
  },
@@ -36,42 +36,41 @@ export const PluginDetail: React.FC = () => {
36
36
  );
37
37
  actions.setView(isFromDiscover ? "DISCOVER" : "INSTALLED");
38
38
  } else if (key.upArrow) {
39
- if (isInstalledAndEnabled) {
40
- setSelectedActionIndex((prev) =>
41
- prev > 0 ? prev - 1 : INSTALLED_ACTIONS.length - 1,
42
- );
43
- } else {
44
- setSelectedScopeIndex((prev) =>
45
- prev > 0 ? prev - 1 : SCOPES.length - 1,
46
- );
47
- }
39
+ setSelectedActionIndex((prev) =>
40
+ prev > 0 ? prev - 1 : INSTALLED_ACTIONS.length - 1,
41
+ );
42
+ setSelectedScopeIndex((prev) =>
43
+ prev > 0 ? prev - 1 : SCOPES.length - 1,
44
+ );
48
45
  } else if (key.downArrow) {
49
- if (isInstalledAndEnabled) {
50
- setSelectedActionIndex((prev) =>
51
- prev < INSTALLED_ACTIONS.length - 1 ? prev + 1 : 0,
52
- );
53
- } else {
54
- setSelectedScopeIndex((prev) =>
55
- prev < SCOPES.length - 1 ? prev + 1 : 0,
56
- );
57
- }
46
+ setSelectedActionIndex((prev) =>
47
+ prev < INSTALLED_ACTIONS.length - 1 ? prev + 1 : 0,
48
+ );
49
+ setSelectedScopeIndex((prev) =>
50
+ prev < SCOPES.length - 1 ? prev + 1 : 0,
51
+ );
58
52
  } else if (key.return && plugin) {
59
53
  if (isInstalledAndEnabled) {
60
- const action = INSTALLED_ACTIONS[selectedActionIndex].id;
61
- if (action === "uninstall") {
62
- actions.uninstallPlugin(plugin.name, plugin.marketplace);
63
- } else {
64
- actions.updatePlugin(plugin.name, plugin.marketplace);
65
- }
66
- actions.setView("INSTALLED");
54
+ setSelectedActionIndex((prev) => {
55
+ const action = INSTALLED_ACTIONS[prev].id;
56
+ if (action === "uninstall") {
57
+ actions.uninstallPlugin(plugin.name, plugin.marketplace);
58
+ } else {
59
+ actions.updatePlugin(plugin.name, plugin.marketplace);
60
+ }
61
+ return prev;
62
+ });
67
63
  } else {
68
- actions.installPlugin(
69
- plugin.name,
70
- plugin.marketplace,
71
- SCOPES[selectedScopeIndex].id,
72
- );
73
- actions.setView("INSTALLED");
64
+ setSelectedScopeIndex((prev) => {
65
+ actions.installPlugin(
66
+ plugin.name,
67
+ plugin.marketplace,
68
+ SCOPES[prev].id,
69
+ );
70
+ return prev;
71
+ });
74
72
  }
73
+ actions.setView("INSTALLED");
75
74
  }
76
75
  });
77
76
 
@@ -11,10 +11,7 @@ export const TaskList: React.FC = () => {
11
11
  return null;
12
12
  }
13
13
 
14
- const getStatusIcon = (status: string, isBlocked: boolean) => {
15
- if (isBlocked) {
16
- return <Text color="red">🔒</Text>;
17
- }
14
+ const getStatusIcon = (status: string) => {
18
15
  switch (status) {
19
16
  case "pending":
20
17
  return <Text color="gray">□</Text>;
@@ -48,7 +45,7 @@ export const TaskList: React.FC = () => {
48
45
 
49
46
  return (
50
47
  <Box key={task.id} gap={1}>
51
- {getStatusIcon(task.status, isBlocked)}
48
+ {getStatusIcon(task.status)}
52
49
  <Text dimColor={isDimmed}>{fullText}</Text>
53
50
  </Box>
54
51
  );
@@ -131,7 +131,11 @@ export const ToolDisplay: React.FC<ToolDisplayProps> = ({
131
131
 
132
132
  {/* Diff display - only show after tool execution completes and was successful */}
133
133
  {stage === "end" && success && (
134
- <DiffDisplay toolName={name} parameters={parameters} />
134
+ <DiffDisplay
135
+ toolName={name}
136
+ parameters={parameters}
137
+ startLineNumber={block.startLineNumber}
138
+ />
135
139
  )}
136
140
  </Box>
137
141
  );
@@ -131,6 +131,8 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
131
131
 
132
132
  // AI State
133
133
  const [messages, setMessages] = useState<Message[]>([]);
134
+ const messagesUpdateTimerRef = useRef<NodeJS.Timeout | null>(null);
135
+
134
136
  const [isLoading, setIsLoading] = useState(false);
135
137
  const [latestTotalTokens, setlatestTotalTokens] = useState(0);
136
138
  const [sessionId, setSessionId] = useState("");
@@ -227,9 +229,16 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
227
229
  useEffect(() => {
228
230
  const initializeAgent = async () => {
229
231
  const callbacks: AgentCallbacks = {
230
- onMessagesChange: (newMessages) => {
232
+ onMessagesChange: () => {
231
233
  if (!isExpandedRef.current) {
232
- setMessages([...newMessages]);
234
+ if (!messagesUpdateTimerRef.current) {
235
+ messagesUpdateTimerRef.current = setTimeout(() => {
236
+ if (agentRef.current) {
237
+ setMessages([...agentRef.current.messages]);
238
+ }
239
+ messagesUpdateTimerRef.current = null;
240
+ }, 50);
241
+ }
233
242
  }
234
243
  },
235
244
  onServersChange: (servers) => {
@@ -345,6 +354,9 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
345
354
  // Cleanup on unmount
346
355
  useEffect(() => {
347
356
  return () => {
357
+ if (messagesUpdateTimerRef.current) {
358
+ clearTimeout(messagesUpdateTimerRef.current);
359
+ }
348
360
  if (agentRef.current) {
349
361
  try {
350
362
  // Display usage summary before cleanup
@@ -530,6 +542,10 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
530
542
  setIsExpanded((prev) => {
531
543
  const newExpanded = !prev;
532
544
  if (newExpanded) {
545
+ if (messagesUpdateTimerRef.current) {
546
+ clearTimeout(messagesUpdateTimerRef.current);
547
+ messagesUpdateTimerRef.current = null;
548
+ }
533
549
  // Transitioning to EXPANDED: Freeze the current view
534
550
  // Deep copy the last message to ensure it doesn't update if the agent is still writing to it
535
551
  setMessages((currentMessages) => {
@@ -0,0 +1,76 @@
1
+ import hljs from 'highlight.js';
2
+ import { parse, Node, HTMLElement, TextNode } from 'node-html-parser';
3
+ import chalk from 'chalk';
4
+
5
+ const theme: Record<string, (text: string) => string> = {
6
+ 'hljs-keyword': chalk.blue,
7
+ 'hljs-built_in': chalk.cyan,
8
+ 'hljs-type': chalk.cyan,
9
+ 'hljs-literal': chalk.magenta,
10
+ 'hljs-number': chalk.magenta,
11
+ 'hljs-operator': chalk.white,
12
+ 'hljs-punctuation': chalk.white,
13
+ 'hljs-property': chalk.yellow,
14
+ 'hljs-attr': chalk.yellow,
15
+ 'hljs-variable': chalk.white,
16
+ 'hljs-template-variable': chalk.white,
17
+ 'hljs-string': chalk.green,
18
+ 'hljs-char': chalk.green,
19
+ 'hljs-comment': chalk.gray,
20
+ 'hljs-doctag': chalk.gray,
21
+ 'hljs-function': chalk.yellow,
22
+ 'hljs-title': chalk.yellow,
23
+ 'hljs-params': chalk.white,
24
+ 'hljs-tag': chalk.blue,
25
+ 'hljs-name': chalk.blue,
26
+ 'hljs-selector-tag': chalk.blue,
27
+ 'hljs-selector-id': chalk.blue,
28
+ 'hljs-selector-class': chalk.blue,
29
+ 'hljs-selector-attr': chalk.blue,
30
+ 'hljs-selector-pseudo': chalk.blue,
31
+ 'hljs-subst': chalk.white,
32
+ 'hljs-section': chalk.blue.bold,
33
+ 'hljs-bullet': chalk.magenta,
34
+ 'hljs-emphasis': chalk.italic,
35
+ 'hljs-strong': chalk.bold,
36
+ 'hljs-addition': chalk.green,
37
+ 'hljs-deletion': chalk.red,
38
+ 'hljs-link': chalk.blue.underline,
39
+ };
40
+
41
+ function nodeToAnsi(node: Node): string {
42
+ if (node instanceof TextNode) {
43
+ return node.text;
44
+ }
45
+
46
+ if (node instanceof HTMLElement) {
47
+ const content = node.childNodes.map(nodeToAnsi).join('');
48
+ const classes = node.getAttribute('class')?.split(/\s+/) || [];
49
+
50
+ for (const className of classes) {
51
+ if (theme[className]) {
52
+ return theme[className](content);
53
+ }
54
+ }
55
+
56
+ return content;
57
+ }
58
+
59
+ return '';
60
+ }
61
+
62
+ export function highlightToAnsi(code: string, language?: string): string {
63
+ if (!code) {
64
+ return '';
65
+ }
66
+ try {
67
+ const highlighted = language
68
+ ? hljs.highlight(code, { language }).value
69
+ : hljs.highlightAuto(code).value;
70
+
71
+ const root = parse(highlighted);
72
+ return root.childNodes.map(nodeToAnsi).join('');
73
+ } catch {
74
+ return code;
75
+ }
76
+ }
@@ -61,6 +61,7 @@ export function transformEditParameters(
61
61
  export function transformToolBlockToChanges(
62
62
  toolName: string,
63
63
  parameters: string,
64
+ startLineNumber?: number,
64
65
  ): Change[] {
65
66
  try {
66
67
  if (!toolName) {
@@ -69,16 +70,24 @@ export function transformToolBlockToChanges(
69
70
 
70
71
  const parsedParams = parseToolParameters(parameters);
71
72
 
73
+ let changes: Change[] = [];
72
74
  switch (toolName) {
73
75
  case "Write":
74
- return transformWriteParameters(parsedParams as WriteToolParameters);
76
+ changes = transformWriteParameters(parsedParams as WriteToolParameters);
77
+ break;
75
78
 
76
79
  case "Edit":
77
- return transformEditParameters(parsedParams as EditToolParameters);
80
+ changes = transformEditParameters(parsedParams as EditToolParameters);
81
+ break;
78
82
 
79
83
  default:
80
84
  return [];
81
85
  }
86
+
87
+ if (changes.length > 0 && startLineNumber !== undefined) {
88
+ changes[0].startLineNumber = startLineNumber;
89
+ }
90
+ return changes;
82
91
  } catch (error) {
83
92
  logger.warn("Failed to transform tool block to changes:", error);
84
93
  return [];
@@ -1,8 +0,0 @@
1
- import type { Message } from "wave-agent-sdk";
2
- export interface MessageItemProps {
3
- message: Message;
4
- isExpanded: boolean;
5
- shouldShowHeader: boolean;
6
- }
7
- export declare const MessageItem: ({ message, isExpanded }: MessageItemProps) => import("react/jsx-runtime").JSX.Element | null;
8
- //# sourceMappingURL=MessageItem.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"MessageItem.d.ts","sourceRoot":"","sources":["../../src/components/MessageItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAQ9C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,eAAO,MAAM,WAAW,GAAI,yBAAyB,gBAAgB,mDAgEpE,CAAC"}
@@ -1,13 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Box, Text } from "ink";
3
- import { MessageSource } from "wave-agent-sdk";
4
- import { CommandOutputDisplay } from "./CommandOutputDisplay.js";
5
- import { ToolDisplay } from "./ToolDisplay.js";
6
- import { CompressDisplay } from "./CompressDisplay.js";
7
- import { ReasoningDisplay } from "./ReasoningDisplay.js";
8
- import { Markdown } from "./Markdown.js";
9
- export const MessageItem = ({ message, isExpanded }) => {
10
- if (message.blocks.length === 0)
11
- return null;
12
- return (_jsx(Box, { flexDirection: "column", gap: 1, marginTop: 1, children: _jsx(Box, { flexDirection: "column", gap: 1, children: message.blocks.map((block, blockIndex) => (_jsxs(Box, { children: [block.type === "text" && block.content.trim() && (_jsxs(Box, { children: [block.customCommandContent && (_jsx(Text, { color: "cyan", bold: true, children: "$ " })), block.source === MessageSource.HOOK && (_jsx(Text, { color: "magenta", bold: true, children: "~ " })), message.role === "user" ? (_jsx(Text, { backgroundColor: "gray", color: "white", children: block.content })) : (_jsx(Markdown, { children: block.content }))] })), block.type === "error" && (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["Error: ", block.content] }) })), block.type === "command_output" && (_jsx(CommandOutputDisplay, { block: block, isExpanded: isExpanded })), block.type === "tool" && (_jsx(ToolDisplay, { block: block, isExpanded: isExpanded })), block.type === "image" && (_jsxs(Box, { children: [_jsx(Text, { color: "magenta", bold: true, children: "# Image" }), block.imageUrls && block.imageUrls.length > 0 && (_jsxs(Text, { color: "gray", dimColor: true, children: [" ", "(", block.imageUrls.length, ")"] }))] })), block.type === "compress" && (_jsx(CompressDisplay, { block: block, isExpanded: isExpanded })), block.type === "reasoning" && _jsx(ReasoningDisplay, { block: block })] }, blockIndex))) }) }));
13
- };
@@ -1,81 +0,0 @@
1
- import React from "react";
2
- import { Box, Text } from "ink";
3
- import type { Message } from "wave-agent-sdk";
4
- import { MessageSource } from "wave-agent-sdk";
5
- import { CommandOutputDisplay } from "./CommandOutputDisplay.js";
6
- import { ToolDisplay } from "./ToolDisplay.js";
7
- import { CompressDisplay } from "./CompressDisplay.js";
8
- import { ReasoningDisplay } from "./ReasoningDisplay.js";
9
- import { Markdown } from "./Markdown.js";
10
-
11
- export interface MessageItemProps {
12
- message: Message;
13
- isExpanded: boolean;
14
- shouldShowHeader: boolean;
15
- }
16
-
17
- export const MessageItem = ({ message, isExpanded }: MessageItemProps) => {
18
- if (message.blocks.length === 0) return null;
19
-
20
- return (
21
- <Box flexDirection="column" gap={1} marginTop={1}>
22
- <Box flexDirection="column" gap={1}>
23
- {message.blocks.map((block, blockIndex) => (
24
- <Box key={blockIndex}>
25
- {block.type === "text" && block.content.trim() && (
26
- <Box>
27
- {block.customCommandContent && (
28
- <Text color="cyan" bold>$ </Text>
29
- )}
30
- {block.source === MessageSource.HOOK && (
31
- <Text color="magenta" bold>~ </Text>
32
- )}
33
- {message.role === "user" ? (
34
- <Text backgroundColor="gray" color="white">
35
- {block.content}
36
- </Text>
37
- ) : (
38
- <Markdown>{block.content}</Markdown>
39
- )}
40
- </Box>
41
- )}
42
-
43
- {block.type === "error" && (
44
- <Box>
45
- <Text color="red">Error: {block.content}</Text>
46
- </Box>
47
- )}
48
-
49
- {block.type === "command_output" && (
50
- <CommandOutputDisplay block={block} isExpanded={isExpanded} />
51
- )}
52
-
53
- {block.type === "tool" && (
54
- <ToolDisplay block={block} isExpanded={isExpanded} />
55
- )}
56
-
57
- {block.type === "image" && (
58
- <Box>
59
- <Text color="magenta" bold>
60
- # Image
61
- </Text>
62
- {block.imageUrls && block.imageUrls.length > 0 && (
63
- <Text color="gray" dimColor>
64
- {" "}
65
- ({block.imageUrls.length})
66
- </Text>
67
- )}
68
- </Box>
69
- )}
70
-
71
- {block.type === "compress" && (
72
- <CompressDisplay block={block} isExpanded={isExpanded} />
73
- )}
74
-
75
- {block.type === "reasoning" && <ReasoningDisplay block={block} />}
76
- </Box>
77
- ))}
78
- </Box>
79
- </Box>
80
- );
81
- };