wave-code 0.5.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.
- package/dist/components/App.d.ts.map +1 -1
- package/dist/components/App.js +38 -2
- package/dist/components/BackgroundTaskManager.d.ts +6 -0
- package/dist/components/BackgroundTaskManager.d.ts.map +1 -0
- package/dist/components/{TaskManager.js → BackgroundTaskManager.js} +1 -1
- package/dist/components/ChatInterface.d.ts.map +1 -1
- package/dist/components/ChatInterface.js +39 -5
- package/dist/components/CommandSelector.d.ts.map +1 -1
- package/dist/components/CommandSelector.js +10 -2
- package/dist/components/CompressDisplay.d.ts.map +1 -1
- package/dist/components/CompressDisplay.js +6 -10
- package/dist/components/ConfirmationDetails.d.ts +9 -0
- package/dist/components/ConfirmationDetails.d.ts.map +1 -0
- package/dist/components/ConfirmationDetails.js +53 -0
- package/dist/components/{Confirmation.d.ts → ConfirmationSelector.d.ts} +3 -3
- package/dist/components/ConfirmationSelector.d.ts.map +1 -0
- package/dist/components/{Confirmation.js → ConfirmationSelector.js} +34 -96
- package/dist/components/DiffDisplay.d.ts.map +1 -1
- package/dist/components/DiffDisplay.js +44 -1
- package/dist/components/FileSelector.d.ts.map +1 -1
- package/dist/components/FileSelector.js +2 -2
- package/dist/components/HistorySearch.d.ts.map +1 -1
- package/dist/components/HistorySearch.js +12 -4
- package/dist/components/InputBox.d.ts +1 -3
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +7 -17
- package/dist/components/LoadingIndicator.d.ts +11 -0
- package/dist/components/LoadingIndicator.d.ts.map +1 -0
- package/dist/components/LoadingIndicator.js +6 -0
- package/dist/components/Markdown.d.ts.map +1 -1
- package/dist/components/Markdown.js +114 -121
- package/dist/components/MessageItem.d.ts.map +1 -1
- package/dist/components/MessageItem.js +1 -2
- package/dist/components/MessageList.d.ts +2 -3
- package/dist/components/MessageList.d.ts.map +1 -1
- package/dist/components/MessageList.js +7 -7
- package/dist/components/PlanDisplay.d.ts.map +1 -1
- package/dist/components/PlanDisplay.js +4 -12
- package/dist/components/RewindCommand.d.ts +4 -0
- package/dist/components/RewindCommand.d.ts.map +1 -1
- package/dist/components/RewindCommand.js +19 -2
- package/dist/components/SubagentBlock.d.ts.map +1 -1
- package/dist/components/SubagentBlock.js +9 -6
- package/dist/components/TaskList.d.ts +3 -0
- package/dist/components/TaskList.d.ts.map +1 -0
- package/dist/components/TaskList.js +49 -0
- package/dist/components/ToolResultDisplay.js +1 -1
- package/dist/contexts/useChat.d.ts +11 -3
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +36 -31
- package/dist/hooks/useInputManager.d.ts +2 -13
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +8 -57
- package/dist/hooks/useTasks.d.ts +2 -0
- package/dist/hooks/useTasks.d.ts.map +1 -0
- package/dist/hooks/useTasks.js +5 -0
- package/dist/managers/InputManager.d.ts +4 -28
- package/dist/managers/InputManager.d.ts.map +1 -1
- package/dist/managers/InputManager.js +22 -128
- package/package.json +5 -6
- package/src/components/App.tsx +50 -3
- package/src/components/{TaskManager.tsx → BackgroundTaskManager.tsx} +4 -2
- package/src/components/ChatInterface.tsx +79 -23
- package/src/components/CommandSelector.tsx +35 -17
- package/src/components/CompressDisplay.tsx +5 -22
- package/src/components/ConfirmationDetails.tsx +108 -0
- package/src/components/{Confirmation.tsx → ConfirmationSelector.tsx} +69 -184
- package/src/components/DiffDisplay.tsx +62 -1
- package/src/components/FileSelector.tsx +0 -2
- package/src/components/HistorySearch.tsx +45 -21
- package/src/components/InputBox.tsx +11 -33
- package/src/components/LoadingIndicator.tsx +56 -0
- package/src/components/Markdown.tsx +126 -323
- package/src/components/MessageItem.tsx +1 -3
- package/src/components/MessageList.tsx +10 -67
- package/src/components/PlanDisplay.tsx +4 -27
- package/src/components/RewindCommand.tsx +38 -1
- package/src/components/SubagentBlock.tsx +25 -16
- package/src/components/TaskList.tsx +70 -0
- package/src/components/ToolResultDisplay.tsx +2 -2
- package/src/contexts/useChat.tsx +57 -40
- package/src/hooks/useInputManager.ts +9 -73
- package/src/hooks/useTasks.ts +6 -0
- package/src/managers/InputManager.ts +25 -159
- package/dist/components/Confirmation.d.ts.map +0 -1
- package/dist/components/MemoryDisplay.d.ts +0 -8
- package/dist/components/MemoryDisplay.d.ts.map +0 -1
- package/dist/components/MemoryDisplay.js +0 -25
- package/dist/components/MemoryTypeSelector.d.ts +0 -8
- package/dist/components/MemoryTypeSelector.d.ts.map +0 -1
- package/dist/components/MemoryTypeSelector.js +0 -38
- package/dist/components/TaskManager.d.ts +0 -6
- package/dist/components/TaskManager.d.ts.map +0 -1
- package/src/components/MemoryDisplay.tsx +0 -62
- package/src/components/MemoryTypeSelector.tsx +0 -98
|
@@ -4,7 +4,6 @@ import type { Message } from "wave-agent-sdk";
|
|
|
4
4
|
import { MessageSource } from "wave-agent-sdk";
|
|
5
5
|
import { CommandOutputDisplay } from "./CommandOutputDisplay.js";
|
|
6
6
|
import { ToolResultDisplay } from "./ToolResultDisplay.js";
|
|
7
|
-
import { MemoryDisplay } from "./MemoryDisplay.js";
|
|
8
7
|
import { CompressDisplay } from "./CompressDisplay.js";
|
|
9
8
|
import { SubagentBlock } from "./SubagentBlock.js";
|
|
10
9
|
import { ReasoningDisplay } from "./ReasoningDisplay.js";
|
|
@@ -22,6 +21,7 @@ export const MessageItem = ({
|
|
|
22
21
|
shouldShowHeader,
|
|
23
22
|
}: MessageItemProps) => {
|
|
24
23
|
if (message.blocks.length === 0) return null;
|
|
24
|
+
|
|
25
25
|
return (
|
|
26
26
|
<Box flexDirection="column" gap={1} marginTop={1}>
|
|
27
27
|
{shouldShowHeader && (
|
|
@@ -79,8 +79,6 @@ export const MessageItem = ({
|
|
|
79
79
|
</Box>
|
|
80
80
|
)}
|
|
81
81
|
|
|
82
|
-
{block.type === "memory" && <MemoryDisplay block={block} />}
|
|
83
|
-
|
|
84
82
|
{block.type === "compress" && (
|
|
85
83
|
<CompressDisplay block={block} isExpanded={isExpanded} />
|
|
86
84
|
)}
|
|
@@ -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"
|
|
28
|
-
<
|
|
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 =
|
|
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}`}
|
|
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
|
|
2
|
-
import { Box
|
|
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
|
};
|
|
@@ -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,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
|
|
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
|
|
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"
|
|
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"
|
|
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="
|
|
94
|
+
<Text key={index} color="gray">
|
|
95
95
|
{line}
|
|
96
96
|
</Text>
|
|
97
97
|
))}
|