wave-code 0.2.1 → 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 (156) hide show
  1. package/dist/commands/plugin/disable.d.ts +2 -1
  2. package/dist/commands/plugin/disable.d.ts.map +1 -1
  3. package/dist/commands/plugin/disable.js +3 -2
  4. package/dist/commands/plugin/enable.d.ts +2 -1
  5. package/dist/commands/plugin/enable.d.ts.map +1 -1
  6. package/dist/commands/plugin/enable.js +3 -2
  7. package/dist/commands/plugin/install.d.ts +2 -1
  8. package/dist/commands/plugin/install.d.ts.map +1 -1
  9. package/dist/commands/plugin/list.d.ts.map +1 -1
  10. package/dist/commands/plugin/list.js +15 -3
  11. package/dist/commands/plugin/marketplace.d.ts +3 -0
  12. package/dist/commands/plugin/marketplace.d.ts.map +1 -1
  13. package/dist/commands/plugin/marketplace.js +15 -1
  14. package/dist/commands/plugin/uninstall.d.ts +4 -0
  15. package/dist/commands/plugin/uninstall.d.ts.map +1 -0
  16. package/dist/commands/plugin/uninstall.js +29 -0
  17. package/dist/commands/plugin/update.d.ts +4 -0
  18. package/dist/commands/plugin/update.d.ts.map +1 -0
  19. package/dist/commands/plugin/update.js +15 -0
  20. package/dist/components/ChatInterface.d.ts.map +1 -1
  21. package/dist/components/ChatInterface.js +2 -2
  22. package/dist/components/CommandSelector.d.ts.map +1 -1
  23. package/dist/components/CommandSelector.js +9 -3
  24. package/dist/components/Confirmation.d.ts.map +1 -1
  25. package/dist/components/Confirmation.js +73 -20
  26. package/dist/components/DiffDisplay.d.ts +0 -1
  27. package/dist/components/DiffDisplay.d.ts.map +1 -1
  28. package/dist/components/DiffDisplay.js +38 -59
  29. package/dist/components/DiscoverView.d.ts +3 -0
  30. package/dist/components/DiscoverView.d.ts.map +1 -0
  31. package/dist/components/DiscoverView.js +25 -0
  32. package/dist/components/FileSelector.js +1 -1
  33. package/dist/components/HistorySearch.d.ts +8 -0
  34. package/dist/components/HistorySearch.d.ts.map +1 -0
  35. package/dist/components/HistorySearch.js +67 -0
  36. package/dist/components/InputBox.d.ts +1 -1
  37. package/dist/components/InputBox.d.ts.map +1 -1
  38. package/dist/components/InputBox.js +29 -19
  39. package/dist/components/InstalledView.d.ts +3 -0
  40. package/dist/components/InstalledView.d.ts.map +1 -0
  41. package/dist/components/InstalledView.js +30 -0
  42. package/dist/components/Markdown.d.ts.map +1 -1
  43. package/dist/components/Markdown.js +24 -10
  44. package/dist/components/MarketplaceAddForm.d.ts +3 -0
  45. package/dist/components/MarketplaceAddForm.d.ts.map +1 -0
  46. package/dist/components/MarketplaceAddForm.js +26 -0
  47. package/dist/components/MarketplaceDetail.d.ts +3 -0
  48. package/dist/components/MarketplaceDetail.d.ts.map +1 -0
  49. package/dist/components/MarketplaceDetail.js +38 -0
  50. package/dist/components/MarketplaceList.d.ts +9 -0
  51. package/dist/components/MarketplaceList.d.ts.map +1 -0
  52. package/dist/components/MarketplaceList.js +16 -0
  53. package/dist/components/MarketplaceView.d.ts +3 -0
  54. package/dist/components/MarketplaceView.d.ts.map +1 -0
  55. package/dist/components/MarketplaceView.js +28 -0
  56. package/dist/components/PlanDisplay.d.ts.map +1 -1
  57. package/dist/components/PlanDisplay.js +2 -2
  58. package/dist/components/PluginDetail.d.ts +3 -0
  59. package/dist/components/PluginDetail.d.ts.map +1 -0
  60. package/dist/components/PluginDetail.js +63 -0
  61. package/dist/components/PluginList.d.ts +14 -0
  62. package/dist/components/PluginList.d.ts.map +1 -0
  63. package/dist/components/PluginList.js +12 -0
  64. package/dist/components/PluginManagerShell.d.ts +5 -0
  65. package/dist/components/PluginManagerShell.d.ts.map +1 -0
  66. package/dist/components/PluginManagerShell.js +89 -0
  67. package/dist/components/PluginManagerTypes.d.ts +33 -0
  68. package/dist/components/PluginManagerTypes.d.ts.map +1 -0
  69. package/dist/components/PluginManagerTypes.js +1 -0
  70. package/dist/components/RewindCommand.d.ts +9 -0
  71. package/dist/components/RewindCommand.d.ts.map +1 -0
  72. package/dist/components/RewindCommand.js +42 -0
  73. package/dist/components/SessionSelector.d.ts +11 -0
  74. package/dist/components/SessionSelector.d.ts.map +1 -0
  75. package/dist/components/SessionSelector.js +38 -0
  76. package/dist/components/SubagentBlock.d.ts.map +1 -1
  77. package/dist/components/SubagentBlock.js +24 -1
  78. package/dist/components/TaskManager.d.ts +6 -0
  79. package/dist/components/TaskManager.d.ts.map +1 -0
  80. package/dist/components/TaskManager.js +114 -0
  81. package/dist/components/ToolResultDisplay.d.ts.map +1 -1
  82. package/dist/components/ToolResultDisplay.js +2 -1
  83. package/dist/contexts/PluginManagerContext.d.ts +4 -0
  84. package/dist/contexts/PluginManagerContext.d.ts.map +1 -0
  85. package/dist/contexts/PluginManagerContext.js +9 -0
  86. package/dist/contexts/useChat.d.ts +7 -4
  87. package/dist/contexts/useChat.d.ts.map +1 -1
  88. package/dist/contexts/useChat.js +37 -12
  89. package/dist/hooks/useInputManager.d.ts +8 -16
  90. package/dist/hooks/useInputManager.d.ts.map +1 -1
  91. package/dist/hooks/useInputManager.js +39 -55
  92. package/dist/hooks/usePluginManager.d.ts +3 -0
  93. package/dist/hooks/usePluginManager.d.ts.map +1 -0
  94. package/dist/hooks/usePluginManager.js +227 -0
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +150 -177
  97. package/dist/managers/InputManager.d.ts +18 -26
  98. package/dist/managers/InputManager.d.ts.map +1 -1
  99. package/dist/managers/InputManager.js +93 -119
  100. package/dist/plugin-manager-cli.d.ts +6 -0
  101. package/dist/plugin-manager-cli.d.ts.map +1 -0
  102. package/dist/plugin-manager-cli.js +12 -0
  103. package/dist/session-selector-cli.d.ts +2 -0
  104. package/dist/session-selector-cli.d.ts.map +1 -0
  105. package/dist/session-selector-cli.js +25 -0
  106. package/package.json +9 -5
  107. package/src/commands/plugin/disable.ts +7 -3
  108. package/src/commands/plugin/enable.ts +7 -3
  109. package/src/commands/plugin/install.ts +2 -1
  110. package/src/commands/plugin/list.ts +21 -3
  111. package/src/commands/plugin/marketplace.ts +17 -1
  112. package/src/commands/plugin/uninstall.ts +39 -0
  113. package/src/commands/plugin/update.ts +19 -0
  114. package/src/components/ChatInterface.tsx +2 -1
  115. package/src/components/CommandSelector.tsx +10 -3
  116. package/src/components/Confirmation.tsx +115 -25
  117. package/src/components/DiffDisplay.tsx +60 -106
  118. package/src/components/DiscoverView.tsx +31 -0
  119. package/src/components/FileSelector.tsx +1 -1
  120. package/src/components/HistorySearch.tsx +148 -0
  121. package/src/components/InputBox.tsx +51 -34
  122. package/src/components/InstalledView.tsx +61 -0
  123. package/src/components/Markdown.tsx +44 -28
  124. package/src/components/MarketplaceAddForm.tsx +39 -0
  125. package/src/components/MarketplaceDetail.tsx +79 -0
  126. package/src/components/MarketplaceList.tsx +52 -0
  127. package/src/components/MarketplaceView.tsx +43 -0
  128. package/src/components/PlanDisplay.tsx +14 -19
  129. package/src/components/PluginDetail.tsx +147 -0
  130. package/src/components/PluginList.tsx +51 -0
  131. package/src/components/PluginManagerShell.tsx +189 -0
  132. package/src/components/PluginManagerTypes.ts +47 -0
  133. package/src/components/RewindCommand.tsx +114 -0
  134. package/src/components/SessionSelector.tsx +127 -0
  135. package/src/components/SubagentBlock.tsx +34 -1
  136. package/src/components/{BashShellManager.tsx → TaskManager.tsx} +79 -75
  137. package/src/components/ToolResultDisplay.tsx +6 -2
  138. package/src/contexts/PluginManagerContext.ts +15 -0
  139. package/src/contexts/useChat.tsx +51 -20
  140. package/src/hooks/useInputManager.ts +39 -71
  141. package/src/hooks/usePluginManager.ts +302 -0
  142. package/src/index.ts +241 -280
  143. package/src/managers/InputManager.ts +113 -162
  144. package/src/plugin-manager-cli.tsx +13 -0
  145. package/src/session-selector-cli.tsx +37 -0
  146. package/dist/components/BashHistorySelector.d.ts +0 -11
  147. package/dist/components/BashHistorySelector.d.ts.map +0 -1
  148. package/dist/components/BashHistorySelector.js +0 -93
  149. package/dist/components/BashShellManager.d.ts +0 -6
  150. package/dist/components/BashShellManager.d.ts.map +0 -1
  151. package/dist/components/BashShellManager.js +0 -116
  152. package/dist/hooks/usePagination.d.ts +0 -20
  153. package/dist/hooks/usePagination.d.ts.map +0 -1
  154. package/dist/hooks/usePagination.js +0 -168
  155. package/src/components/BashHistorySelector.tsx +0 -181
  156. package/src/hooks/usePagination.ts +0 -203
@@ -0,0 +1,127 @@
1
+ import React, { useState } from "react";
2
+ import { Box, Text, useInput } from "ink";
3
+ import type { SessionMetadata } from "wave-agent-sdk";
4
+
5
+ export interface SessionSelectorProps {
6
+ sessions: (SessionMetadata & { firstMessage?: string })[];
7
+ onSelect: (sessionId: string) => void;
8
+ onCancel: () => void;
9
+ }
10
+
11
+ export const SessionSelector: React.FC<SessionSelectorProps> = ({
12
+ sessions,
13
+ onSelect,
14
+ onCancel,
15
+ }) => {
16
+ const [selectedIndex, setSelectedIndex] = useState(0);
17
+
18
+ useInput((input, key) => {
19
+ if (key.return) {
20
+ if (sessions.length > 0 && selectedIndex < sessions.length) {
21
+ onSelect(sessions[selectedIndex].id);
22
+ }
23
+ return;
24
+ }
25
+
26
+ if (key.escape) {
27
+ onCancel();
28
+ return;
29
+ }
30
+
31
+ if (key.upArrow) {
32
+ setSelectedIndex(Math.max(0, selectedIndex - 1));
33
+ return;
34
+ }
35
+
36
+ if (key.downArrow) {
37
+ setSelectedIndex(Math.min(sessions.length - 1, selectedIndex + 1));
38
+ return;
39
+ }
40
+ });
41
+
42
+ if (sessions.length === 0) {
43
+ return (
44
+ <Box
45
+ flexDirection="column"
46
+ borderStyle="single"
47
+ borderColor="yellow"
48
+ borderLeft={false}
49
+ borderRight={false}
50
+ paddingX={1}
51
+ width="100%"
52
+ >
53
+ <Text color="yellow">No sessions found.</Text>
54
+ <Text dimColor>Press Escape to cancel</Text>
55
+ </Box>
56
+ );
57
+ }
58
+
59
+ const maxDisplay = 10;
60
+ const startIndex = Math.max(
61
+ 0,
62
+ Math.min(
63
+ selectedIndex - Math.floor(maxDisplay / 2),
64
+ sessions.length - maxDisplay,
65
+ ),
66
+ );
67
+ const displaySessions = sessions.slice(startIndex, startIndex + maxDisplay);
68
+
69
+ return (
70
+ <Box
71
+ flexDirection="column"
72
+ paddingX={1}
73
+ gap={1}
74
+ borderStyle="single"
75
+ borderColor="cyan"
76
+ borderLeft={false}
77
+ borderRight={false}
78
+ width="100%"
79
+ >
80
+ <Box>
81
+ <Text color="cyan" bold>
82
+ Select a session to resume
83
+ </Text>
84
+ </Box>
85
+
86
+ <Box flexDirection="column">
87
+ {displaySessions.map((session, index) => {
88
+ const actualIndex = startIndex + index;
89
+ const isSelected = actualIndex === selectedIndex;
90
+ const lastActiveAt = new Date(session.lastActiveAt).toLocaleString();
91
+
92
+ return (
93
+ <Box key={session.id} flexDirection="column" width="100%">
94
+ <Box width="100%">
95
+ <Text
96
+ color={isSelected ? "black" : "white"}
97
+ backgroundColor={isSelected ? "cyan" : undefined}
98
+ >
99
+ {isSelected ? "▶ " : " "}
100
+ {session.id} | {lastActiveAt} | {session.latestTotalTokens}{" "}
101
+ tokens
102
+ </Text>
103
+ </Box>
104
+ <Box marginLeft={4} width="100%">
105
+ <Text dimColor italic>
106
+ {session.firstMessage}
107
+ </Text>
108
+ </Box>
109
+ </Box>
110
+ );
111
+ })}
112
+ </Box>
113
+
114
+ {sessions.length > maxDisplay && (
115
+ <Box>
116
+ <Text dimColor>
117
+ ... showing {displaySessions.length} of {sessions.length} sessions
118
+ </Text>
119
+ </Box>
120
+ )}
121
+
122
+ <Box>
123
+ <Text dimColor>↑↓ navigate • Enter to select • Esc to cancel</Text>
124
+ </Box>
125
+ </Box>
126
+ );
127
+ };
@@ -2,6 +2,7 @@ import React from "react";
2
2
  import { Box, Text } from "ink";
3
3
  import type { SubagentBlock as SubagentBlockType } from "wave-agent-sdk";
4
4
  import { useChat } from "../contexts/useChat.js";
5
+ import { Markdown } from "./Markdown.js";
5
6
 
6
7
  interface SubagentBlockProps {
7
8
  block: SubagentBlockType;
@@ -10,6 +11,11 @@ interface SubagentBlockProps {
10
11
  export const SubagentBlock: React.FC<SubagentBlockProps> = ({ block }) => {
11
12
  const { subagentMessages } = useChat();
12
13
 
14
+ // If the subagent is running in the background, don't show the block
15
+ if (block.runInBackground) {
16
+ return null;
17
+ }
18
+
13
19
  // Get messages for this subagent from context
14
20
  const messages = subagentMessages[block.subagentId] || [];
15
21
 
@@ -59,6 +65,26 @@ export const SubagentBlock: React.FC<SubagentBlockProps> = ({ block }) => {
59
65
 
60
66
  const { tools: lastTwoTools, totalToolCount } = getLastTwoTools();
61
67
 
68
+ // Get the last text message content if completed
69
+ const getLastTextMessage = () => {
70
+ if (block.status !== "completed") return null;
71
+
72
+ for (let i = messages.length - 1; i >= 0; i--) {
73
+ const message = messages[i];
74
+ if (message.role === "assistant") {
75
+ for (let j = message.blocks.length - 1; j >= 0; j--) {
76
+ const messageBlock = message.blocks[j];
77
+ if (messageBlock.type === "text" && messageBlock.content) {
78
+ return messageBlock.content;
79
+ }
80
+ }
81
+ }
82
+ }
83
+ return null;
84
+ };
85
+
86
+ const lastTextMessage = getLastTextMessage();
87
+
62
88
  return (
63
89
  <Box
64
90
  borderRight={false}
@@ -86,8 +112,15 @@ export const SubagentBlock: React.FC<SubagentBlockProps> = ({ block }) => {
86
112
  </Box>
87
113
  </Box>
88
114
 
115
+ {/* Last Text Message Section */}
116
+ {lastTextMessage && (
117
+ <Box marginTop={1}>
118
+ <Markdown>{lastTextMessage}</Markdown>
119
+ </Box>
120
+ )}
121
+
89
122
  {/* Tool Names Section - Vertical List */}
90
- {lastTwoTools.length > 0 && (
123
+ {block.status !== "completed" && lastTwoTools.length > 0 && (
91
124
  <Box flexDirection="column" marginTop={1} gap={1}>
92
125
  {totalToolCount > 2 && (
93
126
  <Text color="gray" dimColor>
@@ -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 */}
@@ -135,8 +139,8 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
135
139
  </Box>
136
140
  )}
137
141
 
138
- {/* Diff display - only show after tool execution completes */}
139
- {stage === "end" && (
142
+ {/* Diff display - only show after tool execution completes and was successful */}
143
+ {stage === "end" && success && (
140
144
  <DiffDisplay toolName={name} parameters={parameters} />
141
145
  )}
142
146
  </Box>
@@ -0,0 +1,15 @@
1
+ import { createContext, useContext } from "react";
2
+ import { PluginManagerContextType } from "../components/PluginManagerTypes.js";
3
+
4
+ export const PluginManagerContext =
5
+ createContext<PluginManagerContextType | null>(null);
6
+
7
+ export const usePluginManagerContext = () => {
8
+ const context = useContext(PluginManagerContext);
9
+ if (!context) {
10
+ throw new Error(
11
+ "usePluginManagerContext must be used within a PluginManagerProvider",
12
+ );
13
+ }
14
+ return context;
15
+ };