wave-code 0.5.0 → 0.6.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 (88) hide show
  1. package/dist/components/BackgroundTaskManager.d.ts +6 -0
  2. package/dist/components/BackgroundTaskManager.d.ts.map +1 -0
  3. package/dist/components/{TaskManager.js → BackgroundTaskManager.js} +1 -1
  4. package/dist/components/ChatInterface.d.ts.map +1 -1
  5. package/dist/components/ChatInterface.js +55 -5
  6. package/dist/components/CommandSelector.d.ts.map +1 -1
  7. package/dist/components/CommandSelector.js +10 -2
  8. package/dist/components/CompressDisplay.d.ts.map +1 -1
  9. package/dist/components/CompressDisplay.js +6 -10
  10. package/dist/components/ConfirmationDetails.d.ts +9 -0
  11. package/dist/components/ConfirmationDetails.d.ts.map +1 -0
  12. package/dist/components/ConfirmationDetails.js +53 -0
  13. package/dist/components/{Confirmation.d.ts → ConfirmationSelector.d.ts} +3 -3
  14. package/dist/components/ConfirmationSelector.d.ts.map +1 -0
  15. package/dist/components/{Confirmation.js → ConfirmationSelector.js} +34 -96
  16. package/dist/components/DiffDisplay.d.ts.map +1 -1
  17. package/dist/components/DiffDisplay.js +44 -1
  18. package/dist/components/FileSelector.d.ts.map +1 -1
  19. package/dist/components/FileSelector.js +2 -2
  20. package/dist/components/HistorySearch.d.ts.map +1 -1
  21. package/dist/components/HistorySearch.js +12 -4
  22. package/dist/components/InputBox.d.ts +1 -2
  23. package/dist/components/InputBox.d.ts.map +1 -1
  24. package/dist/components/InputBox.js +5 -9
  25. package/dist/components/LoadingIndicator.d.ts +11 -0
  26. package/dist/components/LoadingIndicator.d.ts.map +1 -0
  27. package/dist/components/LoadingIndicator.js +6 -0
  28. package/dist/components/Markdown.d.ts.map +1 -1
  29. package/dist/components/Markdown.js +114 -121
  30. package/dist/components/MessageItem.d.ts.map +1 -1
  31. package/dist/components/MessageItem.js +1 -2
  32. package/dist/components/MessageList.d.ts +2 -3
  33. package/dist/components/MessageList.d.ts.map +1 -1
  34. package/dist/components/MessageList.js +7 -7
  35. package/dist/components/PlanDisplay.d.ts.map +1 -1
  36. package/dist/components/PlanDisplay.js +4 -12
  37. package/dist/components/SubagentBlock.d.ts.map +1 -1
  38. package/dist/components/SubagentBlock.js +9 -6
  39. package/dist/components/TaskList.d.ts +3 -0
  40. package/dist/components/TaskList.d.ts.map +1 -0
  41. package/dist/components/TaskList.js +49 -0
  42. package/dist/components/ToolResultDisplay.js +1 -1
  43. package/dist/contexts/useChat.d.ts +5 -2
  44. package/dist/contexts/useChat.d.ts.map +1 -1
  45. package/dist/contexts/useChat.js +25 -25
  46. package/dist/hooks/useInputManager.d.ts +2 -7
  47. package/dist/hooks/useInputManager.d.ts.map +1 -1
  48. package/dist/hooks/useInputManager.js +8 -40
  49. package/dist/hooks/useTasks.d.ts +2 -0
  50. package/dist/hooks/useTasks.d.ts.map +1 -0
  51. package/dist/hooks/useTasks.js +5 -0
  52. package/dist/managers/InputManager.d.ts +4 -19
  53. package/dist/managers/InputManager.d.ts.map +1 -1
  54. package/dist/managers/InputManager.js +22 -65
  55. package/package.json +5 -6
  56. package/src/components/{TaskManager.tsx → BackgroundTaskManager.tsx} +4 -2
  57. package/src/components/ChatInterface.tsx +100 -20
  58. package/src/components/CommandSelector.tsx +35 -17
  59. package/src/components/CompressDisplay.tsx +5 -22
  60. package/src/components/ConfirmationDetails.tsx +108 -0
  61. package/src/components/{Confirmation.tsx → ConfirmationSelector.tsx} +69 -184
  62. package/src/components/DiffDisplay.tsx +62 -1
  63. package/src/components/FileSelector.tsx +0 -2
  64. package/src/components/HistorySearch.tsx +45 -21
  65. package/src/components/InputBox.tsx +9 -24
  66. package/src/components/LoadingIndicator.tsx +56 -0
  67. package/src/components/Markdown.tsx +126 -323
  68. package/src/components/MessageItem.tsx +1 -3
  69. package/src/components/MessageList.tsx +10 -67
  70. package/src/components/PlanDisplay.tsx +4 -27
  71. package/src/components/SubagentBlock.tsx +25 -16
  72. package/src/components/TaskList.tsx +70 -0
  73. package/src/components/ToolResultDisplay.tsx +2 -2
  74. package/src/contexts/useChat.tsx +38 -33
  75. package/src/hooks/useInputManager.ts +9 -47
  76. package/src/hooks/useTasks.ts +6 -0
  77. package/src/managers/InputManager.ts +25 -83
  78. package/dist/components/Confirmation.d.ts.map +0 -1
  79. package/dist/components/MemoryDisplay.d.ts +0 -8
  80. package/dist/components/MemoryDisplay.d.ts.map +0 -1
  81. package/dist/components/MemoryDisplay.js +0 -25
  82. package/dist/components/MemoryTypeSelector.d.ts +0 -8
  83. package/dist/components/MemoryTypeSelector.d.ts.map +0 -1
  84. package/dist/components/MemoryTypeSelector.js +0 -38
  85. package/dist/components/TaskManager.d.ts +0 -6
  86. package/dist/components/TaskManager.d.ts.map +0 -1
  87. package/src/components/MemoryDisplay.tsx +0 -62
  88. package/src/components/MemoryTypeSelector.tsx +0 -98
@@ -7,9 +7,8 @@ export interface MessageListProps {
7
7
  messages: Message[];
8
8
  isLoading?: boolean;
9
9
  isCommandRunning?: boolean;
10
- isCompressing?: boolean;
11
- latestTotalTokens?: number;
12
10
  isExpanded?: boolean;
11
+ forceStaticLastMessage?: boolean;
13
12
  }
14
13
 
15
14
  export const MessageList = React.memo(
@@ -17,15 +16,16 @@ export const MessageList = React.memo(
17
16
  messages,
18
17
  isLoading = false,
19
18
  isCommandRunning = false,
20
- isCompressing = false,
21
- latestTotalTokens = 0,
22
19
  isExpanded = false,
20
+ forceStaticLastMessage = false,
23
21
  }: MessageListProps) => {
24
22
  // Empty message state
25
23
  if (messages.length === 0) {
26
24
  return (
27
- <Box flexDirection="column" paddingY={1}>
28
- <Text color="gray">Welcome to WAVE Code Assistant!</Text>
25
+ <Box flexDirection="column" gap={1}>
26
+ <Box flexDirection="column" paddingY={1}>
27
+ <Text color="gray">Welcome to WAVE Code Assistant!</Text>
28
+ </Box>
29
29
  </Box>
30
30
  );
31
31
  }
@@ -42,7 +42,8 @@ export const MessageList = React.memo(
42
42
  : 0;
43
43
 
44
44
  // Compute which messages to render statically vs dynamically
45
- const shouldRenderLastDynamic = isLoading || isCommandRunning;
45
+ const shouldRenderLastDynamic =
46
+ !forceStaticLastMessage && (isLoading || isCommandRunning);
46
47
  const staticMessages = shouldRenderLastDynamic
47
48
  ? displayMessages.slice(0, -1)
48
49
  : displayMessages;
@@ -52,7 +53,7 @@ export const MessageList = React.memo(
52
53
  : [];
53
54
 
54
55
  return (
55
- <Box flexDirection="column" gap={1}>
56
+ <Box flexDirection="column" gap={1} paddingBottom={1}>
56
57
  {/* Show omitted message count when limiting */}
57
58
  {omittedCount > 0 && (
58
59
  <Box>
@@ -86,7 +87,7 @@ export const MessageList = React.memo(
86
87
  const previousMessage =
87
88
  messageIndex > 0 ? displayMessages[messageIndex - 1] : undefined;
88
89
  return (
89
- <Box key={`dynamic-${index}`} marginTop={-1}>
90
+ <Box key={`dynamic-${index}`}>
90
91
  <MessageItem
91
92
  message={message}
92
93
  shouldShowHeader={previousMessage?.role !== message.role}
@@ -95,64 +96,6 @@ export const MessageList = React.memo(
95
96
  </Box>
96
97
  );
97
98
  })}
98
-
99
- {(isLoading || isCommandRunning || isCompressing) && (
100
- <Box flexDirection="column" gap={1}>
101
- {isLoading && (
102
- <Box>
103
- <Text color="yellow">💭 AI is thinking... </Text>
104
- <Text color="gray" dimColor>
105
- |{" "}
106
- </Text>
107
- <Text color="red" bold>
108
- Esc
109
- </Text>
110
- <Text color="gray" dimColor>
111
- {" "}
112
- to abort
113
- </Text>
114
- </Box>
115
- )}
116
- {isCommandRunning && (
117
- <Text color="blue">🚀 Command is running...</Text>
118
- )}
119
- {isCompressing && (
120
- <Text color="magenta">🗜️ Compressing message history...</Text>
121
- )}
122
- </Box>
123
- )}
124
-
125
- {/* Bottom info and shortcut key hints */}
126
- {messages.length > 0 && (
127
- <Box>
128
- <Box justifyContent="space-between" width="100%">
129
- <Box>
130
- <Text color="gray">
131
- Messages {messages.length}
132
- {latestTotalTokens > 0 && (
133
- <>
134
- <Text color="gray" dimColor>
135
- {" "}
136
- |{" "}
137
- </Text>
138
- <Text color="blue" bold>
139
- {latestTotalTokens.toLocaleString()}
140
- </Text>
141
- <Text color="gray" dimColor>
142
- {" "}
143
- tokens
144
- </Text>
145
- </>
146
- )}
147
- </Text>
148
- </Box>
149
- <Text color="gray" dimColor>
150
- <Text color="cyan">Ctrl+O</Text> Toggle{" "}
151
- {isExpanded ? "Collapse" : "Expand"}
152
- </Text>
153
- </Box>
154
- </Box>
155
- )}
156
99
  </Box>
157
100
  );
158
101
  },
@@ -1,5 +1,5 @@
1
- import React, { useMemo } from "react";
2
- import { Box, Text, useStdout } from "ink";
1
+ import React from "react";
2
+ import { Box } from "ink";
3
3
  import { Markdown } from "./Markdown.js";
4
4
 
5
5
  interface PlanDisplayProps {
@@ -7,35 +7,12 @@ interface PlanDisplayProps {
7
7
  isExpanded?: boolean;
8
8
  }
9
9
 
10
- export const PlanDisplay: React.FC<PlanDisplayProps> = ({
11
- plan,
12
- isExpanded = false,
13
- }) => {
14
- const { stdout } = useStdout();
15
- const maxHeight = useMemo(() => {
16
- // Similar to DiffDisplay.tsx maxHeight calculation
17
- return Math.max(5, (stdout?.rows || 24) - 25);
18
- }, [stdout?.rows]);
19
-
20
- const lines = useMemo(() => plan.split("\n"), [plan]);
21
- const isOverflowing = !isExpanded && lines.length > maxHeight;
22
-
10
+ export const PlanDisplay: React.FC<PlanDisplayProps> = ({ plan }) => {
23
11
  return (
24
12
  <Box flexDirection="column" marginTop={1}>
25
- <Box
26
- flexDirection="column"
27
- height={isOverflowing ? maxHeight : undefined}
28
- overflow="hidden"
29
- >
13
+ <Box flexDirection="column">
30
14
  <Markdown>{plan}</Markdown>
31
15
  </Box>
32
- {isOverflowing && (
33
- <Box marginTop={1}>
34
- <Text color="yellow" dimColor>
35
- ... (plan truncated, {lines.length} lines total)
36
- </Text>
37
- </Box>
38
- )}
39
16
  </Box>
40
17
  );
41
18
  };
@@ -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,16 +9,22 @@ 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
+
14
+ // Get messages for this subagent from context
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;
13
22
 
14
23
  // If the subagent is running in the background, don't show the block
15
24
  if (block.runInBackground) {
16
25
  return null;
17
26
  }
18
27
 
19
- // Get messages for this subagent from context
20
- const messages = subagentMessages[block.subagentId] || [];
21
-
22
28
  // Status indicator mapping
23
29
  const getStatusIndicator = (status: SubagentBlockType["status"]) => {
24
30
  switch (status) {
@@ -63,7 +69,7 @@ export const SubagentBlock: React.FC<SubagentBlockProps> = ({ block }) => {
63
69
  return { tools: tools.reverse(), totalToolCount }; // Reverse to show oldest first, newest last
64
70
  };
65
71
 
66
- const { tools: lastTwoTools, totalToolCount } = getLastTwoTools();
72
+ const { tools: lastTwoTools } = getLastTwoTools();
67
73
 
68
74
  // Get the last text message content if completed
69
75
  const getLastTextMessage = () => {
@@ -93,9 +99,7 @@ export const SubagentBlock: React.FC<SubagentBlockProps> = ({ block }) => {
93
99
  borderStyle="classic"
94
100
  borderColor="magenta"
95
101
  paddingX={1}
96
- paddingY={0}
97
102
  flexDirection="column"
98
- marginBottom={1}
99
103
  >
100
104
  {/* Header Section */}
101
105
  <Box flexDirection="row" gap={1}>
@@ -107,26 +111,31 @@ export const SubagentBlock: React.FC<SubagentBlockProps> = ({ block }) => {
107
111
  </Text>
108
112
  <Text color="gray" dimColor>
109
113
  {" "}
110
- ({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
+ )
111
125
  </Text>
112
126
  </Box>
113
127
  </Box>
114
128
 
115
129
  {/* Last Text Message Section */}
116
130
  {lastTextMessage && (
117
- <Box marginTop={1}>
131
+ <Box>
118
132
  <Markdown>{lastTextMessage}</Markdown>
119
133
  </Box>
120
134
  )}
121
135
 
122
136
  {/* Tool Names Section - Vertical List */}
123
137
  {block.status !== "completed" && lastTwoTools.length > 0 && (
124
- <Box flexDirection="column" marginTop={1} gap={1}>
125
- {totalToolCount > 2 && (
126
- <Text color="gray" dimColor>
127
- ...
128
- </Text>
129
- )}
138
+ <Box flexDirection="column">
130
139
  {lastTwoTools.map((tool, index) => (
131
140
  <Box key={index} flexDirection="row">
132
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
+ };
@@ -68,7 +68,7 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
68
68
  const shortResult = getShortResult();
69
69
 
70
70
  return (
71
- <Box flexDirection="column" gap={1}>
71
+ <Box flexDirection="column">
72
72
  <Box>
73
73
  <Text color="magenta">🔧 </Text>
74
74
  <Text color="white">{toolName}</Text>
@@ -91,7 +91,7 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
91
91
  flexDirection="column"
92
92
  >
93
93
  {shortResult.split("\n").map((line, index) => (
94
- <Text key={index} color="white">
94
+ <Text key={index} color="gray">
95
95
  {line}
96
96
  </Text>
97
97
  ))}
@@ -12,6 +12,7 @@ import type {
12
12
  Message,
13
13
  McpServerStatus,
14
14
  BackgroundTask,
15
+ Task,
15
16
  SlashCommand,
16
17
  PermissionDecision,
17
18
  PermissionMode,
@@ -33,6 +34,8 @@ export interface ChatContextType {
33
34
  userInputHistory: string[];
34
35
  // Message display state
35
36
  isExpanded: boolean;
37
+ isTaskListVisible: boolean;
38
+ setIsTaskListVisible: (visible: boolean) => void;
36
39
  // AI functionality
37
40
  sessionId: string;
38
41
  sendMessage: (
@@ -41,14 +44,14 @@ export interface ChatContextType {
41
44
  ) => Promise<void>;
42
45
  abortMessage: () => void;
43
46
  latestTotalTokens: number;
44
- // Memory functionality
45
- saveMemory: (message: string, type: "project" | "user") => Promise<void>;
46
47
  // MCP functionality
47
48
  mcpServers: McpServerStatus[];
48
49
  connectMcpServer: (serverName: string) => Promise<boolean>;
49
50
  disconnectMcpServer: (serverName: string) => Promise<boolean>;
50
51
  // Background tasks
51
52
  backgroundTasks: BackgroundTask[];
53
+ // Session tasks
54
+ sessionTasks: Task[];
52
55
  getBackgroundTaskOutput: (
53
56
  taskId: string,
54
57
  ) => { stdout: string; stderr: string; status: string } | null;
@@ -58,6 +61,7 @@ export interface ChatContextType {
58
61
  hasSlashCommand: (commandId: string) => boolean;
59
62
  // Subagent messages
60
63
  subagentMessages: Record<string, Message[]>;
64
+ subagentLatestTokens: Record<string, number>;
61
65
  // Permission functionality
62
66
  permissionMode: PermissionMode;
63
67
  setPermissionMode: (mode: PermissionMode) => void;
@@ -110,6 +114,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
110
114
 
111
115
  // Message Display State
112
116
  const [isExpanded, setIsExpanded] = useState(false);
117
+ const [isTaskListVisible, setIsTaskListVisible] = useState(true);
113
118
 
114
119
  // AI State
115
120
  const [messages, setMessages] = useState<Message[]>([]);
@@ -125,6 +130,8 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
125
130
 
126
131
  // Background tasks state
127
132
  const [backgroundTasks, setBackgroundTasks] = useState<BackgroundTask[]>([]);
133
+ // Session tasks state
134
+ const [sessionTasks, setSessionTasks] = useState<Task[]>([]);
128
135
 
129
136
  // Command state
130
137
  const [slashCommands, setSlashCommands] = useState<SlashCommand[]>([]);
@@ -133,6 +140,9 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
133
140
  const [subagentMessages, setSubagentMessages] = useState<
134
141
  Record<string, Message[]>
135
142
  >({});
143
+ const [subagentLatestTokens, setSubagentLatestTokens] = useState<
144
+ Record<string, number>
145
+ >({});
136
146
 
137
147
  // Permission state
138
148
  const [permissionMode, setPermissionModeState] =
@@ -209,9 +219,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
209
219
  setMcpServers([...servers]);
210
220
  },
211
221
  onSessionIdChange: (sessionId) => {
212
- process.stdout.write("\x1Bc", () => {
213
- setSessionId(sessionId);
214
- });
222
+ setSessionId(sessionId);
215
223
  },
216
224
  onLatestTotalTokensChange: (tokens) => {
217
225
  setlatestTotalTokens(tokens);
@@ -225,13 +233,25 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
225
233
  onTasksChange: (tasks) => {
226
234
  setBackgroundTasks([...tasks]);
227
235
  },
228
- onSubagentMessagesChange: (subagentId, messages) => {
236
+ onSessionTasksChange: (tasks) => {
237
+ setSessionTasks([...tasks]);
238
+ },
239
+ onSubagentMessagesChange: (subagentId: string, messages: Message[]) => {
229
240
  logger.debug("onSubagentMessagesChange", subagentId, messages.length);
230
241
  setSubagentMessages((prev) => ({
231
242
  ...prev,
232
243
  [subagentId]: [...messages],
233
244
  }));
234
245
  },
246
+ onSubagentLatestTotalTokensChange: (
247
+ subagentId: string,
248
+ tokens: number,
249
+ ) => {
250
+ setSubagentLatestTokens((prev) => ({
251
+ ...prev,
252
+ [subagentId]: tokens,
253
+ }));
254
+ },
235
255
  onPermissionModeChange: (mode) => {
236
256
  setPermissionModeState(mode);
237
257
  },
@@ -338,16 +358,6 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
338
358
  if (!hasTextContent && !hasImageAttachments) return;
339
359
 
340
360
  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
361
  // Handle bash mode - check if it's a bash command (starts with ! and only one line)
352
362
  if (content.startsWith("!") && !content.includes("\n")) {
353
363
  const command = content.substring(1).trim();
@@ -394,14 +404,6 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
394
404
  agentRef.current?.abortMessage();
395
405
  }, []);
396
406
 
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
407
  // Permission management methods
406
408
  const setPermissionMode = useCallback((mode: PermissionMode) => {
407
409
  setPermissionModeState((prev) => {
@@ -492,9 +494,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
492
494
  await agentRef.current.truncateHistory(index);
493
495
 
494
496
  // Clear terminal screen after rewind
495
- process.stdout.write("\x1Bc", () => {
496
- setRewindId((prev) => prev + 1);
497
- });
497
+ setRewindId((prev) => prev + 1);
498
498
  } catch (error) {
499
499
  logger.error("Failed to rewind:", error);
500
500
  }
@@ -505,14 +505,16 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
505
505
  useInput((input, key) => {
506
506
  if (key.ctrl && input === "o") {
507
507
  // Clear terminal screen when expanded state changes
508
- process.stdout.write("\x1Bc", () => {
509
- setIsExpanded((prev) => {
510
- const newExpanded = !prev;
511
- return newExpanded;
512
- });
508
+ setIsExpanded((prev) => {
509
+ const newExpanded = !prev;
510
+ return newExpanded;
513
511
  });
514
512
  }
515
513
 
514
+ if (key.ctrl && input === "t") {
515
+ setIsTaskListVisible((prev) => !prev);
516
+ }
517
+
516
518
  // Handle ESC key to cancel confirmation
517
519
  if (key.escape && isConfirmationVisible) {
518
520
  handleConfirmationCancel();
@@ -525,21 +527,24 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
525
527
  isCommandRunning,
526
528
  userInputHistory,
527
529
  isExpanded,
530
+ isTaskListVisible,
531
+ setIsTaskListVisible,
528
532
  sessionId,
529
533
  sendMessage,
530
534
  abortMessage,
531
535
  latestTotalTokens,
532
536
  isCompressing,
533
- saveMemory,
534
537
  mcpServers,
535
538
  connectMcpServer,
536
539
  disconnectMcpServer,
537
540
  backgroundTasks,
541
+ sessionTasks,
538
542
  getBackgroundTaskOutput,
539
543
  stopBackgroundTask,
540
544
  slashCommands,
541
545
  hasSlashCommand,
542
546
  subagentMessages,
547
+ subagentLatestTokens,
543
548
  permissionMode,
544
549
  setPermissionMode,
545
550
  isConfirmationVisible,
@@ -33,11 +33,8 @@ export const useInputManager = (
33
33
  show: false,
34
34
  query: "",
35
35
  });
36
- const [memoryTypeSelectorState, setMemoryTypeSelectorState] = useState({
37
- show: false,
38
- message: "",
39
- });
40
- const [showTaskManager, setShowTaskManager] = useState(false);
36
+ const [showBackgroundTaskManager, setShowBackgroundTaskManager] =
37
+ useState(false);
41
38
  const [showMcpManager, setShowMcpManager] = useState(false);
42
39
  const [showRewindManager, setShowRewindManager] = useState(false);
43
40
  const [permissionMode, setPermissionModeState] =
@@ -61,11 +58,8 @@ export const useInputManager = (
61
58
  onHistorySearchStateChange: (show, query) => {
62
59
  setHistorySearchState({ show, query });
63
60
  },
64
- onMemoryTypeSelectorStateChange: (show, message) => {
65
- setMemoryTypeSelectorState({ show, message });
66
- },
67
- onTaskManagerStateChange: (show) => {
68
- setShowTaskManager(show);
61
+ onBackgroundTaskManagerStateChange: (show) => {
62
+ setShowBackgroundTaskManager(show);
69
63
  },
70
64
  onMcpManagerStateChange: (show) => {
71
65
  setShowMcpManager(show);
@@ -78,9 +72,6 @@ export const useInputManager = (
78
72
  callbacks.onPermissionModeChange?.(mode);
79
73
  },
80
74
  onImagesStateChange: setAttachedImages,
81
- onShowTaskManager: () => setShowTaskManager(true),
82
- onShowMcpManager: () => setShowMcpManager(true),
83
- onShowRewindManager: () => setShowRewindManager(true),
84
75
  ...callbacks,
85
76
  });
86
77
 
@@ -101,11 +92,8 @@ export const useInputManager = (
101
92
  onHistorySearchStateChange: (show, query) => {
102
93
  setHistorySearchState({ show, query });
103
94
  },
104
- onMemoryTypeSelectorStateChange: (show, message) => {
105
- setMemoryTypeSelectorState({ show, message });
106
- },
107
- onTaskManagerStateChange: (show) => {
108
- setShowTaskManager(show);
95
+ onBackgroundTaskManagerStateChange: (show) => {
96
+ setShowBackgroundTaskManager(show);
109
97
  },
110
98
  onMcpManagerStateChange: (show) => {
111
99
  setShowMcpManager(show);
@@ -118,9 +106,6 @@ export const useInputManager = (
118
106
  callbacks.onPermissionModeChange?.(mode);
119
107
  },
120
108
  onImagesStateChange: setAttachedImages,
121
- onShowTaskManager: () => setShowTaskManager(true),
122
- onShowMcpManager: () => setShowMcpManager(true),
123
- onShowRewindManager: () => setShowRewindManager(true),
124
109
  ...callbacks,
125
110
  });
126
111
  }
@@ -252,22 +237,6 @@ export const useInputManager = (
252
237
  managerRef.current?.handleCancelHistorySearch();
253
238
  }, []);
254
239
 
255
- // Memory type selector methods
256
- const activateMemoryTypeSelector = useCallback((message: string) => {
257
- managerRef.current?.activateMemoryTypeSelector(message);
258
- }, []);
259
-
260
- const handleMemoryTypeSelect = useCallback(
261
- async (type: "project" | "user") => {
262
- await managerRef.current?.handleMemoryTypeSelect(type);
263
- },
264
- [],
265
- );
266
-
267
- const handleCancelMemoryTypeSelect = useCallback(() => {
268
- managerRef.current?.handleCancelMemoryTypeSelect();
269
- }, []);
270
-
271
240
  // Input history methods
272
241
  const setUserInputHistory = useCallback((history: string[]) => {
273
242
  managerRef.current?.setUserInputHistory(history);
@@ -317,9 +286,7 @@ export const useInputManager = (
317
286
  slashPosition: commandSelectorState.position,
318
287
  showHistorySearch: historySearchState.show,
319
288
  historySearchQuery: historySearchState.query,
320
- showMemoryTypeSelector: memoryTypeSelectorState.show,
321
- memoryMessage: memoryTypeSelectorState.message,
322
- showTaskManager,
289
+ showBackgroundTaskManager,
323
290
  showMcpManager,
324
291
  showRewindManager,
325
292
  permissionMode,
@@ -354,11 +321,6 @@ export const useInputManager = (
354
321
  handleHistorySearchSelect,
355
322
  handleCancelHistorySearch,
356
323
 
357
- // Memory type selector
358
- activateMemoryTypeSelector,
359
- handleMemoryTypeSelect,
360
- handleCancelMemoryTypeSelect,
361
-
362
324
  // Input history
363
325
  setUserInputHistory,
364
326
  navigateHistory,
@@ -368,8 +330,8 @@ export const useInputManager = (
368
330
  handleSpecialCharInput,
369
331
 
370
332
  // Bash/MCP Manager
371
- setShowTaskManager: useCallback((show: boolean) => {
372
- managerRef.current?.setShowTaskManager(show);
333
+ setShowBackgroundTaskManager: useCallback((show: boolean) => {
334
+ managerRef.current?.setShowBackgroundTaskManager(show);
373
335
  }, []),
374
336
  setShowMcpManager: useCallback((show: boolean) => {
375
337
  managerRef.current?.setShowMcpManager(show);
@@ -0,0 +1,6 @@
1
+ import { useChat } from "../contexts/useChat.js";
2
+
3
+ export const useTasks = () => {
4
+ const { sessionTasks } = useChat();
5
+ return sessionTasks;
6
+ };