wave-code 0.0.4 → 0.0.6

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 (102) hide show
  1. package/README.md +2 -2
  2. package/dist/components/ChatInterface.d.ts.map +1 -1
  3. package/dist/components/ChatInterface.js +4 -24
  4. package/dist/components/CommandSelector.js +4 -4
  5. package/dist/components/DiffViewer.d.ts +1 -1
  6. package/dist/components/DiffViewer.d.ts.map +1 -1
  7. package/dist/components/DiffViewer.js +15 -15
  8. package/dist/components/FileSelector.js +2 -2
  9. package/dist/components/InputBox.d.ts.map +1 -1
  10. package/dist/components/InputBox.js +46 -101
  11. package/dist/components/Markdown.d.ts +6 -0
  12. package/dist/components/Markdown.d.ts.map +1 -0
  13. package/dist/components/Markdown.js +22 -0
  14. package/dist/components/MessageItem.d.ts +9 -0
  15. package/dist/components/MessageItem.d.ts.map +1 -0
  16. package/dist/components/MessageItem.js +15 -0
  17. package/dist/components/MessageList.d.ts +1 -1
  18. package/dist/components/MessageList.d.ts.map +1 -1
  19. package/dist/components/MessageList.js +33 -32
  20. package/dist/components/SubagentBlock.d.ts +1 -2
  21. package/dist/components/SubagentBlock.d.ts.map +1 -1
  22. package/dist/components/SubagentBlock.js +29 -20
  23. package/dist/components/ToolResultDisplay.js +5 -5
  24. package/dist/contexts/useChat.d.ts +1 -0
  25. package/dist/contexts/useChat.d.ts.map +1 -1
  26. package/dist/contexts/useChat.js +29 -2
  27. package/dist/hooks/useInputManager.d.ts +93 -0
  28. package/dist/hooks/useInputManager.d.ts.map +1 -0
  29. package/dist/hooks/useInputManager.js +332 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +17 -10
  32. package/dist/managers/InputManager.d.ts +171 -0
  33. package/dist/managers/InputManager.d.ts.map +1 -0
  34. package/dist/managers/InputManager.js +826 -0
  35. package/dist/print-cli.d.ts +8 -0
  36. package/dist/print-cli.d.ts.map +1 -0
  37. package/dist/print-cli.js +128 -0
  38. package/dist/utils/constants.d.ts +1 -1
  39. package/dist/utils/constants.js +1 -1
  40. package/dist/utils/fileSearch.d.ts +20 -0
  41. package/dist/utils/fileSearch.d.ts.map +1 -0
  42. package/dist/utils/fileSearch.js +102 -0
  43. package/dist/utils/logger.js +3 -3
  44. package/dist/utils/usageSummary.d.ts +33 -0
  45. package/dist/utils/usageSummary.d.ts.map +1 -0
  46. package/dist/utils/usageSummary.js +154 -0
  47. package/package.json +10 -6
  48. package/src/components/ChatInterface.tsx +13 -43
  49. package/src/components/CommandSelector.tsx +5 -5
  50. package/src/components/DiffViewer.tsx +18 -16
  51. package/src/components/FileSelector.tsx +2 -2
  52. package/src/components/InputBox.tsx +78 -169
  53. package/src/components/Markdown.tsx +29 -0
  54. package/src/components/MessageItem.tsx +104 -0
  55. package/src/components/MessageList.tsx +142 -198
  56. package/src/components/SubagentBlock.tsx +56 -73
  57. package/src/components/ToolResultDisplay.tsx +6 -6
  58. package/src/contexts/useChat.tsx +34 -2
  59. package/src/hooks/useInputManager.ts +461 -0
  60. package/src/index.ts +20 -10
  61. package/src/managers/InputManager.ts +1132 -0
  62. package/src/print-cli.ts +160 -0
  63. package/src/utils/constants.ts +1 -1
  64. package/src/utils/fileSearch.ts +133 -0
  65. package/src/utils/logger.ts +3 -3
  66. package/src/utils/usageSummary.ts +234 -0
  67. package/dist/hooks/useBashHistorySelector.d.ts +0 -15
  68. package/dist/hooks/useBashHistorySelector.d.ts.map +0 -1
  69. package/dist/hooks/useBashHistorySelector.js +0 -61
  70. package/dist/hooks/useCommandSelector.d.ts +0 -24
  71. package/dist/hooks/useCommandSelector.d.ts.map +0 -1
  72. package/dist/hooks/useCommandSelector.js +0 -98
  73. package/dist/hooks/useFileSelector.d.ts +0 -16
  74. package/dist/hooks/useFileSelector.d.ts.map +0 -1
  75. package/dist/hooks/useFileSelector.js +0 -174
  76. package/dist/hooks/useImageManager.d.ts +0 -13
  77. package/dist/hooks/useImageManager.d.ts.map +0 -1
  78. package/dist/hooks/useImageManager.js +0 -46
  79. package/dist/hooks/useInputHistory.d.ts +0 -11
  80. package/dist/hooks/useInputHistory.d.ts.map +0 -1
  81. package/dist/hooks/useInputHistory.js +0 -64
  82. package/dist/hooks/useInputKeyboardHandler.d.ts +0 -83
  83. package/dist/hooks/useInputKeyboardHandler.d.ts.map +0 -1
  84. package/dist/hooks/useInputKeyboardHandler.js +0 -507
  85. package/dist/hooks/useInputState.d.ts +0 -14
  86. package/dist/hooks/useInputState.d.ts.map +0 -1
  87. package/dist/hooks/useInputState.js +0 -57
  88. package/dist/hooks/useMemoryTypeSelector.d.ts +0 -9
  89. package/dist/hooks/useMemoryTypeSelector.d.ts.map +0 -1
  90. package/dist/hooks/useMemoryTypeSelector.js +0 -27
  91. package/dist/plain-cli.d.ts +0 -7
  92. package/dist/plain-cli.d.ts.map +0 -1
  93. package/dist/plain-cli.js +0 -44
  94. package/src/hooks/useBashHistorySelector.ts +0 -77
  95. package/src/hooks/useCommandSelector.ts +0 -131
  96. package/src/hooks/useFileSelector.ts +0 -227
  97. package/src/hooks/useImageManager.ts +0 -64
  98. package/src/hooks/useInputHistory.ts +0 -74
  99. package/src/hooks/useInputKeyboardHandler.ts +0 -778
  100. package/src/hooks/useInputState.ts +0 -66
  101. package/src/hooks/useMemoryTypeSelector.ts +0 -40
  102. package/src/plain-cli.ts +0 -60
@@ -1,107 +1,7 @@
1
- import React, { useMemo } from "react";
2
- import { Box, Text } from "ink";
1
+ import React from "react";
2
+ import { Box, Text, Static } from "ink";
3
3
  import type { Message } from "wave-agent-sdk";
4
- import { DiffViewer } from "./DiffViewer.js";
5
- import { CommandOutputDisplay } from "./CommandOutputDisplay.js";
6
- import { ToolResultDisplay } from "./ToolResultDisplay.js";
7
- import { MemoryDisplay } from "./MemoryDisplay.js";
8
- import { CompressDisplay } from "./CompressDisplay.js";
9
- import { SubagentBlock } from "./SubagentBlock.js";
10
- import { usePagination } from "../hooks/usePagination.js";
11
-
12
- // Function to render a single message
13
- const renderMessageItem = (
14
- message: Message,
15
- originalIndex: number,
16
- isExpanded: boolean,
17
- previousMessage?: Message,
18
- ) => {
19
- const shouldShowHeader = previousMessage?.role !== message.role;
20
-
21
- return (
22
- <Box key={`message-${originalIndex}`} flexDirection="column">
23
- {shouldShowHeader && (
24
- <Box>
25
- <Text color={message.role === "user" ? "cyan" : "green"} bold>
26
- {message.role === "user" ? "👤 You" : "🤖 Assistant"}
27
- <Text color="gray" dimColor>
28
- {" "}
29
- #{originalIndex + 1}
30
- </Text>
31
- </Text>
32
- </Box>
33
- )}
34
-
35
- <Box
36
- marginLeft={2}
37
- flexDirection="column"
38
- gap={1}
39
- marginTop={shouldShowHeader ? 1 : 0}
40
- >
41
- {message.blocks.map((block, blockIndex) => (
42
- <Box key={blockIndex}>
43
- {block.type === "text" && block.content.trim() && (
44
- <Box>
45
- <Text>{block.content}</Text>
46
- </Box>
47
- )}
48
-
49
- {block.type === "error" && (
50
- <Box>
51
- <Text color="red">❌ Error: {block.content}</Text>
52
- </Box>
53
- )}
54
-
55
- {block.type === "diff" && (
56
- <DiffViewer block={block} isExpanded={isExpanded} />
57
- )}
58
-
59
- {block.type === "command_output" && (
60
- <CommandOutputDisplay block={block} isExpanded={isExpanded} />
61
- )}
62
-
63
- {block.type === "tool" && (
64
- <ToolResultDisplay block={block} isExpanded={isExpanded} />
65
- )}
66
-
67
- {block.type === "image" && (
68
- <Box>
69
- <Text color="magenta" bold>
70
- 📷 Image
71
- </Text>
72
- {block.imageUrls && block.imageUrls.length > 0 && (
73
- <Text color="gray" dimColor>
74
- {" "}
75
- ({block.imageUrls.length})
76
- </Text>
77
- )}
78
- </Box>
79
- )}
80
-
81
- {block.type === "memory" && <MemoryDisplay block={block} />}
82
-
83
- {block.type === "compress" && (
84
- <CompressDisplay block={block} isExpanded={isExpanded} />
85
- )}
86
-
87
- {block.type === "custom_command" && (
88
- <Box>
89
- <Text color="cyan" bold>
90
-
91
- </Text>
92
- <Text>{block.originalInput || `/${block.commandName}`}</Text>
93
- </Box>
94
- )}
95
-
96
- {block.type === "subagent" && (
97
- <SubagentBlock block={block} isExpanded={isExpanded} />
98
- )}
99
- </Box>
100
- ))}
101
- </Box>
102
- </Box>
103
- );
104
- };
4
+ import { MessageItem } from "./MessageItem.js";
105
5
 
106
6
  export interface MessageListProps {
107
7
  messages: Message[];
@@ -112,109 +12,153 @@ export interface MessageListProps {
112
12
  isExpanded?: boolean;
113
13
  }
114
14
 
115
- export const MessageList: React.FC<MessageListProps> = ({
116
- messages,
117
- isLoading = false,
118
- isCommandRunning = false,
119
- isCompressing = false,
120
- latestTotalTokens = 0,
121
- isExpanded = false,
122
- }) => {
123
- // Use original messages for pagination calculation
124
- const { displayInfo } = usePagination(messages);
125
-
126
- // Get current page messages while preserving original index information
127
- const currentMessagesWithIndex = useMemo(() => {
128
- return messages
129
- .slice(displayInfo.startIndex, displayInfo.endIndex)
130
- .map((message, index) => ({
131
- message,
132
- originalIndex: displayInfo.startIndex + index,
133
- }));
134
- }, [messages, displayInfo.startIndex, displayInfo.endIndex]);
15
+ export const MessageList = React.memo(
16
+ ({
17
+ messages,
18
+ isLoading = false,
19
+ isCommandRunning = false,
20
+ isCompressing = false,
21
+ latestTotalTokens = 0,
22
+ isExpanded = false,
23
+ }: MessageListProps) => {
24
+ // Empty message state
25
+ if (messages.length === 0) {
26
+ return (
27
+ <Box flexDirection="column" paddingY={1}>
28
+ <Text color="gray">Welcome to WAVE Code Assistant!</Text>
29
+ </Box>
30
+ );
31
+ }
32
+
33
+ // Limit messages when expanded to prevent long rendering times
34
+ const maxExpandedMessages = 20;
35
+ const shouldLimitMessages =
36
+ isExpanded && messages.length > maxExpandedMessages;
37
+ const displayMessages = shouldLimitMessages
38
+ ? messages.slice(-maxExpandedMessages)
39
+ : messages;
40
+ const omittedCount = shouldLimitMessages
41
+ ? messages.length - maxExpandedMessages
42
+ : 0;
43
+
44
+ // Compute which messages to render statically vs dynamically
45
+ const shouldRenderLastDynamic = isLoading || isCommandRunning;
46
+ const staticMessages = shouldRenderLastDynamic
47
+ ? displayMessages.slice(0, -1)
48
+ : displayMessages;
49
+ const dynamicMessages =
50
+ shouldRenderLastDynamic && displayMessages.length > 0
51
+ ? [displayMessages[displayMessages.length - 1]]
52
+ : [];
135
53
 
136
- // Empty message state
137
- if (messages.length === 0) {
138
54
  return (
139
- <Box flexDirection="column" paddingY={1}>
140
- <Text color="gray">Welcome to WAVE Code Assistant!</Text>
141
- </Box>
142
- );
143
- }
144
-
145
- return (
146
- <Box flexDirection="column" gap={1} marginTop={1}>
147
- {/* Message list */}
148
- <Box flexDirection="column" gap={1}>
149
- {currentMessagesWithIndex.map(({ message, originalIndex }) => {
150
- // Get previous message
55
+ <Box flexDirection="column" paddingX={1} gap={1}>
56
+ {/* Show omitted message count when limiting */}
57
+ {omittedCount > 0 && (
58
+ <Box>
59
+ <Text color="gray" dimColor>
60
+ ... {omittedCount} earlier message{omittedCount !== 1 ? "s" : ""}{" "}
61
+ omitted (showing latest {maxExpandedMessages})
62
+ </Text>
63
+ </Box>
64
+ )}
65
+
66
+ {/* Static messages */}
67
+ <Static items={staticMessages}>
68
+ {(message, key) => {
69
+ // Get previous message
70
+ const previousMessage =
71
+ key > 0 ? staticMessages[key - 1] : undefined;
72
+ return (
73
+ <MessageItem
74
+ key={key}
75
+ message={message}
76
+ shouldShowHeader={previousMessage?.role !== message.role}
77
+ isExpanded={isExpanded}
78
+ isStatic={true}
79
+ />
80
+ );
81
+ }}
82
+ </Static>
83
+
84
+ {/* Dynamic messages */}
85
+ {dynamicMessages.map((message, index) => {
86
+ const messageIndex = staticMessages.length + index;
151
87
  const previousMessage =
152
- originalIndex > 0 ? messages[originalIndex - 1] : undefined;
153
- return renderMessageItem(
154
- message,
155
- originalIndex,
156
- isExpanded,
157
- previousMessage,
88
+ messageIndex > 0 ? displayMessages[messageIndex - 1] : undefined;
89
+ return (
90
+ <Box key={`dynamic-${index}`} marginTop={-1}>
91
+ <MessageItem
92
+ message={message}
93
+ shouldShowHeader={previousMessage?.role !== message.role}
94
+ isExpanded={isExpanded}
95
+ isStatic={false}
96
+ />
97
+ </Box>
158
98
  );
159
99
  })}
160
- </Box>
161
100
 
162
- {/* Loading state display - only show in non-expanded state */}
163
- {!isExpanded && (isLoading || isCommandRunning || isCompressing) && (
164
- <Box flexDirection="column" gap={1}>
165
- {isLoading && (
166
- <Box>
167
- <Text color="yellow">💭 AI is thinking... </Text>
168
- <Text color="gray" dimColor>
169
- {" "}
170
- |{" "}
171
- </Text>
172
- <Text color="blue" bold>
173
- {latestTotalTokens.toLocaleString()}
174
- </Text>
175
- <Text color="gray" dimColor>
176
- {" "}
177
- tokens |{" "}
178
- </Text>
179
- <Text color="red" bold>
180
- Esc
181
- </Text>
182
- <Text color="gray" dimColor>
183
- {" "}
184
- to abort
185
- </Text>
186
- </Box>
187
- )}
188
- {isCommandRunning && (
189
- <Text color="blue">🚀 Command is running...</Text>
190
- )}
191
- {isCompressing && (
192
- <Text color="magenta">🗜️ Compressing message history...</Text>
193
- )}
194
- </Box>
195
- )}
101
+ {(isLoading || isCommandRunning || isCompressing) && (
102
+ <Box flexDirection="column" gap={1}>
103
+ {isLoading && (
104
+ <Box>
105
+ <Text color="yellow">💭 AI is thinking... </Text>
106
+ <Text color="gray" dimColor>
107
+ |{" "}
108
+ </Text>
109
+ <Text color="red" bold>
110
+ Esc
111
+ </Text>
112
+ <Text color="gray" dimColor>
113
+ {" "}
114
+ to abort
115
+ </Text>
116
+ </Box>
117
+ )}
118
+ {isCommandRunning && (
119
+ <Text color="blue">🚀 Command is running...</Text>
120
+ )}
121
+ {isCompressing && (
122
+ <Text color="magenta">🗜️ Compressing message history...</Text>
123
+ )}
124
+ </Box>
125
+ )}
196
126
 
197
- {/* Bottom info and shortcut key hints */}
198
- {messages.length > 0 && (
199
- <Box>
200
- <Box justifyContent="space-between" width="100%">
201
- <Box>
202
- <Text color="gray">
203
- Messages {messages.length} Page {displayInfo.currentPage}/
204
- {displayInfo.totalPages}
205
- </Text>
127
+ {/* Bottom info and shortcut key hints */}
128
+ {messages.length > 0 && (
129
+ <Box>
130
+ <Box justifyContent="space-between" width="100%">
131
+ <Box>
132
+ <Text color="gray">
133
+ Messages {messages.length}
134
+ {latestTotalTokens > 0 && (
135
+ <>
136
+ <Text color="gray" dimColor>
137
+ {" "}
138
+ |{" "}
139
+ </Text>
140
+ <Text color="blue" bold>
141
+ {latestTotalTokens.toLocaleString()}
142
+ </Text>
143
+ <Text color="gray" dimColor>
144
+ {" "}
145
+ tokens
146
+ </Text>
147
+ </>
148
+ )}
149
+ </Text>
150
+ </Box>
206
151
  <Text color="gray" dimColor>
207
- {" "}
208
- <Text color="cyan">Ctrl+U/D</Text> Navigate
152
+ <Text color="cyan">Ctrl+O</Text> Toggle{" "}
153
+ {isExpanded ? "Collapse" : "Expand"}
209
154
  </Text>
210
155
  </Box>
211
- <Text color="gray" dimColor>
212
- <Text color="cyan">Ctrl+O</Text> Toggle{" "}
213
- {isExpanded ? "Collapse" : "Expand"}
214
- </Text>
215
156
  </Box>
216
- </Box>
217
- )}
218
- </Box>
219
- );
220
- };
157
+ )}
158
+ </Box>
159
+ );
160
+ },
161
+ );
162
+
163
+ // Add display name for debugging
164
+ MessageList.displayName = "MessageList";
@@ -1,46 +1,18 @@
1
1
  import React from "react";
2
2
  import { Box, Text } from "ink";
3
- import type {
4
- SubagentBlock as SubagentBlockType,
5
- Message,
6
- MessageBlock,
7
- } from "wave-agent-sdk/src/types.js";
8
- import { ToolResultDisplay } from "./ToolResultDisplay.js";
9
-
10
- // Component to render individual message blocks
11
- interface MessageBlockRendererProps {
12
- block: MessageBlock;
13
- isExpanded: boolean;
14
- }
15
-
16
- const MessageBlockRenderer: React.FC<MessageBlockRendererProps> = ({
17
- block,
18
- isExpanded,
19
- }) => {
20
- switch (block.type) {
21
- case "text":
22
- return <Text>{block.content}</Text>;
23
-
24
- case "error":
25
- return <Text color="red">❌ Error: {block.content}</Text>;
26
-
27
- case "tool":
28
- return <ToolResultDisplay block={block} isExpanded={isExpanded} />;
29
-
30
- default:
31
- return null;
32
- }
33
- };
3
+ import type { SubagentBlock as SubagentBlockType } from "wave-agent-sdk";
4
+ import { useChat } from "../contexts/useChat.js";
34
5
 
35
6
  interface SubagentBlockProps {
36
7
  block: SubagentBlockType;
37
- isExpanded?: boolean;
38
8
  }
39
9
 
40
- export const SubagentBlock: React.FC<SubagentBlockProps> = ({
41
- block,
42
- isExpanded = false,
43
- }) => {
10
+ export const SubagentBlock: React.FC<SubagentBlockProps> = ({ block }) => {
11
+ const { subagentMessages } = useChat();
12
+
13
+ // Get messages for this subagent from context
14
+ const messages = subagentMessages[block.subagentId] || [];
15
+
44
16
  // Status indicator mapping
45
17
  const getStatusIndicator = (status: SubagentBlockType["status"]) => {
46
18
  switch (status) {
@@ -59,14 +31,40 @@ export const SubagentBlock: React.FC<SubagentBlockProps> = ({
59
31
 
60
32
  const statusInfo = getStatusIndicator(block.status);
61
33
 
62
- // Determine how many messages to show
63
- const messagesToShow = isExpanded
64
- ? block.messages.slice(-10) // Up to 10 most recent when expanded
65
- : block.messages.slice(-2); // Up to 2 most recent when collapsed
34
+ // Find the last 2 tool names and their compact params, and count total tools
35
+ const getLastTwoTools = (): {
36
+ tools: Array<{ name: string; compactParams?: string }>;
37
+ totalToolCount: number;
38
+ } => {
39
+ const tools: Array<{ name: string; compactParams?: string }> = [];
40
+ let totalToolCount = 0;
41
+
42
+ for (let i = messages.length - 1; i >= 0; i--) {
43
+ const message = messages[i];
44
+ for (let j = message.blocks.length - 1; j >= 0; j--) {
45
+ const messageBlock = message.blocks[j];
46
+ if (messageBlock.type === "tool" && messageBlock.name) {
47
+ totalToolCount++;
48
+ if (tools.length < 2) {
49
+ tools.push({
50
+ name: messageBlock.name,
51
+ compactParams: messageBlock.compactParams,
52
+ });
53
+ }
54
+ }
55
+ }
56
+ }
57
+ return { tools: tools.reverse(), totalToolCount }; // Reverse to show oldest first, newest last
58
+ };
59
+
60
+ const { tools: lastTwoTools, totalToolCount } = getLastTwoTools();
66
61
 
67
62
  return (
68
63
  <Box
69
- borderStyle="round"
64
+ borderRight={false}
65
+ borderTop={false}
66
+ borderBottom={false}
67
+ borderStyle="classic"
70
68
  borderColor="magenta"
71
69
  paddingX={1}
72
70
  paddingY={0}
@@ -74,54 +72,39 @@ export const SubagentBlock: React.FC<SubagentBlockProps> = ({
74
72
  marginBottom={1}
75
73
  >
76
74
  {/* Header Section */}
77
- <Box
78
- flexDirection="row"
79
- justifyContent="space-between"
80
- alignItems="center"
81
- >
75
+ <Box flexDirection="row" gap={1}>
82
76
  <Box flexDirection="row" alignItems="center">
83
77
  <Text color="cyan">🤖 {block.subagentName}</Text>
84
78
  <Text color={statusInfo.color} dimColor={false}>
85
79
  {" "}
86
80
  {statusInfo.icon}
87
81
  </Text>
88
- </Box>
89
-
90
- {!isExpanded && (
91
82
  <Text color="gray" dimColor>
92
- {block.messages.length} messages
83
+ {" "}
84
+ ({messages.length} messages)
93
85
  </Text>
94
- )}
86
+ </Box>
95
87
  </Box>
96
88
 
97
- {/* Messages Section */}
98
- {messagesToShow.length > 0 && (
89
+ {/* Tool Names Section - Vertical List */}
90
+ {lastTwoTools.length > 0 && (
99
91
  <Box flexDirection="column" marginTop={1} gap={1}>
100
- {messagesToShow.map((message: Message, index: number) => (
101
- <Box key={index} flexDirection="column" marginBottom={0} gap={1}>
102
- {message.blocks.map(
103
- (messageBlock: MessageBlock, blockIndex: number) => (
104
- <Box key={blockIndex} flexDirection="column">
105
- <MessageBlockRenderer
106
- block={messageBlock}
107
- isExpanded={isExpanded}
108
- />
109
- </Box>
110
- ),
92
+ {totalToolCount > 2 && (
93
+ <Text color="gray" dimColor>
94
+ ...
95
+ </Text>
96
+ )}
97
+ {lastTwoTools.map((tool, index) => (
98
+ <Box key={index} flexDirection="row">
99
+ <Text color="magenta">🔧 </Text>
100
+ <Text color="white">{tool.name}</Text>
101
+ {tool.compactParams && (
102
+ <Text color="gray"> {tool.compactParams}</Text>
111
103
  )}
112
104
  </Box>
113
105
  ))}
114
106
  </Box>
115
107
  )}
116
-
117
- {/* Show truncation indicator if there are more messages */}
118
- {!isExpanded && block.messages.length > 2 && (
119
- <Box marginTop={1}>
120
- <Text color="gray" dimColor>
121
- ... and {block.messages.length - 2} more messages (Ctrl+O to expand)
122
- </Text>
123
- </Box>
124
- )}
125
108
  </Box>
126
109
  );
127
110
  };
@@ -11,23 +11,23 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
11
11
  block,
12
12
  isExpanded = false,
13
13
  }) => {
14
- const { parameters, result, compactParams, isRunning, success, error, name } =
14
+ const { parameters, result, compactParams, stage, success, error, name } =
15
15
  block;
16
16
 
17
17
  // Directly use compactParams
18
18
  // (no change needed as we destructured it above)
19
19
 
20
20
  const getStatusColor = () => {
21
- if (isRunning) return "yellow";
21
+ if (stage === "running") return "yellow";
22
22
  if (success) return "green";
23
23
  if (error || success === false) return "red";
24
24
  return "gray"; // Unknown state or no state information
25
25
  };
26
26
 
27
27
  const getStatusText = () => {
28
- if (isRunning) return "🔄";
28
+ if (stage === "running") return "🔄";
29
29
  if (success) return "";
30
- if (error || success === false) return "❌ Failed";
30
+ if (error || success === false) return "❌";
31
31
  return ""; // Don't display text for unknown state
32
32
  };
33
33
 
@@ -70,7 +70,7 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
70
70
  <Text color="white">{toolName}</Text>
71
71
  {/* Display compactParams in collapsed state */}
72
72
  {!isExpanded && compactParams && (
73
- <Text color="gray"> ({compactParams})</Text>
73
+ <Text color="gray"> {compactParams}</Text>
74
74
  )}
75
75
  <Text color={getStatusColor()}> {getStatusText()}</Text>
76
76
  {/* Display image indicator */}
@@ -78,7 +78,7 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
78
78
  </Box>
79
79
 
80
80
  {/* Display shortResult in collapsed state */}
81
- {!isExpanded && shortResult && (
81
+ {!isExpanded && shortResult && !error && (
82
82
  <Box
83
83
  paddingLeft={2}
84
84
  borderLeft
@@ -16,6 +16,7 @@ import type {
16
16
  } from "wave-agent-sdk";
17
17
  import { Agent, AgentCallbacks } from "wave-agent-sdk";
18
18
  import { logger } from "../utils/logger.js";
19
+ import { displayUsageSummary } from "../utils/usageSummary.js";
19
20
 
20
21
  // Main Chat Context
21
22
  export interface ChatContextType {
@@ -49,6 +50,8 @@ export interface ChatContextType {
49
50
  // Slash Command functionality
50
51
  slashCommands: SlashCommand[];
51
52
  hasSlashCommand: (commandId: string) => boolean;
53
+ // Subagent messages
54
+ subagentMessages: Record<string, Message[]>;
52
55
  }
53
56
 
54
57
  const ChatContext = createContext<ChatContextType | null>(null);
@@ -91,12 +94,23 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
91
94
  // Command state
92
95
  const [slashCommands, setSlashCommands] = useState<SlashCommand[]>([]);
93
96
 
97
+ // Subagent messages state
98
+ const [subagentMessages, setSubagentMessages] = useState<
99
+ Record<string, Message[]>
100
+ >({});
101
+
94
102
  const agentRef = useRef<Agent | null>(null);
95
103
 
96
104
  // Listen for Ctrl+O hotkey to toggle collapse/expand state
97
105
  useInput((input, key) => {
98
106
  if (key.ctrl && input === "o") {
99
- setIsExpanded((prev) => !prev);
107
+ // Clear terminal screen when expanded state changes
108
+ process.stdout.write("\x1Bc", () => {
109
+ setIsExpanded((prev) => {
110
+ const newExpanded = !prev;
111
+ return newExpanded;
112
+ });
113
+ });
100
114
  }
101
115
  });
102
116
 
@@ -111,7 +125,9 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
111
125
  setMcpServers([...servers]);
112
126
  },
113
127
  onSessionIdChange: (sessionId) => {
114
- setSessionId(sessionId);
128
+ process.stdout.write("\x1Bc", () => {
129
+ setSessionId(sessionId);
130
+ });
115
131
  },
116
132
  onLatestTotalTokensChange: (tokens) => {
117
133
  setlatestTotalTokens(tokens);
@@ -125,6 +141,12 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
125
141
  onShellsChange: (shells) => {
126
142
  setBackgroundShells([...shells]);
127
143
  },
144
+ onSubagentMessagesChange: (subagentId, messages) => {
145
+ setSubagentMessages((prev) => ({
146
+ ...prev,
147
+ [subagentId]: [...messages],
148
+ }));
149
+ },
128
150
  };
129
151
 
130
152
  try {
@@ -165,6 +187,15 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
165
187
  useEffect(() => {
166
188
  return () => {
167
189
  if (agentRef.current) {
190
+ try {
191
+ // Display usage summary before cleanup
192
+ const usages = agentRef.current.usages;
193
+ const sessionFilePath = agentRef.current.sessionFilePath;
194
+ displayUsageSummary(usages, sessionFilePath);
195
+ } catch {
196
+ // Silently ignore usage summary errors during cleanup
197
+ }
198
+
168
199
  agentRef.current.destroy();
169
200
  }
170
201
  };
@@ -292,6 +323,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
292
323
  killBackgroundShell,
293
324
  slashCommands,
294
325
  hasSlashCommand,
326
+ subagentMessages,
295
327
  };
296
328
 
297
329
  return (