wave-code 0.4.0 → 0.5.0

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 (50) hide show
  1. package/dist/commands/plugin/uninstall.js +1 -1
  2. package/dist/components/CommandSelector.js +3 -3
  3. package/dist/components/Confirmation.d.ts.map +1 -1
  4. package/dist/components/Confirmation.js +72 -19
  5. package/dist/components/DiffDisplay.d.ts +0 -1
  6. package/dist/components/DiffDisplay.d.ts.map +1 -1
  7. package/dist/components/DiffDisplay.js +38 -59
  8. package/dist/components/InputBox.d.ts.map +1 -1
  9. package/dist/components/InputBox.js +6 -5
  10. package/dist/components/Markdown.d.ts.map +1 -1
  11. package/dist/components/Markdown.js +2 -1
  12. package/dist/components/PlanDisplay.d.ts.map +1 -1
  13. package/dist/components/PlanDisplay.js +2 -2
  14. package/dist/components/PluginDetail.js +1 -1
  15. package/dist/components/SubagentBlock.d.ts.map +1 -1
  16. package/dist/components/SubagentBlock.js +4 -0
  17. package/dist/components/TaskManager.d.ts +6 -0
  18. package/dist/components/TaskManager.d.ts.map +1 -0
  19. package/dist/components/TaskManager.js +114 -0
  20. package/dist/components/ToolResultDisplay.d.ts.map +1 -1
  21. package/dist/components/ToolResultDisplay.js +2 -1
  22. package/dist/contexts/useChat.d.ts +5 -4
  23. package/dist/contexts/useChat.d.ts.map +1 -1
  24. package/dist/contexts/useChat.js +16 -12
  25. package/dist/hooks/useInputManager.d.ts +2 -2
  26. package/dist/hooks/useInputManager.js +10 -10
  27. package/dist/hooks/usePluginManager.d.ts.map +1 -1
  28. package/dist/hooks/usePluginManager.js +8 -4
  29. package/dist/managers/InputManager.d.ts +7 -6
  30. package/dist/managers/InputManager.d.ts.map +1 -1
  31. package/dist/managers/InputManager.js +17 -12
  32. package/package.json +6 -6
  33. package/src/commands/plugin/uninstall.ts +1 -1
  34. package/src/components/CommandSelector.tsx +3 -3
  35. package/src/components/Confirmation.tsx +114 -24
  36. package/src/components/DiffDisplay.tsx +60 -106
  37. package/src/components/InputBox.tsx +9 -7
  38. package/src/components/Markdown.tsx +7 -2
  39. package/src/components/PlanDisplay.tsx +14 -19
  40. package/src/components/PluginDetail.tsx +1 -1
  41. package/src/components/SubagentBlock.tsx +5 -0
  42. package/src/components/{BashShellManager.tsx → TaskManager.tsx} +79 -75
  43. package/src/components/ToolResultDisplay.tsx +4 -0
  44. package/src/contexts/useChat.tsx +25 -20
  45. package/src/hooks/useInputManager.ts +10 -10
  46. package/src/hooks/usePluginManager.ts +10 -4
  47. package/src/managers/InputManager.ts +22 -15
  48. package/dist/components/BashShellManager.d.ts +0 -6
  49. package/dist/components/BashShellManager.d.ts.map +0 -1
  50. package/dist/components/BashShellManager.js +0 -116
@@ -2,55 +2,55 @@ 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 TaskManagerProps {
15
16
  onCancel: () => void;
16
17
  }
17
18
 
18
- export const BashShellManager: React.FC<BashShellManagerProps> = ({
19
- onCancel,
20
- }) => {
21
- const { backgroundShells, getBackgroundShellOutput, killBackgroundShell } =
19
+ export const TaskManager: React.FC<TaskManagerProps> = ({ onCancel }) => {
20
+ const { backgroundTasks, getBackgroundTaskOutput, stopBackgroundTask } =
22
21
  useChat();
23
- const [shells, setShells] = useState<BashShell[]>([]);
22
+ const [tasks, setTasks] = useState<Task[]>([]);
24
23
  const [selectedIndex, setSelectedIndex] = useState(0);
25
24
  const [viewMode, setViewMode] = useState<"list" | "detail">("list");
26
- const [detailShellId, setDetailShellId] = useState<string | null>(null);
25
+ const [detailTaskId, setDetailTaskId] = useState<string | null>(null);
27
26
  const [detailOutput, setDetailOutput] = useState<{
28
27
  stdout: string;
29
28
  stderr: string;
30
29
  status: string;
31
30
  } | null>(null);
32
31
 
33
- // Convert backgroundShells to local BashShell format
32
+ // Convert backgroundTasks to local Task format
34
33
  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,
34
+ setTasks(
35
+ backgroundTasks.map((task) => ({
36
+ id: task.id,
37
+ type: task.type,
38
+ description: task.description,
39
+ status: task.status,
40
+ startTime: task.startTime,
41
+ exitCode: task.exitCode,
42
+ runtime: task.runtime,
43
43
  })),
44
44
  );
45
- }, [backgroundShells]);
45
+ }, [backgroundTasks]);
46
46
 
47
- // Load detail output for selected shell
47
+ // Load detail output for selected task
48
48
  useEffect(() => {
49
- if (viewMode === "detail" && detailShellId) {
50
- const output = getBackgroundShellOutput(detailShellId);
49
+ if (viewMode === "detail" && detailTaskId) {
50
+ const output = getBackgroundTaskOutput(detailTaskId);
51
51
  setDetailOutput(output);
52
52
  }
53
- }, [viewMode, detailShellId, getBackgroundShellOutput]);
53
+ }, [viewMode, detailTaskId, getBackgroundTaskOutput]);
54
54
 
55
55
  const formatDuration = (ms: number): string => {
56
56
  if (ms < 1000) return `${ms}ms`;
@@ -64,17 +64,17 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
64
64
  return new Date(timestamp).toLocaleTimeString();
65
65
  };
66
66
 
67
- const killShell = (shellId: string) => {
68
- killBackgroundShell(shellId);
67
+ const stopTask = (taskId: string) => {
68
+ stopBackgroundTask(taskId);
69
69
  };
70
70
 
71
71
  useInput((input, key) => {
72
72
  if (viewMode === "list") {
73
73
  // List mode navigation
74
74
  if (key.return) {
75
- if (shells.length > 0 && selectedIndex < shells.length) {
76
- const selectedShell = shells[selectedIndex];
77
- setDetailShellId(selectedShell.id);
75
+ if (tasks.length > 0 && selectedIndex < tasks.length) {
76
+ const selectedTask = tasks[selectedIndex];
77
+ setDetailTaskId(selectedTask.id);
78
78
  setViewMode("detail");
79
79
  }
80
80
  return;
@@ -91,14 +91,14 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
91
91
  }
92
92
 
93
93
  if (key.downArrow) {
94
- setSelectedIndex(Math.min(shells.length - 1, selectedIndex + 1));
94
+ setSelectedIndex(Math.min(tasks.length - 1, selectedIndex + 1));
95
95
  return;
96
96
  }
97
97
 
98
- if (input === "k" && shells.length > 0 && selectedIndex < shells.length) {
99
- const selectedShell = shells[selectedIndex];
100
- if (selectedShell.status === "running") {
101
- killShell(selectedShell.id);
98
+ if (input === "k" && tasks.length > 0 && selectedIndex < tasks.length) {
99
+ const selectedTask = tasks[selectedIndex];
100
+ if (selectedTask.status === "running") {
101
+ stopTask(selectedTask.id);
102
102
  }
103
103
  return;
104
104
  }
@@ -106,24 +106,24 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
106
106
  // Detail mode navigation
107
107
  if (key.escape) {
108
108
  setViewMode("list");
109
- setDetailShellId(null);
109
+ setDetailTaskId(null);
110
110
  setDetailOutput(null);
111
111
  return;
112
112
  }
113
113
 
114
- if (input === "k" && detailShellId) {
115
- const shell = shells.find((s) => s.id === detailShellId);
116
- if (shell && shell.status === "running") {
117
- killShell(detailShellId);
114
+ if (input === "k" && detailTaskId) {
115
+ const task = tasks.find((t) => t.id === detailTaskId);
116
+ if (task && task.status === "running") {
117
+ stopTask(detailTaskId);
118
118
  }
119
119
  return;
120
120
  }
121
121
  }
122
122
  });
123
123
 
124
- if (viewMode === "detail" && detailShellId && detailOutput) {
125
- const shell = shells.find((s) => s.id === detailShellId);
126
- if (!shell) {
124
+ if (viewMode === "detail" && detailTaskId && detailOutput) {
125
+ const task = tasks.find((t) => t.id === detailTaskId);
126
+ if (!task) {
127
127
  setViewMode("list");
128
128
  return null;
129
129
  }
@@ -141,31 +141,37 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
141
141
  >
142
142
  <Box>
143
143
  <Text color="cyan" bold>
144
- Background Shell Details: {shell.id}
144
+ Background Task Details: {task.id}
145
145
  </Text>
146
146
  </Box>
147
147
 
148
148
  <Box flexDirection="column" gap={1}>
149
149
  <Box>
150
150
  <Text>
151
- <Text color="blue">Command:</Text> {shell.command}
151
+ <Text color="blue">Type:</Text> {task.type}
152
152
  </Text>
153
153
  </Box>
154
+ {task.description && (
155
+ <Box>
156
+ <Text>
157
+ <Text color="blue">Description:</Text> {task.description}
158
+ </Text>
159
+ </Box>
160
+ )}
154
161
  <Box>
155
162
  <Text>
156
- <Text color="blue">Status:</Text> {shell.status}
157
- {shell.exitCode !== undefined &&
158
- ` (exit code: ${shell.exitCode})`}
163
+ <Text color="blue">Status:</Text> {task.status}
164
+ {task.exitCode !== undefined && ` (exit code: ${task.exitCode})`}
159
165
  </Text>
160
166
  </Box>
161
167
  <Box>
162
168
  <Text>
163
- <Text color="blue">Started:</Text> {formatTime(shell.startTime)}
164
- {shell.runtime !== undefined && (
169
+ <Text color="blue">Started:</Text> {formatTime(task.startTime)}
170
+ {task.runtime !== undefined && (
165
171
  <Text>
166
172
  {" "}
167
173
  | <Text color="blue">Runtime:</Text>{" "}
168
- {formatDuration(shell.runtime)}
174
+ {formatDuration(task.runtime)}
169
175
  </Text>
170
176
  )}
171
177
  </Text>
@@ -175,7 +181,7 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
175
181
  {detailOutput.stdout && (
176
182
  <Box flexDirection="column" marginTop={1}>
177
183
  <Text color="green" bold>
178
- STDOUT (last 10 lines):
184
+ OUTPUT (last 10 lines):
179
185
  </Text>
180
186
  <Box borderStyle="single" borderColor="green" padding={1}>
181
187
  <Text>
@@ -188,7 +194,7 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
188
194
  {detailOutput.stderr && (
189
195
  <Box flexDirection="column" marginTop={1}>
190
196
  <Text color="red" bold>
191
- STDERR:
197
+ ERRORS:
192
198
  </Text>
193
199
  <Box borderStyle="single" borderColor="red" padding={1}>
194
200
  <Text color="red">
@@ -200,14 +206,14 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
200
206
 
201
207
  <Box marginTop={1}>
202
208
  <Text dimColor>
203
- {shell.status === "running" ? "k to kill · " : ""}Esc to go back
209
+ {task.status === "running" ? "k to stop · " : ""}Esc to go back
204
210
  </Text>
205
211
  </Box>
206
212
  </Box>
207
213
  );
208
214
  }
209
215
 
210
- if (!backgroundShells) {
216
+ if (!backgroundTasks) {
211
217
  return (
212
218
  <Box
213
219
  flexDirection="column"
@@ -219,15 +225,15 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
219
225
  paddingTop={1}
220
226
  >
221
227
  <Text color="cyan" bold>
222
- Background Bash Shells
228
+ Background Tasks
223
229
  </Text>
224
- <Text>Background bash shells not available</Text>
230
+ <Text>Background tasks not available</Text>
225
231
  <Text dimColor>Press Escape to close</Text>
226
232
  </Box>
227
233
  );
228
234
  }
229
235
 
230
- if (shells.length === 0) {
236
+ if (tasks.length === 0) {
231
237
  return (
232
238
  <Box
233
239
  flexDirection="column"
@@ -239,9 +245,9 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
239
245
  paddingTop={1}
240
246
  >
241
247
  <Text color="cyan" bold>
242
- Background Bash Shells
248
+ Background Tasks
243
249
  </Text>
244
- <Text>No background shells found</Text>
250
+ <Text>No background tasks found</Text>
245
251
  <Text dimColor>Press Escape to close</Text>
246
252
  </Box>
247
253
  );
@@ -260,42 +266,40 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
260
266
  >
261
267
  <Box>
262
268
  <Text color="cyan" bold>
263
- Background Bash Shells
269
+ Background Tasks
264
270
  </Text>
265
271
  </Box>
266
- <Text dimColor>Select a shell to view details</Text>
272
+ <Text dimColor>Select a task to view details</Text>
267
273
 
268
- {shells.map((shell, index) => (
269
- <Box key={shell.id} flexDirection="column">
274
+ {tasks.map((task, index) => (
275
+ <Box key={task.id} flexDirection="column">
270
276
  <Text
271
277
  color={index === selectedIndex ? "black" : "white"}
272
278
  backgroundColor={index === selectedIndex ? "cyan" : undefined}
273
279
  >
274
280
  {index === selectedIndex ? "▶ " : " "}
275
- {index + 1}.{" "}
276
- {shell.command.length > 50
277
- ? shell.command.substring(0, 47) + "..."
278
- : shell.command}
281
+ {index + 1}. [{task.id}] {task.type}
282
+ {task.description ? `: ${task.description}` : ""}
279
283
  <Text
280
284
  color={
281
- shell.status === "running"
285
+ task.status === "running"
282
286
  ? "green"
283
- : shell.status === "completed"
287
+ : task.status === "completed"
284
288
  ? "blue"
285
289
  : "red"
286
290
  }
287
291
  >
288
292
  {" "}
289
- ({shell.status})
293
+ ({task.status})
290
294
  </Text>
291
295
  </Text>
292
296
  {index === selectedIndex && (
293
297
  <Box marginLeft={4} flexDirection="column">
294
298
  <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}`}
299
+ Started: {formatTime(task.startTime)}
300
+ {task.runtime !== undefined &&
301
+ ` | Runtime: ${formatDuration(task.runtime)}`}
302
+ {task.exitCode !== undefined && ` | Exit: ${task.exitCode}`}
299
303
  </Text>
300
304
  </Box>
301
305
  )}
@@ -305,7 +309,7 @@ export const BashShellManager: React.FC<BashShellManagerProps> = ({
305
309
  <Box marginTop={1}>
306
310
  <Text dimColor>
307
311
  ↑/↓ to select · Enter to view ·{" "}
308
- {shells[selectedIndex]?.status === "running" ? "k to kill · " : ""}Esc
312
+ {tasks[selectedIndex]?.status === "running" ? "k to stop · " : ""}Esc
309
313
  to close
310
314
  </Text>
311
315
  </Box>
@@ -44,6 +44,9 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
44
44
 
45
45
  const toolName = name ? String(name) : "Tool";
46
46
 
47
+ const isBackgroundable =
48
+ stage === "running" && (toolName === "Bash" || toolName === "Task");
49
+
47
50
  // Get shortResult, if not available show last 5 lines of result
48
51
  const getShortResult = () => {
49
52
  if (block.shortResult) {
@@ -76,6 +79,7 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
76
79
  <Text color={getStatusColor()}> {getStatusText()}</Text>
77
80
  {/* Display image indicator */}
78
81
  {hasImages() && <Text color="blue"> {getImageIndicator()}</Text>}
82
+ {isBackgroundable && <Text color="gray"> [Ctrl-B] Background</Text>}
79
83
  </Box>
80
84
 
81
85
  {/* Display shortResult in collapsed state */}
@@ -11,7 +11,7 @@ import { useAppConfig } from "./useAppConfig.js";
11
11
  import type {
12
12
  Message,
13
13
  McpServerStatus,
14
- BackgroundShell,
14
+ BackgroundTask,
15
15
  SlashCommand,
16
16
  PermissionDecision,
17
17
  PermissionMode,
@@ -47,12 +47,12 @@ export interface ChatContextType {
47
47
  mcpServers: McpServerStatus[];
48
48
  connectMcpServer: (serverName: string) => Promise<boolean>;
49
49
  disconnectMcpServer: (serverName: string) => Promise<boolean>;
50
- // Background bash shells
51
- backgroundShells: BackgroundShell[];
52
- getBackgroundShellOutput: (
53
- shellId: string,
50
+ // Background tasks
51
+ backgroundTasks: BackgroundTask[];
52
+ getBackgroundTaskOutput: (
53
+ taskId: string,
54
54
  ) => { stdout: string; stderr: string; status: string } | null;
55
- killBackgroundShell: (shellId: string) => boolean;
55
+ stopBackgroundTask: (taskId: string) => boolean;
56
56
  // Slash Command functionality
57
57
  slashCommands: SlashCommand[];
58
58
  hasSlashCommand: (commandId: string) => boolean;
@@ -78,6 +78,8 @@ export interface ChatContextType {
78
78
  hideConfirmation: () => void;
79
79
  handleConfirmationDecision: (decision: PermissionDecision) => void;
80
80
  handleConfirmationCancel: () => void;
81
+ // Background current task
82
+ backgroundCurrentTask: () => void;
81
83
  // Rewind functionality
82
84
  rewindId: number;
83
85
  handleRewindSelect: (index: number) => Promise<void>;
@@ -121,10 +123,8 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
121
123
  // MCP State
122
124
  const [mcpServers, setMcpServers] = useState<McpServerStatus[]>([]);
123
125
 
124
- // Background bash shells state
125
- const [backgroundShells, setBackgroundShells] = useState<BackgroundShell[]>(
126
- [],
127
- );
126
+ // Background tasks state
127
+ const [backgroundTasks, setBackgroundTasks] = useState<BackgroundTask[]>([]);
128
128
 
129
129
  // Command state
130
130
  const [slashCommands, setSlashCommands] = useState<SlashCommand[]>([]);
@@ -222,8 +222,8 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
222
222
  onCompressionStateChange: (isCompressingState) => {
223
223
  setIsCompressing(isCompressingState);
224
224
  },
225
- onShellsChange: (shells) => {
226
- setBackgroundShells([...shells]);
225
+ onTasksChange: (tasks) => {
226
+ setBackgroundTasks([...tasks]);
227
227
  },
228
228
  onSubagentMessagesChange: (subagentId, messages) => {
229
229
  logger.debug("onSubagentMessagesChange", subagentId, messages.length);
@@ -422,15 +422,15 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
422
422
  return (await agentRef.current?.disconnectMcpServer(serverName)) ?? false;
423
423
  }, []);
424
424
 
425
- // Background bash management methods - delegate to Agent
426
- const getBackgroundShellOutput = useCallback((shellId: string) => {
425
+ // Background task management methods - delegate to Agent
426
+ const getBackgroundTaskOutput = useCallback((taskId: string) => {
427
427
  if (!agentRef.current) return null;
428
- return agentRef.current.getBackgroundShellOutput(shellId);
428
+ return agentRef.current.getBackgroundTaskOutput(taskId);
429
429
  }, []);
430
430
 
431
- const killBackgroundShell = useCallback((shellId: string) => {
431
+ const stopBackgroundTask = useCallback((taskId: string) => {
432
432
  if (!agentRef.current) return false;
433
- return agentRef.current.killBackgroundShell(shellId);
433
+ return agentRef.current.stopBackgroundTask(taskId);
434
434
  }, []);
435
435
 
436
436
  const hasSlashCommand = useCallback((commandId: string) => {
@@ -482,6 +482,10 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
482
482
  hideConfirmation();
483
483
  }, [currentConfirmation, hideConfirmation]);
484
484
 
485
+ const backgroundCurrentTask = useCallback(() => {
486
+ agentRef.current?.backgroundCurrentTask();
487
+ }, []);
488
+
485
489
  const handleRewindSelect = useCallback(async (index: number) => {
486
490
  if (agentRef.current) {
487
491
  try {
@@ -530,9 +534,9 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
530
534
  mcpServers,
531
535
  connectMcpServer,
532
536
  disconnectMcpServer,
533
- backgroundShells,
534
- getBackgroundShellOutput,
535
- killBackgroundShell,
537
+ backgroundTasks,
538
+ getBackgroundTaskOutput,
539
+ stopBackgroundTask,
536
540
  slashCommands,
537
541
  hasSlashCommand,
538
542
  subagentMessages,
@@ -544,6 +548,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
544
548
  hideConfirmation,
545
549
  handleConfirmationDecision,
546
550
  handleConfirmationCancel,
551
+ backgroundCurrentTask,
547
552
  rewindId,
548
553
  handleRewindSelect,
549
554
  };
@@ -37,7 +37,7 @@ export const useInputManager = (
37
37
  show: false,
38
38
  message: "",
39
39
  });
40
- const [showBashManager, setShowBashManager] = useState(false);
40
+ const [showTaskManager, setShowTaskManager] = useState(false);
41
41
  const [showMcpManager, setShowMcpManager] = useState(false);
42
42
  const [showRewindManager, setShowRewindManager] = useState(false);
43
43
  const [permissionMode, setPermissionModeState] =
@@ -64,8 +64,8 @@ export const useInputManager = (
64
64
  onMemoryTypeSelectorStateChange: (show, message) => {
65
65
  setMemoryTypeSelectorState({ show, message });
66
66
  },
67
- onBashManagerStateChange: (show) => {
68
- setShowBashManager(show);
67
+ onTaskManagerStateChange: (show) => {
68
+ setShowTaskManager(show);
69
69
  },
70
70
  onMcpManagerStateChange: (show) => {
71
71
  setShowMcpManager(show);
@@ -78,7 +78,7 @@ export const useInputManager = (
78
78
  callbacks.onPermissionModeChange?.(mode);
79
79
  },
80
80
  onImagesStateChange: setAttachedImages,
81
- onShowBashManager: () => setShowBashManager(true),
81
+ onShowTaskManager: () => setShowTaskManager(true),
82
82
  onShowMcpManager: () => setShowMcpManager(true),
83
83
  onShowRewindManager: () => setShowRewindManager(true),
84
84
  ...callbacks,
@@ -104,8 +104,8 @@ export const useInputManager = (
104
104
  onMemoryTypeSelectorStateChange: (show, message) => {
105
105
  setMemoryTypeSelectorState({ show, message });
106
106
  },
107
- onBashManagerStateChange: (show) => {
108
- setShowBashManager(show);
107
+ onTaskManagerStateChange: (show) => {
108
+ setShowTaskManager(show);
109
109
  },
110
110
  onMcpManagerStateChange: (show) => {
111
111
  setShowMcpManager(show);
@@ -118,7 +118,7 @@ export const useInputManager = (
118
118
  callbacks.onPermissionModeChange?.(mode);
119
119
  },
120
120
  onImagesStateChange: setAttachedImages,
121
- onShowBashManager: () => setShowBashManager(true),
121
+ onShowTaskManager: () => setShowTaskManager(true),
122
122
  onShowMcpManager: () => setShowMcpManager(true),
123
123
  onShowRewindManager: () => setShowRewindManager(true),
124
124
  ...callbacks,
@@ -319,7 +319,7 @@ export const useInputManager = (
319
319
  historySearchQuery: historySearchState.query,
320
320
  showMemoryTypeSelector: memoryTypeSelectorState.show,
321
321
  memoryMessage: memoryTypeSelectorState.message,
322
- showBashManager,
322
+ showTaskManager,
323
323
  showMcpManager,
324
324
  showRewindManager,
325
325
  permissionMode,
@@ -368,8 +368,8 @@ export const useInputManager = (
368
368
  handleSpecialCharInput,
369
369
 
370
370
  // Bash/MCP Manager
371
- setShowBashManager: useCallback((show: boolean) => {
372
- managerRef.current?.setShowBashManager(show);
371
+ setShowTaskManager: useCallback((show: boolean) => {
372
+ managerRef.current?.setShowTaskManager(show);
373
373
  }, []),
374
374
  setShowMcpManager: useCallback((show: boolean) => {
375
375
  managerRef.current?.setShowMcpManager(show);
@@ -210,7 +210,8 @@ export function usePluginManager(): PluginManagerContextType {
210
210
  }));
211
211
  try {
212
212
  const pluginId = `${name}@${marketplace}`;
213
- await marketplaceService.installPlugin(pluginId);
213
+ const workdir = process.cwd();
214
+ await marketplaceService.installPlugin(pluginId, workdir);
214
215
  await pluginScopeManager.enablePlugin(scope, pluginId);
215
216
  await refresh();
216
217
  } catch (error) {
@@ -233,11 +234,16 @@ export function usePluginManager(): PluginManagerContextType {
233
234
  }));
234
235
  try {
235
236
  const pluginId = `${name}@${marketplace}`;
236
- // Find the scope where it's currently enabled and remove it from there
237
+ const workdir = process.cwd();
238
+
239
+ // 1. Remove from global registry and potentially clean up cache
240
+ await marketplaceService.uninstallPlugin(pluginId, workdir);
241
+
242
+ // 2. Find the scope where it's currently enabled and remove it from there
237
243
  const scope = pluginScopeManager.findPluginScope(pluginId);
238
244
  if (scope) {
239
245
  await configurationService.removeEnabledPlugin(
240
- process.cwd(),
246
+ workdir,
241
247
  scope,
242
248
  pluginId,
243
249
  );
@@ -251,7 +257,7 @@ export function usePluginManager(): PluginManagerContextType {
251
257
  }));
252
258
  }
253
259
  },
254
- [configurationService, pluginScopeManager, refresh],
260
+ [configurationService, marketplaceService, pluginScopeManager, refresh],
255
261
  );
256
262
 
257
263
  const updatePlugin = useCallback(
@@ -30,11 +30,11 @@ export interface InputManagerCallbacks {
30
30
  ) => void;
31
31
  onHistorySearchStateChange?: (show: boolean, query: string) => void;
32
32
  onMemoryTypeSelectorStateChange?: (show: boolean, message: string) => void;
33
- onShowBashManager?: () => void;
33
+ onShowTaskManager?: () => void;
34
+ onTaskManagerStateChange?: (show: boolean) => void;
34
35
  onShowMcpManager?: () => void;
35
- onShowRewindManager?: () => void;
36
- onBashManagerStateChange?: (show: boolean) => void;
37
36
  onMcpManagerStateChange?: (show: boolean) => void;
37
+ onShowRewindManager?: () => void;
38
38
  onRewindManagerStateChange?: (show: boolean) => void;
39
39
  onImagesStateChange?: (images: AttachedImage[]) => void;
40
40
  onSendMessage?: (
@@ -44,6 +44,7 @@ export interface InputManagerCallbacks {
44
44
  onHasSlashCommand?: (commandId: string) => boolean;
45
45
  onSaveMemory?: (message: string, type: "project" | "user") => Promise<void>;
46
46
  onAbortMessage?: () => void;
47
+ onBackgroundCurrentTask?: () => void;
47
48
  onResetHistoryNavigation?: () => void;
48
49
  onPermissionModeChange?: (mode: PermissionMode) => void;
49
50
  logger?: Logger;
@@ -94,7 +95,7 @@ export class InputManager {
94
95
  private imageIdCounter: number = 1;
95
96
 
96
97
  // Additional UI state
97
- private showBashManager: boolean = false;
98
+ private showTaskManager: boolean = false;
98
99
  private showMcpManager: boolean = false;
99
100
  private showRewindManager: boolean = false;
100
101
 
@@ -361,8 +362,8 @@ export class InputManager {
361
362
 
362
363
  // If not an agent command or execution failed, check local commands
363
364
  if (!commandExecuted) {
364
- if (command === "bashes" && this.callbacks.onShowBashManager) {
365
- this.callbacks.onShowBashManager();
365
+ if (command === "tasks" && this.callbacks.onShowTaskManager) {
366
+ this.callbacks.onShowTaskManager();
366
367
  commandExecuted = true;
367
368
  } else if (command === "mcp" && this.callbacks.onShowMcpManager) {
368
369
  this.callbacks.onShowMcpManager();
@@ -751,14 +752,14 @@ export class InputManager {
751
752
  }
752
753
  }
753
754
 
754
- // Bash/MCP manager state methods
755
- getShowBashManager(): boolean {
756
- return this.showBashManager;
755
+ // Task manager state methods
756
+ getShowTaskManager(): boolean {
757
+ return this.showTaskManager;
757
758
  }
758
759
 
759
- setShowBashManager(show: boolean): void {
760
- this.showBashManager = show;
761
- this.callbacks.onBashManagerStateChange?.(show);
760
+ setShowTaskManager(show: boolean): void {
761
+ this.showTaskManager = show;
762
+ this.callbacks.onTaskManagerStateChange?.(show);
762
763
  }
763
764
 
764
765
  getShowMcpManager(): boolean {
@@ -1005,6 +1006,12 @@ export class InputManager {
1005
1006
  return true;
1006
1007
  }
1007
1008
 
1009
+ // Handle Ctrl+B for backgrounding current task
1010
+ if (key.ctrl && input === "b") {
1011
+ this.callbacks.onBackgroundCurrentTask?.();
1012
+ return true;
1013
+ }
1014
+
1008
1015
  // Handle up/down keys for history navigation (only when no selector is active)
1009
1016
  if (key.upArrow && !this.showFileSelector && !this.showCommandSelector) {
1010
1017
  this.navigateHistory("up", this.inputText);
@@ -1072,17 +1079,17 @@ export class InputManager {
1072
1079
  this.showCommandSelector ||
1073
1080
  this.showHistorySearch ||
1074
1081
  this.showMemoryTypeSelector ||
1075
- this.showBashManager ||
1082
+ this.showTaskManager ||
1076
1083
  this.showMcpManager ||
1077
1084
  this.showRewindManager
1078
1085
  ) {
1079
1086
  if (
1080
1087
  this.showMemoryTypeSelector ||
1081
- this.showBashManager ||
1088
+ this.showTaskManager ||
1082
1089
  this.showMcpManager ||
1083
1090
  this.showRewindManager
1084
1091
  ) {
1085
- // Memory type selector, bash manager, MCP manager and Rewind don't need to handle input, handled by component itself
1092
+ // Memory type selector, task manager, MCP manager and Rewind don't need to handle input, handled by component itself
1086
1093
  return false;
1087
1094
  }
1088
1095
 
@@ -1,6 +0,0 @@
1
- import React from "react";
2
- export interface BashShellManagerProps {
3
- onCancel: () => void;
4
- }
5
- export declare const BashShellManager: React.FC<BashShellManagerProps>;
6
- //# sourceMappingURL=BashShellManager.d.ts.map