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.
Files changed (105) hide show
  1. package/dist/commands/plugin/uninstall.js +1 -1
  2. package/dist/components/App.d.ts.map +1 -1
  3. package/dist/components/App.js +38 -2
  4. package/dist/components/BackgroundTaskManager.d.ts +6 -0
  5. package/dist/components/BackgroundTaskManager.d.ts.map +1 -0
  6. package/dist/components/BackgroundTaskManager.js +114 -0
  7. package/dist/components/ChatInterface.d.ts.map +1 -1
  8. package/dist/components/ChatInterface.js +39 -5
  9. package/dist/components/CommandSelector.d.ts.map +1 -1
  10. package/dist/components/CommandSelector.js +13 -5
  11. package/dist/components/CompressDisplay.d.ts.map +1 -1
  12. package/dist/components/CompressDisplay.js +6 -10
  13. package/dist/components/ConfirmationDetails.d.ts +9 -0
  14. package/dist/components/ConfirmationDetails.d.ts.map +1 -0
  15. package/dist/components/ConfirmationDetails.js +53 -0
  16. package/dist/components/{Confirmation.d.ts → ConfirmationSelector.d.ts} +3 -3
  17. package/dist/components/ConfirmationSelector.d.ts.map +1 -0
  18. package/dist/components/{Confirmation.js → ConfirmationSelector.js} +92 -101
  19. package/dist/components/DiffDisplay.d.ts +0 -1
  20. package/dist/components/DiffDisplay.d.ts.map +1 -1
  21. package/dist/components/DiffDisplay.js +82 -60
  22. package/dist/components/FileSelector.d.ts.map +1 -1
  23. package/dist/components/FileSelector.js +2 -2
  24. package/dist/components/HistorySearch.d.ts.map +1 -1
  25. package/dist/components/HistorySearch.js +12 -4
  26. package/dist/components/InputBox.d.ts +1 -3
  27. package/dist/components/InputBox.d.ts.map +1 -1
  28. package/dist/components/InputBox.js +9 -18
  29. package/dist/components/LoadingIndicator.d.ts +11 -0
  30. package/dist/components/LoadingIndicator.d.ts.map +1 -0
  31. package/dist/components/LoadingIndicator.js +6 -0
  32. package/dist/components/Markdown.d.ts.map +1 -1
  33. package/dist/components/Markdown.js +114 -120
  34. package/dist/components/MessageItem.d.ts.map +1 -1
  35. package/dist/components/MessageItem.js +1 -2
  36. package/dist/components/MessageList.d.ts +2 -3
  37. package/dist/components/MessageList.d.ts.map +1 -1
  38. package/dist/components/MessageList.js +7 -7
  39. package/dist/components/PlanDisplay.d.ts.map +1 -1
  40. package/dist/components/PlanDisplay.js +4 -12
  41. package/dist/components/PluginDetail.js +1 -1
  42. package/dist/components/RewindCommand.d.ts +4 -0
  43. package/dist/components/RewindCommand.d.ts.map +1 -1
  44. package/dist/components/RewindCommand.js +19 -2
  45. package/dist/components/SubagentBlock.d.ts.map +1 -1
  46. package/dist/components/SubagentBlock.js +12 -5
  47. package/dist/components/TaskList.d.ts +3 -0
  48. package/dist/components/TaskList.d.ts.map +1 -0
  49. package/dist/components/TaskList.js +49 -0
  50. package/dist/components/ToolResultDisplay.d.ts.map +1 -1
  51. package/dist/components/ToolResultDisplay.js +2 -1
  52. package/dist/contexts/useChat.d.ts +15 -6
  53. package/dist/contexts/useChat.d.ts.map +1 -1
  54. package/dist/contexts/useChat.js +52 -43
  55. package/dist/hooks/useInputManager.d.ts +2 -13
  56. package/dist/hooks/useInputManager.d.ts.map +1 -1
  57. package/dist/hooks/useInputManager.js +8 -57
  58. package/dist/hooks/usePluginManager.d.ts.map +1 -1
  59. package/dist/hooks/usePluginManager.js +8 -4
  60. package/dist/hooks/useTasks.d.ts +2 -0
  61. package/dist/hooks/useTasks.d.ts.map +1 -0
  62. package/dist/hooks/useTasks.js +5 -0
  63. package/dist/managers/InputManager.d.ts +5 -28
  64. package/dist/managers/InputManager.d.ts.map +1 -1
  65. package/dist/managers/InputManager.js +26 -127
  66. package/package.json +9 -10
  67. package/src/commands/plugin/uninstall.ts +1 -1
  68. package/src/components/App.tsx +50 -3
  69. package/src/components/{BashShellManager.tsx → BackgroundTaskManager.tsx} +79 -73
  70. package/src/components/ChatInterface.tsx +79 -23
  71. package/src/components/CommandSelector.tsx +38 -20
  72. package/src/components/CompressDisplay.tsx +5 -22
  73. package/src/components/ConfirmationDetails.tsx +108 -0
  74. package/src/components/{Confirmation.tsx → ConfirmationSelector.tsx} +162 -187
  75. package/src/components/DiffDisplay.tsx +122 -107
  76. package/src/components/FileSelector.tsx +0 -2
  77. package/src/components/HistorySearch.tsx +45 -21
  78. package/src/components/InputBox.tsx +14 -34
  79. package/src/components/LoadingIndicator.tsx +56 -0
  80. package/src/components/Markdown.tsx +126 -318
  81. package/src/components/MessageItem.tsx +1 -3
  82. package/src/components/MessageList.tsx +10 -67
  83. package/src/components/PlanDisplay.tsx +5 -33
  84. package/src/components/PluginDetail.tsx +1 -1
  85. package/src/components/RewindCommand.tsx +38 -1
  86. package/src/components/SubagentBlock.tsx +28 -14
  87. package/src/components/TaskList.tsx +70 -0
  88. package/src/components/ToolResultDisplay.tsx +6 -2
  89. package/src/contexts/useChat.tsx +82 -60
  90. package/src/hooks/useInputManager.ts +9 -73
  91. package/src/hooks/usePluginManager.ts +10 -4
  92. package/src/hooks/useTasks.ts +6 -0
  93. package/src/managers/InputManager.ts +30 -157
  94. package/dist/components/BashShellManager.d.ts +0 -6
  95. package/dist/components/BashShellManager.d.ts.map +0 -1
  96. package/dist/components/BashShellManager.js +0 -116
  97. package/dist/components/Confirmation.d.ts.map +0 -1
  98. package/dist/components/MemoryDisplay.d.ts +0 -8
  99. package/dist/components/MemoryDisplay.d.ts.map +0 -1
  100. package/dist/components/MemoryDisplay.js +0 -25
  101. package/dist/components/MemoryTypeSelector.d.ts +0 -8
  102. package/dist/components/MemoryTypeSelector.d.ts.map +0 -1
  103. package/dist/components/MemoryTypeSelector.js +0 -38
  104. package/src/components/MemoryDisplay.tsx +0 -62
  105. package/src/components/MemoryTypeSelector.tsx +0 -98
@@ -2,55 +2,57 @@ import React, { useState, useEffect } from "react";
2
2
  import { Box, Text, useInput } from "ink";
3
3
  import { useChat } from "../contexts/useChat.js";
4
4
 
5
- interface BashShell {
5
+ interface Task {
6
6
  id: string;
7
- command: string;
8
- status: "running" | "completed" | "killed";
7
+ type: string;
8
+ description?: string;
9
+ status: "running" | "completed" | "failed" | "killed";
9
10
  startTime: number;
10
11
  exitCode?: number;
11
12
  runtime?: number;
12
13
  }
13
14
 
14
- export interface BashShellManagerProps {
15
+ export interface BackgroundTaskManagerProps {
15
16
  onCancel: () => void;
16
17
  }
17
18
 
18
- export const BashShellManager: React.FC<BashShellManagerProps> = ({
19
+ export const BackgroundTaskManager: React.FC<BackgroundTaskManagerProps> = ({
19
20
  onCancel,
20
21
  }) => {
21
- const { backgroundShells, getBackgroundShellOutput, killBackgroundShell } =
22
+ const { backgroundTasks, getBackgroundTaskOutput, stopBackgroundTask } =
22
23
  useChat();
23
- const [shells, setShells] = useState<BashShell[]>([]);
24
+ const [tasks, setTasks] = useState<Task[]>([]);
24
25
  const [selectedIndex, setSelectedIndex] = useState(0);
25
26
  const [viewMode, setViewMode] = useState<"list" | "detail">("list");
26
- const [detailShellId, setDetailShellId] = useState<string | null>(null);
27
+ const [detailTaskId, setDetailTaskId] = useState<string | null>(null);
27
28
  const [detailOutput, setDetailOutput] = useState<{
28
29
  stdout: string;
29
30
  stderr: string;
30
31
  status: string;
31
32
  } | null>(null);
32
33
 
33
- // Convert backgroundShells to local BashShell format
34
+ // Convert backgroundTasks to local Task format
34
35
  useEffect(() => {
35
- setShells(
36
- backgroundShells.map((shell) => ({
37
- id: shell.id,
38
- command: shell.command,
39
- status: shell.status,
40
- startTime: shell.startTime,
41
- exitCode: shell.exitCode,
42
- runtime: shell.runtime,
36
+ setTasks(
37
+ backgroundTasks.map((task) => ({
38
+ id: task.id,
39
+ type: task.type,
40
+ description: task.description,
41
+ status: task.status,
42
+ startTime: task.startTime,
43
+ exitCode: task.exitCode,
44
+ runtime: task.runtime,
43
45
  })),
44
46
  );
45
- }, [backgroundShells]);
47
+ }, [backgroundTasks]);
46
48
 
47
- // Load detail output for selected shell
49
+ // Load detail output for selected task
48
50
  useEffect(() => {
49
- if (viewMode === "detail" && detailShellId) {
50
- const output = getBackgroundShellOutput(detailShellId);
51
+ if (viewMode === "detail" && detailTaskId) {
52
+ const output = getBackgroundTaskOutput(detailTaskId);
51
53
  setDetailOutput(output);
52
54
  }
53
- }, [viewMode, detailShellId, getBackgroundShellOutput]);
55
+ }, [viewMode, detailTaskId, getBackgroundTaskOutput]);
54
56
 
55
57
  const formatDuration = (ms: number): string => {
56
58
  if (ms < 1000) return `${ms}ms`;
@@ -64,17 +66,17 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
64
66
  return new Date(timestamp).toLocaleTimeString();
65
67
  };
66
68
 
67
- const killShell = (shellId: string) => {
68
- killBackgroundShell(shellId);
69
+ const stopTask = (taskId: string) => {
70
+ stopBackgroundTask(taskId);
69
71
  };
70
72
 
71
73
  useInput((input, key) => {
72
74
  if (viewMode === "list") {
73
75
  // List mode navigation
74
76
  if (key.return) {
75
- if (shells.length > 0 && selectedIndex < shells.length) {
76
- const selectedShell = shells[selectedIndex];
77
- setDetailShellId(selectedShell.id);
77
+ if (tasks.length > 0 && selectedIndex < tasks.length) {
78
+ const selectedTask = tasks[selectedIndex];
79
+ setDetailTaskId(selectedTask.id);
78
80
  setViewMode("detail");
79
81
  }
80
82
  return;
@@ -91,14 +93,14 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
91
93
  }
92
94
 
93
95
  if (key.downArrow) {
94
- setSelectedIndex(Math.min(shells.length - 1, selectedIndex + 1));
96
+ setSelectedIndex(Math.min(tasks.length - 1, selectedIndex + 1));
95
97
  return;
96
98
  }
97
99
 
98
- if (input === "k" && shells.length > 0 && selectedIndex < shells.length) {
99
- const selectedShell = shells[selectedIndex];
100
- if (selectedShell.status === "running") {
101
- killShell(selectedShell.id);
100
+ if (input === "k" && tasks.length > 0 && selectedIndex < tasks.length) {
101
+ const selectedTask = tasks[selectedIndex];
102
+ if (selectedTask.status === "running") {
103
+ stopTask(selectedTask.id);
102
104
  }
103
105
  return;
104
106
  }
@@ -106,24 +108,24 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
106
108
  // Detail mode navigation
107
109
  if (key.escape) {
108
110
  setViewMode("list");
109
- setDetailShellId(null);
111
+ setDetailTaskId(null);
110
112
  setDetailOutput(null);
111
113
  return;
112
114
  }
113
115
 
114
- if (input === "k" && detailShellId) {
115
- const shell = shells.find((s) => s.id === detailShellId);
116
- if (shell && shell.status === "running") {
117
- killShell(detailShellId);
116
+ if (input === "k" && detailTaskId) {
117
+ const task = tasks.find((t) => t.id === detailTaskId);
118
+ if (task && task.status === "running") {
119
+ stopTask(detailTaskId);
118
120
  }
119
121
  return;
120
122
  }
121
123
  }
122
124
  });
123
125
 
124
- if (viewMode === "detail" && detailShellId && detailOutput) {
125
- const shell = shells.find((s) => s.id === detailShellId);
126
- if (!shell) {
126
+ if (viewMode === "detail" && detailTaskId && detailOutput) {
127
+ const task = tasks.find((t) => t.id === detailTaskId);
128
+ if (!task) {
127
129
  setViewMode("list");
128
130
  return null;
129
131
  }
@@ -141,31 +143,37 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
141
143
  >
142
144
  <Box>
143
145
  <Text color="cyan" bold>
144
- Background Shell Details: {shell.id}
146
+ Background Task Details: {task.id}
145
147
  </Text>
146
148
  </Box>
147
149
 
148
150
  <Box flexDirection="column" gap={1}>
149
151
  <Box>
150
152
  <Text>
151
- <Text color="blue">Command:</Text> {shell.command}
153
+ <Text color="blue">Type:</Text> {task.type}
152
154
  </Text>
153
155
  </Box>
156
+ {task.description && (
157
+ <Box>
158
+ <Text>
159
+ <Text color="blue">Description:</Text> {task.description}
160
+ </Text>
161
+ </Box>
162
+ )}
154
163
  <Box>
155
164
  <Text>
156
- <Text color="blue">Status:</Text> {shell.status}
157
- {shell.exitCode !== undefined &&
158
- ` (exit code: ${shell.exitCode})`}
165
+ <Text color="blue">Status:</Text> {task.status}
166
+ {task.exitCode !== undefined && ` (exit code: ${task.exitCode})`}
159
167
  </Text>
160
168
  </Box>
161
169
  <Box>
162
170
  <Text>
163
- <Text color="blue">Started:</Text> {formatTime(shell.startTime)}
164
- {shell.runtime !== undefined && (
171
+ <Text color="blue">Started:</Text> {formatTime(task.startTime)}
172
+ {task.runtime !== undefined && (
165
173
  <Text>
166
174
  {" "}
167
175
  | <Text color="blue">Runtime:</Text>{" "}
168
- {formatDuration(shell.runtime)}
176
+ {formatDuration(task.runtime)}
169
177
  </Text>
170
178
  )}
171
179
  </Text>
@@ -175,7 +183,7 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
175
183
  {detailOutput.stdout && (
176
184
  <Box flexDirection="column" marginTop={1}>
177
185
  <Text color="green" bold>
178
- STDOUT (last 10 lines):
186
+ OUTPUT (last 10 lines):
179
187
  </Text>
180
188
  <Box borderStyle="single" borderColor="green" padding={1}>
181
189
  <Text>
@@ -188,7 +196,7 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
188
196
  {detailOutput.stderr && (
189
197
  <Box flexDirection="column" marginTop={1}>
190
198
  <Text color="red" bold>
191
- STDERR:
199
+ ERRORS:
192
200
  </Text>
193
201
  <Box borderStyle="single" borderColor="red" padding={1}>
194
202
  <Text color="red">
@@ -200,14 +208,14 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
200
208
 
201
209
  <Box marginTop={1}>
202
210
  <Text dimColor>
203
- {shell.status === "running" ? "k to kill · " : ""}Esc to go back
211
+ {task.status === "running" ? "k to stop · " : ""}Esc to go back
204
212
  </Text>
205
213
  </Box>
206
214
  </Box>
207
215
  );
208
216
  }
209
217
 
210
- if (!backgroundShells) {
218
+ if (!backgroundTasks) {
211
219
  return (
212
220
  <Box
213
221
  flexDirection="column"
@@ -219,15 +227,15 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
219
227
  paddingTop={1}
220
228
  >
221
229
  <Text color="cyan" bold>
222
- Background Bash Shells
230
+ Background Tasks
223
231
  </Text>
224
- <Text>Background bash shells not available</Text>
232
+ <Text>Background tasks not available</Text>
225
233
  <Text dimColor>Press Escape to close</Text>
226
234
  </Box>
227
235
  );
228
236
  }
229
237
 
230
- if (shells.length === 0) {
238
+ if (tasks.length === 0) {
231
239
  return (
232
240
  <Box
233
241
  flexDirection="column"
@@ -239,9 +247,9 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
239
247
  paddingTop={1}
240
248
  >
241
249
  <Text color="cyan" bold>
242
- Background Bash Shells
250
+ Background Tasks
243
251
  </Text>
244
- <Text>No background shells found</Text>
252
+ <Text>No background tasks found</Text>
245
253
  <Text dimColor>Press Escape to close</Text>
246
254
  </Box>
247
255
  );
@@ -260,42 +268,40 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
260
268
  >
261
269
  <Box>
262
270
  <Text color="cyan" bold>
263
- Background Bash Shells
271
+ Background Tasks
264
272
  </Text>
265
273
  </Box>
266
- <Text dimColor>Select a shell to view details</Text>
274
+ <Text dimColor>Select a task to view details</Text>
267
275
 
268
- {shells.map((shell, index) => (
269
- <Box key={shell.id} flexDirection="column">
276
+ {tasks.map((task, index) => (
277
+ <Box key={task.id} flexDirection="column">
270
278
  <Text
271
279
  color={index === selectedIndex ? "black" : "white"}
272
280
  backgroundColor={index === selectedIndex ? "cyan" : undefined}
273
281
  >
274
282
  {index === selectedIndex ? "▶ " : " "}
275
- {index + 1}.{" "}
276
- {shell.command.length > 50
277
- ? shell.command.substring(0, 47) + "..."
278
- : shell.command}
283
+ {index + 1}. [{task.id}] {task.type}
284
+ {task.description ? `: ${task.description}` : ""}
279
285
  <Text
280
286
  color={
281
- shell.status === "running"
287
+ task.status === "running"
282
288
  ? "green"
283
- : shell.status === "completed"
289
+ : task.status === "completed"
284
290
  ? "blue"
285
291
  : "red"
286
292
  }
287
293
  >
288
294
  {" "}
289
- ({shell.status})
295
+ ({task.status})
290
296
  </Text>
291
297
  </Text>
292
298
  {index === selectedIndex && (
293
299
  <Box marginLeft={4} flexDirection="column">
294
300
  <Text color="gray" dimColor>
295
- ID: {shell.id} | Started: {formatTime(shell.startTime)}
296
- {shell.runtime !== undefined &&
297
- ` | Runtime: ${formatDuration(shell.runtime)}`}
298
- {shell.exitCode !== undefined && ` | Exit: ${shell.exitCode}`}
301
+ Started: {formatTime(task.startTime)}
302
+ {task.runtime !== undefined &&
303
+ ` | Runtime: ${formatDuration(task.runtime)}`}
304
+ {task.exitCode !== undefined && ` | Exit: ${task.exitCode}`}
299
305
  </Text>
300
306
  </Box>
301
307
  )}
@@ -305,7 +311,7 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
305
311
  <Box marginTop={1}>
306
312
  <Text dimColor>
307
313
  ↑/↓ to select · Enter to view ·{" "}
308
- {shells[selectedIndex]?.status === "running" ? "k to kill · " : ""}Esc
314
+ {tasks[selectedIndex]?.status === "running" ? "k to stop · " : ""}Esc
309
315
  to close
310
316
  </Text>
311
317
  </Box>
@@ -1,20 +1,26 @@
1
- import React from "react";
2
- import { Box } from "ink";
1
+ import React, { useState, useCallback } from "react";
2
+ import { Box, useStdout } from "ink";
3
3
  import { MessageList } from "./MessageList.js";
4
4
  import { InputBox } from "./InputBox.js";
5
- import { Confirmation } from "./Confirmation.js";
5
+ import { LoadingIndicator } from "./LoadingIndicator.js";
6
+ import { TaskList } from "./TaskList.js";
7
+ import { ConfirmationDetails } from "./ConfirmationDetails.js";
8
+ import { ConfirmationSelector } from "./ConfirmationSelector.js";
9
+
6
10
  import { useChat } from "../contexts/useChat.js";
11
+ import type { PermissionDecision } from "wave-agent-sdk";
7
12
 
8
13
  export const ChatInterface: React.FC = () => {
14
+ const { stdout } = useStdout();
15
+ const [isDetailsTooTall, setIsDetailsTooTall] = useState(false);
16
+
9
17
  const {
10
18
  messages,
11
19
  isLoading,
12
20
  isCommandRunning,
13
- userInputHistory,
14
21
  isCompressing,
15
22
  sendMessage,
16
23
  abortMessage,
17
- saveMemory,
18
24
  mcpServers,
19
25
  connectMcpServer,
20
26
  disconnectMcpServer,
@@ -26,45 +32,95 @@ export const ChatInterface: React.FC = () => {
26
32
  isConfirmationVisible,
27
33
  confirmingTool,
28
34
  handleConfirmationDecision,
29
- handleConfirmationCancel,
30
- rewindId,
35
+ handleConfirmationCancel: originalHandleConfirmationCancel,
36
+ setWasLastDetailsTooTall,
31
37
  } = useChat();
32
38
 
39
+ const handleHeightMeasured = useCallback(
40
+ (height: number) => {
41
+ const terminalHeight = stdout?.rows || 24;
42
+ if (height > terminalHeight - 10) {
43
+ setIsDetailsTooTall(true);
44
+ } else {
45
+ setIsDetailsTooTall(false);
46
+ }
47
+ },
48
+ [stdout?.rows],
49
+ );
50
+
51
+ const handleConfirmationCancel = useCallback(() => {
52
+ if (isDetailsTooTall) {
53
+ setWasLastDetailsTooTall((prev) => prev + 1);
54
+ setIsDetailsTooTall(false);
55
+ }
56
+ originalHandleConfirmationCancel();
57
+ }, [
58
+ isDetailsTooTall,
59
+ originalHandleConfirmationCancel,
60
+ setWasLastDetailsTooTall,
61
+ ]);
62
+
63
+ const wrappedHandleConfirmationDecision = useCallback(
64
+ (decision: PermissionDecision) => {
65
+ if (isDetailsTooTall) {
66
+ setWasLastDetailsTooTall((prev) => prev + 1);
67
+ setIsDetailsTooTall(false);
68
+ }
69
+ handleConfirmationDecision(decision);
70
+ },
71
+ [isDetailsTooTall, handleConfirmationDecision, setWasLastDetailsTooTall],
72
+ );
73
+
33
74
  if (!sessionId) return null;
34
75
 
35
76
  return (
36
- <Box flexDirection="column" height="100%" paddingY={1} paddingRight={1}>
77
+ <Box flexDirection="column">
37
78
  <MessageList
38
79
  messages={messages}
39
80
  isLoading={isLoading}
40
81
  isCommandRunning={isCommandRunning}
41
- isCompressing={isCompressing}
42
- latestTotalTokens={latestTotalTokens}
43
82
  isExpanded={isExpanded}
44
- key={String(isExpanded) + sessionId + rewindId}
83
+ forceStaticLastMessage={isDetailsTooTall}
45
84
  />
46
85
 
86
+ {(isLoading || isCommandRunning || isCompressing) &&
87
+ !isConfirmationVisible && (
88
+ <LoadingIndicator
89
+ isLoading={isLoading}
90
+ isCommandRunning={isCommandRunning}
91
+ isCompressing={isCompressing}
92
+ latestTotalTokens={latestTotalTokens}
93
+ />
94
+ )}
95
+ {!isConfirmationVisible && <TaskList />}
96
+
47
97
  {isConfirmationVisible && (
48
- <Confirmation
49
- toolName={confirmingTool!.name}
50
- toolInput={confirmingTool!.input}
51
- suggestedPrefix={confirmingTool!.suggestedPrefix}
52
- hidePersistentOption={confirmingTool!.hidePersistentOption}
53
- isExpanded={isExpanded}
54
- onDecision={handleConfirmationDecision}
55
- onCancel={handleConfirmationCancel}
56
- onAbort={abortMessage}
57
- />
98
+ <>
99
+ <ConfirmationDetails
100
+ toolName={confirmingTool!.name}
101
+ toolInput={confirmingTool!.input}
102
+ isExpanded={isExpanded}
103
+ onHeightMeasured={handleHeightMeasured}
104
+ />
105
+ <ConfirmationSelector
106
+ toolName={confirmingTool!.name}
107
+ toolInput={confirmingTool!.input}
108
+ suggestedPrefix={confirmingTool!.suggestedPrefix}
109
+ hidePersistentOption={confirmingTool!.hidePersistentOption}
110
+ isExpanded={isExpanded}
111
+ onDecision={wrappedHandleConfirmationDecision}
112
+ onCancel={handleConfirmationCancel}
113
+ onAbort={abortMessage}
114
+ />
115
+ </>
58
116
  )}
59
117
 
60
118
  {!isConfirmationVisible && !isExpanded && (
61
119
  <InputBox
62
120
  isLoading={isLoading}
63
121
  isCommandRunning={isCommandRunning}
64
- userInputHistory={userInputHistory}
65
122
  sendMessage={sendMessage}
66
123
  abortMessage={abortMessage}
67
- saveMemory={saveMemory}
68
124
  mcpServers={mcpServers}
69
125
  connectMcpServer={connectMcpServer}
70
126
  disconnectMcpServer={disconnectMcpServer}
@@ -4,9 +4,9 @@ import type { SlashCommand } from "wave-agent-sdk";
4
4
 
5
5
  const AVAILABLE_COMMANDS: SlashCommand[] = [
6
6
  {
7
- id: "bashes",
8
- name: "bashes",
9
- description: "View and manage background bash shells",
7
+ id: "tasks",
8
+ name: "tasks",
9
+ description: "View and manage background tasks (shells and subagents)",
10
10
  handler: () => {}, // Handler here won't be used, actual processing is in the hook
11
11
  },
12
12
  {
@@ -39,6 +39,7 @@ export const CommandSelector: React.FC<CommandSelectorProps> = ({
39
39
  onCancel,
40
40
  commands = [], // Default to empty array
41
41
  }) => {
42
+ const MAX_VISIBLE_ITEMS = 3;
42
43
  const [selectedIndex, setSelectedIndex] = useState(0);
43
44
 
44
45
  // Merge agent commands and local commands
@@ -51,6 +52,19 @@ export const CommandSelector: React.FC<CommandSelectorProps> = ({
51
52
  command.id.toLowerCase().includes(searchQuery.toLowerCase()),
52
53
  );
53
54
 
55
+ // Calculate visible window
56
+ const startIndex = Math.max(
57
+ 0,
58
+ Math.min(
59
+ selectedIndex - Math.floor(MAX_VISIBLE_ITEMS / 2),
60
+ Math.max(0, filteredCommands.length - MAX_VISIBLE_ITEMS),
61
+ ),
62
+ );
63
+ const visibleCommands = filteredCommands.slice(
64
+ startIndex,
65
+ startIndex + MAX_VISIBLE_ITEMS,
66
+ );
67
+
54
68
  useInput((input, key) => {
55
69
  if (key.return) {
56
70
  if (
@@ -101,7 +115,6 @@ export const CommandSelector: React.FC<CommandSelectorProps> = ({
101
115
  borderBottom={false}
102
116
  borderLeft={false}
103
117
  borderRight={false}
104
- paddingTop={1}
105
118
  >
106
119
  <Text color="yellow">No commands found for "{searchQuery}"</Text>
107
120
  <Text dimColor>Press Escape to cancel</Text>
@@ -117,7 +130,6 @@ export const CommandSelector: React.FC<CommandSelectorProps> = ({
117
130
  borderBottom={false}
118
131
  borderLeft={false}
119
132
  borderRight={false}
120
- paddingTop={1}
121
133
  gap={1}
122
134
  >
123
135
  <Box>
@@ -126,23 +138,29 @@ export const CommandSelector: React.FC<CommandSelectorProps> = ({
126
138
  </Text>
127
139
  </Box>
128
140
 
129
- {filteredCommands.map((command, index) => (
130
- <Box key={command.id} flexDirection="column">
131
- <Text
132
- color={index === selectedIndex ? "black" : "white"}
133
- backgroundColor={index === selectedIndex ? "magenta" : undefined}
134
- >
135
- {index === selectedIndex ? "▶ " : " "}/{command.id}
136
- </Text>
137
- {index === selectedIndex && (
138
- <Box marginLeft={4}>
139
- <Text color="gray" dimColor>
140
- {command.description}
141
+ <Box flexDirection="column">
142
+ {visibleCommands.map((command, index) => {
143
+ const actualIndex = startIndex + index;
144
+ const isSelected = actualIndex === selectedIndex;
145
+ return (
146
+ <Box key={command.id} flexDirection="column">
147
+ <Text
148
+ color={isSelected ? "black" : "white"}
149
+ backgroundColor={isSelected ? "magenta" : undefined}
150
+ >
151
+ {isSelected ? "" : " "}/{command.id}
141
152
  </Text>
153
+ {isSelected && (
154
+ <Box marginLeft={4}>
155
+ <Text color="gray" dimColor>
156
+ {command.description}
157
+ </Text>
158
+ </Box>
159
+ )}
142
160
  </Box>
143
- )}
144
- </Box>
145
- ))}
161
+ );
162
+ })}
163
+ </Box>
146
164
 
147
165
  <Box>
148
166
  <Text dimColor>
@@ -7,25 +7,16 @@ interface CompressDisplayProps {
7
7
  isExpanded?: boolean;
8
8
  }
9
9
 
10
- export const CompressDisplay: React.FC<CompressDisplayProps> = ({
11
- block,
12
- isExpanded = false,
13
- }) => {
10
+ export const CompressDisplay: React.FC<CompressDisplayProps> = ({ block }) => {
14
11
  const { content } = block;
15
- const MAX_LINES = 3; // Set maximum display lines for compressed content
16
12
 
17
- const { displayContent, isOverflowing } = useMemo(() => {
13
+ const { displayContent } = useMemo(() => {
18
14
  if (!content) {
19
- return { displayContent: "", isOverflowing: false };
15
+ return { displayContent: "" };
20
16
  }
21
17
 
22
- const lines = content.split("\n");
23
- const overflow = !isExpanded && lines.length > MAX_LINES;
24
-
25
- const display = overflow ? lines.slice(0, MAX_LINES).join("\n") : content;
26
-
27
- return { displayContent: display, isOverflowing: overflow };
28
- }, [content, isExpanded]);
18
+ return { displayContent: content };
19
+ }, [content]);
29
20
 
30
21
  return (
31
22
  <Box flexDirection="column">
@@ -43,14 +34,6 @@ export const CompressDisplay: React.FC<CompressDisplayProps> = ({
43
34
  >
44
35
  <Text color="white">{displayContent}</Text>
45
36
  </Box>
46
- {isOverflowing && (
47
- <Box paddingLeft={2} marginTop={1}>
48
- <Text color="yellow" dimColor>
49
- Content truncated ({content.split("\n").length} lines total,
50
- showing first {MAX_LINES} lines. Press Ctrl+O to expand.
51
- </Text>
52
- </Box>
53
- )}
54
37
  </Box>
55
38
  )}
56
39
  </Box>