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
@@ -6,13 +6,30 @@ export interface RewindCommandProps {
6
6
  messages: Message[];
7
7
  onSelect: (index: number) => void;
8
8
  onCancel: () => void;
9
+ getFullMessageThread?: () => Promise<{
10
+ messages: Message[];
11
+ sessionIds: string[];
12
+ }>;
9
13
  }
10
14
 
11
15
  export const RewindCommand: React.FC<RewindCommandProps> = ({
12
- messages,
16
+ messages: initialMessages,
13
17
  onSelect,
14
18
  onCancel,
19
+ getFullMessageThread,
15
20
  }) => {
21
+ const [messages, setMessages] = useState<Message[]>(initialMessages);
22
+ const [isLoading, setIsLoading] = useState(!!getFullMessageThread);
23
+
24
+ React.useEffect(() => {
25
+ if (getFullMessageThread) {
26
+ getFullMessageThread().then(({ messages: fullMessages }) => {
27
+ setMessages(fullMessages);
28
+ setIsLoading(false);
29
+ });
30
+ }
31
+ }, [getFullMessageThread]);
32
+
16
33
  // Filter user messages as checkpoints
17
34
  const checkpoints = messages
18
35
  .map((msg, index) => ({ msg, index }))
@@ -20,6 +37,11 @@ export const RewindCommand: React.FC<RewindCommandProps> = ({
20
37
 
21
38
  const [selectedIndex, setSelectedIndex] = useState(checkpoints.length - 1);
22
39
 
40
+ // Update selectedIndex when checkpoints change (after loading full thread)
41
+ React.useEffect(() => {
42
+ setSelectedIndex(checkpoints.length - 1);
43
+ }, [checkpoints.length]);
44
+
23
45
  useInput((input, key) => {
24
46
  if (key.return) {
25
47
  if (checkpoints.length > 0 && selectedIndex >= 0) {
@@ -44,6 +66,21 @@ export const RewindCommand: React.FC<RewindCommandProps> = ({
44
66
  }
45
67
  });
46
68
 
69
+ if (isLoading) {
70
+ return (
71
+ <Box
72
+ flexDirection="column"
73
+ paddingX={1}
74
+ borderStyle="single"
75
+ borderColor="cyan"
76
+ borderLeft={false}
77
+ borderRight={false}
78
+ >
79
+ <Text color="cyan">Loading full message thread...</Text>
80
+ </Box>
81
+ );
82
+ }
83
+
47
84
  if (checkpoints.length === 0) {
48
85
  return (
49
86
  <Box
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { useMemo } 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";
@@ -9,10 +9,21 @@ interface SubagentBlockProps {
9
9
  }
10
10
 
11
11
  export const SubagentBlock: React.FC<SubagentBlockProps> = ({ block }) => {
12
- const { subagentMessages } = useChat();
12
+ const { subagentMessages, subagentLatestTokens } = useChat();
13
13
 
14
14
  // Get messages for this subagent from context
15
- const messages = subagentMessages[block.subagentId] || [];
15
+ const messages = useMemo(
16
+ () => subagentMessages[block.subagentId] || [],
17
+ [subagentMessages, block.subagentId],
18
+ );
19
+
20
+ // Get latest turn tokens for this subagent
21
+ const latestTurnTokens = subagentLatestTokens[block.subagentId] || 0;
22
+
23
+ // If the subagent is running in the background, don't show the block
24
+ if (block.runInBackground) {
25
+ return null;
26
+ }
16
27
 
17
28
  // Status indicator mapping
18
29
  const getStatusIndicator = (status: SubagentBlockType["status"]) => {
@@ -58,7 +69,7 @@ export const SubagentBlock: React.FC<SubagentBlockProps> = ({ block }) => {
58
69
  return { tools: tools.reverse(), totalToolCount }; // Reverse to show oldest first, newest last
59
70
  };
60
71
 
61
- const { tools: lastTwoTools, totalToolCount } = getLastTwoTools();
72
+ const { tools: lastTwoTools } = getLastTwoTools();
62
73
 
63
74
  // Get the last text message content if completed
64
75
  const getLastTextMessage = () => {
@@ -88,9 +99,7 @@ export const SubagentBlock: React.FC<SubagentBlockProps> = ({ block }) => {
88
99
  borderStyle="classic"
89
100
  borderColor="magenta"
90
101
  paddingX={1}
91
- paddingY={0}
92
102
  flexDirection="column"
93
- marginBottom={1}
94
103
  >
95
104
  {/* Header Section */}
96
105
  <Box flexDirection="row" gap={1}>
@@ -102,26 +111,31 @@ export const SubagentBlock: React.FC<SubagentBlockProps> = ({ block }) => {
102
111
  </Text>
103
112
  <Text color="gray" dimColor>
104
113
  {" "}
105
- ({messages.length} messages)
114
+ ({messages.length} messages
115
+ {latestTurnTokens > 0 && (
116
+ <>
117
+ {" | "}
118
+ <Text color="blue" bold>
119
+ {latestTurnTokens.toLocaleString()}
120
+ </Text>
121
+ {" tokens"}
122
+ </>
123
+ )}
124
+ )
106
125
  </Text>
107
126
  </Box>
108
127
  </Box>
109
128
 
110
129
  {/* Last Text Message Section */}
111
130
  {lastTextMessage && (
112
- <Box marginTop={1}>
131
+ <Box>
113
132
  <Markdown>{lastTextMessage}</Markdown>
114
133
  </Box>
115
134
  )}
116
135
 
117
136
  {/* Tool Names Section - Vertical List */}
118
137
  {block.status !== "completed" && lastTwoTools.length > 0 && (
119
- <Box flexDirection="column" marginTop={1} gap={1}>
120
- {totalToolCount > 2 && (
121
- <Text color="gray" dimColor>
122
- ...
123
- </Text>
124
- )}
138
+ <Box flexDirection="column">
125
139
  {lastTwoTools.map((tool, index) => (
126
140
  <Box key={index} flexDirection="row">
127
141
  <Text color="magenta">🔧 </Text>
@@ -0,0 +1,70 @@
1
+ import React from "react";
2
+ import { useChat } from "../contexts/useChat.js";
3
+ import { Box, Text, useStdout } from "ink";
4
+ import { useTasks } from "../hooks/useTasks.js";
5
+
6
+ export const TaskList: React.FC = () => {
7
+ const tasks = useTasks();
8
+ const { isTaskListVisible } = useChat();
9
+ const { stdout } = useStdout();
10
+ const terminalWidth = stdout?.columns ?? 80;
11
+ const maxSubjectWidth = Math.max(20, terminalWidth - 10);
12
+
13
+ if (tasks.length === 0 || !isTaskListVisible) {
14
+ return null;
15
+ }
16
+
17
+ const getStatusIcon = (status: string, isBlocked: boolean) => {
18
+ if (isBlocked) {
19
+ return <Text color="red">🔒</Text>;
20
+ }
21
+ switch (status) {
22
+ case "pending":
23
+ return <Text color="gray">○</Text>;
24
+ case "in_progress":
25
+ return <Text color="yellow">●</Text>;
26
+ case "completed":
27
+ return <Text color="green">✓</Text>;
28
+ case "deleted":
29
+ return <Text color="red">✕</Text>;
30
+ default:
31
+ return <Text color="gray">?</Text>;
32
+ }
33
+ };
34
+
35
+ const truncate = (text: string, maxWidth: number) => {
36
+ if (text.length <= maxWidth) {
37
+ return text;
38
+ }
39
+ return text.slice(0, maxWidth - 3) + "...";
40
+ };
41
+
42
+ return (
43
+ <Box flexDirection="column">
44
+ {tasks.map((task) => {
45
+ const isDimmed =
46
+ task.status === "completed" || task.status === "deleted";
47
+ const isBlocked = task.blockedBy && task.blockedBy.length > 0;
48
+ const blockingTaskIds = isBlocked
49
+ ? task.blockedBy.map((id) => `#${id}`)
50
+ : [];
51
+
52
+ const blockedByText =
53
+ isBlocked && blockingTaskIds.length > 0
54
+ ? ` (Blocked by: ${blockingTaskIds.join(", ")})`
55
+ : "";
56
+
57
+ const fullText = `${task.subject}${blockedByText}`;
58
+
59
+ return (
60
+ <Box key={task.id} gap={1}>
61
+ {getStatusIcon(task.status, isBlocked)}
62
+ <Text dimColor={isDimmed}>
63
+ {truncate(fullText, maxSubjectWidth)}
64
+ </Text>
65
+ </Box>
66
+ );
67
+ })}
68
+ </Box>
69
+ );
70
+ };
@@ -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) {
@@ -65,7 +68,7 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
65
68
  const shortResult = getShortResult();
66
69
 
67
70
  return (
68
- <Box flexDirection="column" gap={1}>
71
+ <Box flexDirection="column">
69
72
  <Box>
70
73
  <Text color="magenta">🔧 </Text>
71
74
  <Text color="white">{toolName}</Text>
@@ -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 */}
@@ -87,7 +91,7 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
87
91
  flexDirection="column"
88
92
  >
89
93
  {shortResult.split("\n").map((line, index) => (
90
- <Text key={index} color="white">
94
+ <Text key={index} color="gray">
91
95
  {line}
92
96
  </Text>
93
97
  ))}
@@ -11,7 +11,8 @@ import { useAppConfig } from "./useAppConfig.js";
11
11
  import type {
12
12
  Message,
13
13
  McpServerStatus,
14
- BackgroundShell,
14
+ BackgroundTask,
15
+ Task,
15
16
  SlashCommand,
16
17
  PermissionDecision,
17
18
  PermissionMode,
@@ -30,9 +31,10 @@ export interface ChatContextType {
30
31
  isLoading: boolean;
31
32
  isCommandRunning: boolean;
32
33
  isCompressing: boolean;
33
- userInputHistory: string[];
34
34
  // Message display state
35
35
  isExpanded: boolean;
36
+ isTaskListVisible: boolean;
37
+ setIsTaskListVisible: (visible: boolean) => void;
36
38
  // AI functionality
37
39
  sessionId: string;
38
40
  sendMessage: (
@@ -41,23 +43,24 @@ export interface ChatContextType {
41
43
  ) => Promise<void>;
42
44
  abortMessage: () => void;
43
45
  latestTotalTokens: number;
44
- // Memory functionality
45
- saveMemory: (message: string, type: "project" | "user") => Promise<void>;
46
46
  // MCP functionality
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
+ // Session tasks
53
+ sessionTasks: Task[];
54
+ getBackgroundTaskOutput: (
55
+ taskId: string,
54
56
  ) => { stdout: string; stderr: string; status: string } | null;
55
- killBackgroundShell: (shellId: string) => boolean;
57
+ stopBackgroundTask: (taskId: string) => boolean;
56
58
  // Slash Command functionality
57
59
  slashCommands: SlashCommand[];
58
60
  hasSlashCommand: (commandId: string) => boolean;
59
61
  // Subagent messages
60
62
  subagentMessages: Record<string, Message[]>;
63
+ subagentLatestTokens: Record<string, number>;
61
64
  // Permission functionality
62
65
  permissionMode: PermissionMode;
63
66
  setPermissionMode: (mode: PermissionMode) => void;
@@ -78,9 +81,17 @@ export interface ChatContextType {
78
81
  hideConfirmation: () => void;
79
82
  handleConfirmationDecision: (decision: PermissionDecision) => void;
80
83
  handleConfirmationCancel: () => void;
84
+ // Background current task
85
+ backgroundCurrentTask: () => void;
81
86
  // Rewind functionality
82
87
  rewindId: number;
83
88
  handleRewindSelect: (index: number) => Promise<void>;
89
+ getFullMessageThread: () => Promise<{
90
+ messages: Message[];
91
+ sessionIds: string[];
92
+ }>;
93
+ wasLastDetailsTooTall: number;
94
+ setWasLastDetailsTooTall: React.Dispatch<React.SetStateAction<number>>;
84
95
  }
85
96
 
86
97
  const ChatContext = createContext<ChatContextType | null>(null);
@@ -108,6 +119,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
108
119
 
109
120
  // Message Display State
110
121
  const [isExpanded, setIsExpanded] = useState(false);
122
+ const [isTaskListVisible, setIsTaskListVisible] = useState(true);
111
123
 
112
124
  // AI State
113
125
  const [messages, setMessages] = useState<Message[]>([]);
@@ -116,15 +128,14 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
116
128
  const [sessionId, setSessionId] = useState("");
117
129
  const [isCommandRunning, setIsCommandRunning] = useState(false);
118
130
  const [isCompressing, setIsCompressing] = useState(false);
119
- const [userInputHistory, setUserInputHistory] = useState<string[]>([]);
120
131
 
121
132
  // MCP State
122
133
  const [mcpServers, setMcpServers] = useState<McpServerStatus[]>([]);
123
134
 
124
- // Background bash shells state
125
- const [backgroundShells, setBackgroundShells] = useState<BackgroundShell[]>(
126
- [],
127
- );
135
+ // Background tasks state
136
+ const [backgroundTasks, setBackgroundTasks] = useState<BackgroundTask[]>([]);
137
+ // Session tasks state
138
+ const [sessionTasks, setSessionTasks] = useState<Task[]>([]);
128
139
 
129
140
  // Command state
130
141
  const [slashCommands, setSlashCommands] = useState<SlashCommand[]>([]);
@@ -133,6 +144,9 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
133
144
  const [subagentMessages, setSubagentMessages] = useState<
134
145
  Record<string, Message[]>
135
146
  >({});
147
+ const [subagentLatestTokens, setSubagentLatestTokens] = useState<
148
+ Record<string, number>
149
+ >({});
136
150
 
137
151
  // Permission state
138
152
  const [permissionMode, setPermissionModeState] =
@@ -171,6 +185,9 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
171
185
  // Rewind state
172
186
  const [rewindId, setRewindId] = useState(0);
173
187
 
188
+ // Confirmation too tall state
189
+ const [wasLastDetailsTooTall, setWasLastDetailsTooTall] = useState(0);
190
+
174
191
  const agentRef = useRef<Agent | null>(null);
175
192
 
176
193
  // Permission confirmation methods with queue support
@@ -209,29 +226,36 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
209
226
  setMcpServers([...servers]);
210
227
  },
211
228
  onSessionIdChange: (sessionId) => {
212
- process.stdout.write("\x1Bc", () => {
213
- setSessionId(sessionId);
214
- });
229
+ setSessionId(sessionId);
215
230
  },
216
231
  onLatestTotalTokensChange: (tokens) => {
217
232
  setlatestTotalTokens(tokens);
218
233
  },
219
- onUserInputHistoryChange: (history) => {
220
- setUserInputHistory([...history]);
221
- },
222
234
  onCompressionStateChange: (isCompressingState) => {
223
235
  setIsCompressing(isCompressingState);
224
236
  },
225
- onShellsChange: (shells) => {
226
- setBackgroundShells([...shells]);
237
+ onTasksChange: (tasks) => {
238
+ setBackgroundTasks([...tasks]);
239
+ },
240
+ onSessionTasksChange: (tasks) => {
241
+ setSessionTasks([...tasks]);
227
242
  },
228
- onSubagentMessagesChange: (subagentId, messages) => {
243
+ onSubagentMessagesChange: (subagentId: string, messages: Message[]) => {
229
244
  logger.debug("onSubagentMessagesChange", subagentId, messages.length);
230
245
  setSubagentMessages((prev) => ({
231
246
  ...prev,
232
247
  [subagentId]: [...messages],
233
248
  }));
234
249
  },
250
+ onSubagentLatestTotalTokensChange: (
251
+ subagentId: string,
252
+ tokens: number,
253
+ ) => {
254
+ setSubagentLatestTokens((prev) => ({
255
+ ...prev,
256
+ [subagentId]: tokens,
257
+ }));
258
+ },
235
259
  onPermissionModeChange: (mode) => {
236
260
  setPermissionModeState(mode);
237
261
  },
@@ -283,7 +307,6 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
283
307
  setlatestTotalTokens(agent.latestTotalTokens);
284
308
  setIsCommandRunning(agent.isCommandRunning);
285
309
  setIsCompressing(agent.isCompressing);
286
- setUserInputHistory(agent.userInputHistory);
287
310
  setPermissionModeState(agent.getPermissionMode());
288
311
 
289
312
  // Get initial MCP servers state
@@ -338,16 +361,6 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
338
361
  if (!hasTextContent && !hasImageAttachments) return;
339
362
 
340
363
  try {
341
- // Handle memory mode - check if it's a memory message (starts with # and only one line)
342
- if (content.startsWith("#") && !content.includes("\n")) {
343
- const memoryText = content.substring(1).trim();
344
- if (!memoryText) return;
345
-
346
- // In memory mode, don't add user message, only wait for user to choose memory type then add assistant message
347
- // Don't auto-save, wait for user to choose memory type
348
- return;
349
- }
350
-
351
364
  // Handle bash mode - check if it's a bash command (starts with ! and only one line)
352
365
  if (content.startsWith("!") && !content.includes("\n")) {
353
366
  const command = content.substring(1).trim();
@@ -394,14 +407,6 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
394
407
  agentRef.current?.abortMessage();
395
408
  }, []);
396
409
 
397
- // Memory save function - delegate to Agent
398
- const saveMemory = useCallback(
399
- async (message: string, type: "project" | "user") => {
400
- await agentRef.current?.saveMemory(message, type);
401
- },
402
- [],
403
- );
404
-
405
410
  // Permission management methods
406
411
  const setPermissionMode = useCallback((mode: PermissionMode) => {
407
412
  setPermissionModeState((prev) => {
@@ -422,15 +427,15 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
422
427
  return (await agentRef.current?.disconnectMcpServer(serverName)) ?? false;
423
428
  }, []);
424
429
 
425
- // Background bash management methods - delegate to Agent
426
- const getBackgroundShellOutput = useCallback((shellId: string) => {
430
+ // Background task management methods - delegate to Agent
431
+ const getBackgroundTaskOutput = useCallback((taskId: string) => {
427
432
  if (!agentRef.current) return null;
428
- return agentRef.current.getBackgroundShellOutput(shellId);
433
+ return agentRef.current.getBackgroundTaskOutput(taskId);
429
434
  }, []);
430
435
 
431
- const killBackgroundShell = useCallback((shellId: string) => {
436
+ const stopBackgroundTask = useCallback((taskId: string) => {
432
437
  if (!agentRef.current) return false;
433
- return agentRef.current.killBackgroundShell(shellId);
438
+ return agentRef.current.stopBackgroundTask(taskId);
434
439
  }, []);
435
440
 
436
441
  const hasSlashCommand = useCallback((commandId: string) => {
@@ -482,33 +487,44 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
482
487
  hideConfirmation();
483
488
  }, [currentConfirmation, hideConfirmation]);
484
489
 
490
+ const backgroundCurrentTask = useCallback(() => {
491
+ agentRef.current?.backgroundCurrentTask();
492
+ }, []);
493
+
485
494
  const handleRewindSelect = useCallback(async (index: number) => {
486
495
  if (agentRef.current) {
487
496
  try {
488
497
  await agentRef.current.truncateHistory(index);
489
498
 
490
499
  // Clear terminal screen after rewind
491
- process.stdout.write("\x1Bc", () => {
492
- setRewindId((prev) => prev + 1);
493
- });
500
+ setRewindId((prev) => prev + 1);
494
501
  } catch (error) {
495
502
  logger.error("Failed to rewind:", error);
496
503
  }
497
504
  }
498
505
  }, []);
499
506
 
507
+ const getFullMessageThread = useCallback(async () => {
508
+ if (agentRef.current) {
509
+ return await agentRef.current.getFullMessageThread();
510
+ }
511
+ return { messages: [], sessionIds: [] };
512
+ }, []);
513
+
500
514
  // Listen for Ctrl+O hotkey to toggle collapse/expand state and ESC to cancel confirmation
501
515
  useInput((input, key) => {
502
516
  if (key.ctrl && input === "o") {
503
517
  // Clear terminal screen when expanded state changes
504
- process.stdout.write("\x1Bc", () => {
505
- setIsExpanded((prev) => {
506
- const newExpanded = !prev;
507
- return newExpanded;
508
- });
518
+ setIsExpanded((prev) => {
519
+ const newExpanded = !prev;
520
+ return newExpanded;
509
521
  });
510
522
  }
511
523
 
524
+ if (key.ctrl && input === "t") {
525
+ setIsTaskListVisible((prev) => !prev);
526
+ }
527
+
512
528
  // Handle ESC key to cancel confirmation
513
529
  if (key.escape && isConfirmationVisible) {
514
530
  handleConfirmationCancel();
@@ -519,23 +535,25 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
519
535
  messages,
520
536
  isLoading,
521
537
  isCommandRunning,
522
- userInputHistory,
523
538
  isExpanded,
539
+ isTaskListVisible,
540
+ setIsTaskListVisible,
524
541
  sessionId,
525
542
  sendMessage,
526
543
  abortMessage,
527
544
  latestTotalTokens,
528
545
  isCompressing,
529
- saveMemory,
530
546
  mcpServers,
531
547
  connectMcpServer,
532
548
  disconnectMcpServer,
533
- backgroundShells,
534
- getBackgroundShellOutput,
535
- killBackgroundShell,
549
+ backgroundTasks,
550
+ sessionTasks,
551
+ getBackgroundTaskOutput,
552
+ stopBackgroundTask,
536
553
  slashCommands,
537
554
  hasSlashCommand,
538
555
  subagentMessages,
556
+ subagentLatestTokens,
539
557
  permissionMode,
540
558
  setPermissionMode,
541
559
  isConfirmationVisible,
@@ -544,8 +562,12 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
544
562
  hideConfirmation,
545
563
  handleConfirmationDecision,
546
564
  handleConfirmationCancel,
565
+ backgroundCurrentTask,
547
566
  rewindId,
548
567
  handleRewindSelect,
568
+ getFullMessageThread,
569
+ wasLastDetailsTooTall,
570
+ setWasLastDetailsTooTall,
549
571
  };
550
572
 
551
573
  return (