wave-code 0.6.1 ā 0.6.2
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 +14 -12
- package/dist/components/ChatInterface.d.ts.map +1 -1
- package/dist/components/ChatInterface.js +2 -1
- package/dist/components/CommandOutputDisplay.d.ts.map +1 -1
- package/dist/components/CommandOutputDisplay.js +6 -17
- package/dist/components/CommandSelector.d.ts.map +1 -1
- package/dist/components/CommandSelector.js +6 -0
- package/dist/components/ConfirmationSelector.d.ts.map +1 -1
- package/dist/components/ConfirmationSelector.js +1 -1
- package/dist/components/DiffDisplay.d.ts.map +1 -1
- package/dist/components/DiffDisplay.js +4 -0
- package/dist/components/HelpView.d.ts +6 -0
- package/dist/components/HelpView.d.ts.map +1 -0
- package/dist/components/HelpView.js +24 -0
- package/dist/components/InputBox.d.ts +1 -1
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +10 -3
- package/dist/components/LoadingIndicator.js +1 -1
- package/dist/components/MessageItem.d.ts +1 -1
- package/dist/components/MessageItem.d.ts.map +1 -1
- package/dist/components/MessageItem.js +3 -4
- package/dist/components/MessageList.d.ts.map +1 -1
- package/dist/components/MessageList.js +24 -7
- package/dist/components/RewindCommand.js +1 -1
- package/dist/components/TaskList.d.ts.map +1 -1
- package/dist/components/TaskList.js +4 -13
- package/dist/components/ToolDisplay.d.ts +9 -0
- package/dist/components/ToolDisplay.d.ts.map +1 -0
- package/dist/components/ToolDisplay.js +44 -0
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +15 -1
- package/dist/hooks/useInputManager.d.ts +2 -2
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +12 -8
- package/dist/managers/InputManager.d.ts +4 -2
- package/dist/managers/InputManager.d.ts.map +1 -1
- package/dist/managers/InputManager.js +17 -17
- package/dist/print-cli.d.ts.map +1 -1
- package/dist/print-cli.js +11 -30
- package/package.json +2 -2
- package/src/components/App.tsx +16 -15
- package/src/components/ChatInterface.tsx +3 -2
- package/src/components/CommandOutputDisplay.tsx +16 -38
- package/src/components/CommandSelector.tsx +6 -0
- package/src/components/ConfirmationSelector.tsx +5 -9
- package/src/components/DiffDisplay.tsx +9 -0
- package/src/components/HelpView.tsx +59 -0
- package/src/components/InputBox.tsx +43 -33
- package/src/components/LoadingIndicator.tsx +1 -1
- package/src/components/MessageItem.tsx +12 -21
- package/src/components/MessageList.tsx +40 -17
- package/src/components/RewindCommand.tsx +1 -1
- package/src/components/TaskList.tsx +4 -16
- package/src/components/{ToolResultDisplay.tsx ā ToolDisplay.tsx} +6 -16
- package/src/contexts/useChat.tsx +16 -1
- package/src/hooks/useInputManager.ts +12 -10
- package/src/managers/InputManager.ts +19 -21
- package/src/print-cli.ts +17 -35
- package/dist/components/SubagentBlock.d.ts +0 -8
- package/dist/components/SubagentBlock.d.ts.map +0 -1
- package/dist/components/SubagentBlock.js +0 -73
- package/dist/components/ToolResultDisplay.d.ts +0 -9
- package/dist/components/ToolResultDisplay.d.ts.map +0 -1
- package/dist/components/ToolResultDisplay.js +0 -54
- package/src/components/SubagentBlock.tsx +0 -152
|
@@ -18,7 +18,7 @@ export const LoadingIndicator = ({
|
|
|
18
18
|
<Box flexDirection="column">
|
|
19
19
|
{isLoading && (
|
|
20
20
|
<Box>
|
|
21
|
-
<Text color="yellow"
|
|
21
|
+
<Text color="yellow">ā» AI is thinking... </Text>
|
|
22
22
|
{latestTotalTokens > 0 && (
|
|
23
23
|
<>
|
|
24
24
|
<Text color="gray" dimColor>
|
|
@@ -3,9 +3,8 @@ import { Box, Text } from "ink";
|
|
|
3
3
|
import type { Message } from "wave-agent-sdk";
|
|
4
4
|
import { MessageSource } from "wave-agent-sdk";
|
|
5
5
|
import { CommandOutputDisplay } from "./CommandOutputDisplay.js";
|
|
6
|
-
import {
|
|
6
|
+
import { ToolDisplay } from "./ToolDisplay.js";
|
|
7
7
|
import { CompressDisplay } from "./CompressDisplay.js";
|
|
8
|
-
import { SubagentBlock } from "./SubagentBlock.js";
|
|
9
8
|
import { ReasoningDisplay } from "./ReasoningDisplay.js";
|
|
10
9
|
import { Markdown } from "./Markdown.js";
|
|
11
10
|
|
|
@@ -15,23 +14,11 @@ export interface MessageItemProps {
|
|
|
15
14
|
shouldShowHeader: boolean;
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
export const MessageItem = ({
|
|
19
|
-
message,
|
|
20
|
-
isExpanded,
|
|
21
|
-
shouldShowHeader,
|
|
22
|
-
}: MessageItemProps) => {
|
|
17
|
+
export const MessageItem = ({ message, isExpanded }: MessageItemProps) => {
|
|
23
18
|
if (message.blocks.length === 0) return null;
|
|
24
19
|
|
|
25
20
|
return (
|
|
26
21
|
<Box flexDirection="column" gap={1} marginTop={1}>
|
|
27
|
-
{shouldShowHeader && (
|
|
28
|
-
<Box>
|
|
29
|
-
<Text color={message.role === "user" ? "cyan" : "green"} bold>
|
|
30
|
-
{message.role === "user" ? "š¤ You" : "š¤ Assistant"}
|
|
31
|
-
</Text>
|
|
32
|
-
</Box>
|
|
33
|
-
)}
|
|
34
|
-
|
|
35
22
|
<Box flexDirection="column" gap={1}>
|
|
36
23
|
{message.blocks.map((block, blockIndex) => (
|
|
37
24
|
<Box key={blockIndex}>
|
|
@@ -39,15 +26,21 @@ export const MessageItem = ({
|
|
|
39
26
|
<Box>
|
|
40
27
|
{block.customCommandContent && (
|
|
41
28
|
<Text color="cyan" bold>
|
|
42
|
-
ā”
|
|
29
|
+
ā”
|
|
43
30
|
</Text>
|
|
44
31
|
)}
|
|
45
32
|
{block.source === MessageSource.HOOK && (
|
|
46
33
|
<Text color="magenta" bold>
|
|
47
|
-
š
|
|
34
|
+
š
|
|
35
|
+
</Text>
|
|
36
|
+
)}
|
|
37
|
+
{message.role === "user" ? (
|
|
38
|
+
<Text backgroundColor="gray" color="white">
|
|
39
|
+
{block.content}
|
|
48
40
|
</Text>
|
|
41
|
+
) : (
|
|
42
|
+
<Markdown>{block.content}</Markdown>
|
|
49
43
|
)}
|
|
50
|
-
<Markdown>{block.content}</Markdown>
|
|
51
44
|
</Box>
|
|
52
45
|
)}
|
|
53
46
|
|
|
@@ -62,7 +55,7 @@ export const MessageItem = ({
|
|
|
62
55
|
)}
|
|
63
56
|
|
|
64
57
|
{block.type === "tool" && (
|
|
65
|
-
<
|
|
58
|
+
<ToolDisplay block={block} isExpanded={isExpanded} />
|
|
66
59
|
)}
|
|
67
60
|
|
|
68
61
|
{block.type === "image" && (
|
|
@@ -83,8 +76,6 @@ export const MessageItem = ({
|
|
|
83
76
|
<CompressDisplay block={block} isExpanded={isExpanded} />
|
|
84
77
|
)}
|
|
85
78
|
|
|
86
|
-
{block.type === "subagent" && <SubagentBlock block={block} />}
|
|
87
|
-
|
|
88
79
|
{block.type === "reasoning" && <ReasoningDisplay block={block} />}
|
|
89
80
|
</Box>
|
|
90
81
|
))}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Box, Text, Static } from "ink";
|
|
3
3
|
import type { Message } from "wave-agent-sdk";
|
|
4
|
+
import {
|
|
5
|
+
TASK_CREATE_TOOL_NAME,
|
|
6
|
+
TASK_GET_TOOL_NAME,
|
|
7
|
+
TASK_UPDATE_TOOL_NAME,
|
|
8
|
+
TASK_LIST_TOOL_NAME,
|
|
9
|
+
} from "wave-agent-sdk";
|
|
4
10
|
import { MessageItem } from "./MessageItem.js";
|
|
5
11
|
|
|
6
12
|
export interface MessageListProps {
|
|
@@ -34,16 +40,43 @@ export const MessageList = React.memo(
|
|
|
34
40
|
const maxExpandedMessages = 20;
|
|
35
41
|
const shouldLimitMessages =
|
|
36
42
|
isExpanded && messages.length > maxExpandedMessages;
|
|
43
|
+
|
|
44
|
+
// Filter out task management tools and empty messages
|
|
45
|
+
const taskMgmtTools = [
|
|
46
|
+
TASK_CREATE_TOOL_NAME,
|
|
47
|
+
TASK_GET_TOOL_NAME,
|
|
48
|
+
TASK_UPDATE_TOOL_NAME,
|
|
49
|
+
TASK_LIST_TOOL_NAME,
|
|
50
|
+
];
|
|
51
|
+
const filteredMessages = messages
|
|
52
|
+
.map((message) => ({
|
|
53
|
+
...message,
|
|
54
|
+
blocks: message.blocks.filter(
|
|
55
|
+
(block) =>
|
|
56
|
+
!(
|
|
57
|
+
block.type === "tool" &&
|
|
58
|
+
typeof block.name === "string" &&
|
|
59
|
+
taskMgmtTools.includes(block.name)
|
|
60
|
+
),
|
|
61
|
+
),
|
|
62
|
+
}))
|
|
63
|
+
.filter((message) => message.blocks.length > 0);
|
|
64
|
+
|
|
37
65
|
const displayMessages = shouldLimitMessages
|
|
38
|
-
?
|
|
39
|
-
:
|
|
40
|
-
const omittedCount = shouldLimitMessages
|
|
41
|
-
? messages.length - maxExpandedMessages
|
|
42
|
-
: 0;
|
|
66
|
+
? filteredMessages.slice(-maxExpandedMessages)
|
|
67
|
+
: filteredMessages;
|
|
43
68
|
|
|
44
69
|
// Compute which messages to render statically vs dynamically
|
|
70
|
+
const lastMessage = displayMessages[displayMessages.length - 1];
|
|
71
|
+
const hasNonEndTool = lastMessage?.blocks.some(
|
|
72
|
+
(block) => block.type === "tool" && block.stage !== "end",
|
|
73
|
+
);
|
|
74
|
+
const hasRunningCommand = lastMessage?.blocks.some(
|
|
75
|
+
(block) => block.type === "command_output" && block.isRunning,
|
|
76
|
+
);
|
|
45
77
|
const shouldRenderLastDynamic =
|
|
46
|
-
!forceStaticLastMessage &&
|
|
78
|
+
!forceStaticLastMessage &&
|
|
79
|
+
(isLoading || isCommandRunning || hasNonEndTool || hasRunningCommand);
|
|
47
80
|
const staticMessages = shouldRenderLastDynamic
|
|
48
81
|
? displayMessages.slice(0, -1)
|
|
49
82
|
: displayMessages;
|
|
@@ -53,17 +86,7 @@ export const MessageList = React.memo(
|
|
|
53
86
|
: [];
|
|
54
87
|
|
|
55
88
|
return (
|
|
56
|
-
<Box flexDirection="column"
|
|
57
|
-
{/* Show omitted message count when limiting */}
|
|
58
|
-
{omittedCount > 0 && (
|
|
59
|
-
<Box>
|
|
60
|
-
<Text color="gray" dimColor>
|
|
61
|
-
... {omittedCount} earlier message{omittedCount !== 1 ? "s" : ""}{" "}
|
|
62
|
-
omitted (showing latest {maxExpandedMessages})
|
|
63
|
-
</Text>
|
|
64
|
-
</Box>
|
|
65
|
-
)}
|
|
66
|
-
|
|
89
|
+
<Box flexDirection="column" paddingBottom={1}>
|
|
67
90
|
{/* Static messages */}
|
|
68
91
|
<Static items={staticMessages}>
|
|
69
92
|
{(message, key) => {
|
|
@@ -143,7 +143,7 @@ export const RewindCommand: React.FC<RewindCommandProps> = ({
|
|
|
143
143
|
<Box>
|
|
144
144
|
<Text color="red" dimColor>
|
|
145
145
|
ā ļø Warning: This will delete all subsequent messages and revert file
|
|
146
|
-
changes.
|
|
146
|
+
and task list changes.
|
|
147
147
|
</Text>
|
|
148
148
|
</Box>
|
|
149
149
|
</Box>
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { useChat } from "../contexts/useChat.js";
|
|
3
|
-
import { Box, Text
|
|
3
|
+
import { Box, Text } from "ink";
|
|
4
4
|
import { useTasks } from "../hooks/useTasks.js";
|
|
5
5
|
|
|
6
6
|
export const TaskList: React.FC = () => {
|
|
7
7
|
const tasks = useTasks();
|
|
8
8
|
const { isTaskListVisible } = useChat();
|
|
9
|
-
const { stdout } = useStdout();
|
|
10
|
-
const terminalWidth = stdout?.columns ?? 80;
|
|
11
|
-
const maxSubjectWidth = Math.max(20, terminalWidth - 10);
|
|
12
9
|
|
|
13
10
|
if (tasks.length === 0 || !isTaskListVisible) {
|
|
14
11
|
return null;
|
|
@@ -20,9 +17,9 @@ export const TaskList: React.FC = () => {
|
|
|
20
17
|
}
|
|
21
18
|
switch (status) {
|
|
22
19
|
case "pending":
|
|
23
|
-
return <Text color="gray"
|
|
20
|
+
return <Text color="gray">ā”</Text>;
|
|
24
21
|
case "in_progress":
|
|
25
|
-
return <Text color="yellow"
|
|
22
|
+
return <Text color="yellow">ā </Text>;
|
|
26
23
|
case "completed":
|
|
27
24
|
return <Text color="green">ā</Text>;
|
|
28
25
|
case "deleted":
|
|
@@ -32,13 +29,6 @@ export const TaskList: React.FC = () => {
|
|
|
32
29
|
}
|
|
33
30
|
};
|
|
34
31
|
|
|
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
32
|
return (
|
|
43
33
|
<Box flexDirection="column">
|
|
44
34
|
{tasks.map((task) => {
|
|
@@ -59,9 +49,7 @@ export const TaskList: React.FC = () => {
|
|
|
59
49
|
return (
|
|
60
50
|
<Box key={task.id} gap={1}>
|
|
61
51
|
{getStatusIcon(task.status, isBlocked)}
|
|
62
|
-
<Text dimColor={isDimmed}>
|
|
63
|
-
{truncate(fullText, maxSubjectWidth)}
|
|
64
|
-
</Text>
|
|
52
|
+
<Text dimColor={isDimmed}>{fullText}</Text>
|
|
65
53
|
</Box>
|
|
66
54
|
);
|
|
67
55
|
})}
|
|
@@ -3,12 +3,12 @@ import { Box, Text } from "ink";
|
|
|
3
3
|
import type { ToolBlock } from "wave-agent-sdk";
|
|
4
4
|
import { DiffDisplay } from "./DiffDisplay.js";
|
|
5
5
|
|
|
6
|
-
interface
|
|
6
|
+
interface ToolDisplayProps {
|
|
7
7
|
block: ToolBlock;
|
|
8
8
|
isExpanded?: boolean;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export const
|
|
11
|
+
export const ToolDisplay: React.FC<ToolDisplayProps> = ({
|
|
12
12
|
block,
|
|
13
13
|
isExpanded = false,
|
|
14
14
|
}) => {
|
|
@@ -25,13 +25,6 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
|
|
|
25
25
|
return "gray"; // Unknown state or no state information
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
const getStatusText = () => {
|
|
29
|
-
if (stage === "running") return "š";
|
|
30
|
-
if (success) return "";
|
|
31
|
-
if (error || success === false) return "ā";
|
|
32
|
-
return ""; // Don't display text for unknown state
|
|
33
|
-
};
|
|
34
|
-
|
|
35
28
|
const hasImages = () => {
|
|
36
29
|
return block.images && block.images.length > 0;
|
|
37
30
|
};
|
|
@@ -44,9 +37,6 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
|
|
|
44
37
|
|
|
45
38
|
const toolName = name ? String(name) : "Tool";
|
|
46
39
|
|
|
47
|
-
const isBackgroundable =
|
|
48
|
-
stage === "running" && (toolName === "Bash" || toolName === "Task");
|
|
49
|
-
|
|
50
40
|
// Get shortResult, if not available show last 5 lines of result
|
|
51
41
|
const getShortResult = () => {
|
|
52
42
|
if (block.shortResult) {
|
|
@@ -70,16 +60,16 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
|
|
|
70
60
|
return (
|
|
71
61
|
<Box flexDirection="column">
|
|
72
62
|
<Box>
|
|
73
|
-
<
|
|
74
|
-
|
|
63
|
+
<Box flexShrink={0}>
|
|
64
|
+
<Text color={getStatusColor()}>ā </Text>
|
|
65
|
+
<Text color="white">{toolName}</Text>
|
|
66
|
+
</Box>
|
|
75
67
|
{/* Display compactParams in collapsed state */}
|
|
76
68
|
{!isExpanded && compactParams && (
|
|
77
69
|
<Text color="gray"> {compactParams}</Text>
|
|
78
70
|
)}
|
|
79
|
-
<Text color={getStatusColor()}> {getStatusText()}</Text>
|
|
80
71
|
{/* Display image indicator */}
|
|
81
72
|
{hasImages() && <Text color="blue"> {getImageIndicator()}</Text>}
|
|
82
|
-
{isBackgroundable && <Text color="gray"> [Ctrl-B] Background</Text>}
|
|
83
73
|
</Box>
|
|
84
74
|
|
|
85
75
|
{/* Display shortResult in collapsed state */}
|
package/src/contexts/useChat.tsx
CHANGED
|
@@ -119,6 +119,13 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
119
119
|
|
|
120
120
|
// Message Display State
|
|
121
121
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
122
|
+
const isExpandedRef = useRef(isExpanded);
|
|
123
|
+
const frozenMessagesRef = useRef<Message[] | null>(null);
|
|
124
|
+
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
isExpandedRef.current = isExpanded;
|
|
127
|
+
}, [isExpanded]);
|
|
128
|
+
|
|
122
129
|
const [isTaskListVisible, setIsTaskListVisible] = useState(true);
|
|
123
130
|
|
|
124
131
|
// AI State
|
|
@@ -220,7 +227,11 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
220
227
|
const initializeAgent = async () => {
|
|
221
228
|
const callbacks: AgentCallbacks = {
|
|
222
229
|
onMessagesChange: (newMessages) => {
|
|
223
|
-
|
|
230
|
+
if (isExpandedRef.current) {
|
|
231
|
+
frozenMessagesRef.current = [...newMessages];
|
|
232
|
+
} else {
|
|
233
|
+
setMessages([...newMessages]);
|
|
234
|
+
}
|
|
224
235
|
},
|
|
225
236
|
onServersChange: (servers) => {
|
|
226
237
|
setMcpServers([...servers]);
|
|
@@ -517,6 +528,10 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
517
528
|
// Clear terminal screen when expanded state changes
|
|
518
529
|
setIsExpanded((prev) => {
|
|
519
530
|
const newExpanded = !prev;
|
|
531
|
+
if (!newExpanded && frozenMessagesRef.current) {
|
|
532
|
+
setMessages(frozenMessagesRef.current);
|
|
533
|
+
frozenMessagesRef.current = null;
|
|
534
|
+
}
|
|
520
535
|
return newExpanded;
|
|
521
536
|
});
|
|
522
537
|
}
|
|
@@ -37,6 +37,7 @@ export const useInputManager = (
|
|
|
37
37
|
useState(false);
|
|
38
38
|
const [showMcpManager, setShowMcpManager] = useState(false);
|
|
39
39
|
const [showRewindManager, setShowRewindManager] = useState(false);
|
|
40
|
+
const [showHelp, setShowHelp] = useState(false);
|
|
40
41
|
const [permissionMode, setPermissionModeState] =
|
|
41
42
|
useState<PermissionMode>("default");
|
|
42
43
|
const [attachedImages, setAttachedImages] = useState<AttachedImage[]>([]);
|
|
@@ -67,6 +68,9 @@ export const useInputManager = (
|
|
|
67
68
|
onRewindManagerStateChange: (show) => {
|
|
68
69
|
setShowRewindManager(show);
|
|
69
70
|
},
|
|
71
|
+
onHelpStateChange: (show) => {
|
|
72
|
+
setShowHelp(show);
|
|
73
|
+
},
|
|
70
74
|
onPermissionModeChange: (mode) => {
|
|
71
75
|
setPermissionModeState(mode);
|
|
72
76
|
callbacks.onPermissionModeChange?.(mode);
|
|
@@ -101,6 +105,9 @@ export const useInputManager = (
|
|
|
101
105
|
onRewindManagerStateChange: (show) => {
|
|
102
106
|
setShowRewindManager(show);
|
|
103
107
|
},
|
|
108
|
+
onHelpStateChange: (show) => {
|
|
109
|
+
setShowHelp(show);
|
|
110
|
+
},
|
|
104
111
|
onPermissionModeChange: (mode) => {
|
|
105
112
|
setPermissionModeState(mode);
|
|
106
113
|
callbacks.onPermissionModeChange?.(mode);
|
|
@@ -150,14 +157,6 @@ export const useInputManager = (
|
|
|
150
157
|
managerRef.current?.moveCursorRight();
|
|
151
158
|
}, []);
|
|
152
159
|
|
|
153
|
-
const moveCursorToStart = useCallback(() => {
|
|
154
|
-
managerRef.current?.moveCursorToStart();
|
|
155
|
-
}, []);
|
|
156
|
-
|
|
157
|
-
const moveCursorToEnd = useCallback(() => {
|
|
158
|
-
managerRef.current?.moveCursorToEnd();
|
|
159
|
-
}, []);
|
|
160
|
-
|
|
161
160
|
// File selector methods
|
|
162
161
|
const activateFileSelector = useCallback((position: number) => {
|
|
163
162
|
managerRef.current?.activateFileSelector(position);
|
|
@@ -268,6 +267,7 @@ export const useInputManager = (
|
|
|
268
267
|
showBackgroundTaskManager,
|
|
269
268
|
showMcpManager,
|
|
270
269
|
showRewindManager,
|
|
270
|
+
showHelp,
|
|
271
271
|
permissionMode,
|
|
272
272
|
attachedImages,
|
|
273
273
|
isManagerReady,
|
|
@@ -278,8 +278,6 @@ export const useInputManager = (
|
|
|
278
278
|
clearInput,
|
|
279
279
|
moveCursorLeft,
|
|
280
280
|
moveCursorRight,
|
|
281
|
-
moveCursorToStart,
|
|
282
|
-
moveCursorToEnd,
|
|
283
281
|
|
|
284
282
|
// File selector
|
|
285
283
|
activateFileSelector,
|
|
@@ -314,6 +312,10 @@ export const useInputManager = (
|
|
|
314
312
|
managerRef.current?.setShowRewindManager(show);
|
|
315
313
|
setShowRewindManager(show);
|
|
316
314
|
}, []),
|
|
315
|
+
setShowHelp: useCallback((show: boolean) => {
|
|
316
|
+
managerRef.current?.setShowHelp(show);
|
|
317
|
+
setShowHelp(show);
|
|
318
|
+
}, []),
|
|
317
319
|
setPermissionMode: useCallback((mode: PermissionMode) => {
|
|
318
320
|
setPermissionModeState(mode);
|
|
319
321
|
managerRef.current?.setPermissionMode(mode);
|
|
@@ -32,6 +32,7 @@ export interface InputManagerCallbacks {
|
|
|
32
32
|
onBackgroundTaskManagerStateChange?: (show: boolean) => void;
|
|
33
33
|
onMcpManagerStateChange?: (show: boolean) => void;
|
|
34
34
|
onRewindManagerStateChange?: (show: boolean) => void;
|
|
35
|
+
onHelpStateChange?: (show: boolean) => void;
|
|
35
36
|
onImagesStateChange?: (images: AttachedImage[]) => void;
|
|
36
37
|
onSendMessage?: (
|
|
37
38
|
content: string,
|
|
@@ -84,6 +85,7 @@ export class InputManager {
|
|
|
84
85
|
private showBackgroundTaskManager: boolean = false;
|
|
85
86
|
private showMcpManager: boolean = false;
|
|
86
87
|
private showRewindManager: boolean = false;
|
|
88
|
+
private showHelp: boolean = false;
|
|
87
89
|
|
|
88
90
|
// Permission mode state
|
|
89
91
|
private permissionMode: PermissionMode = "default";
|
|
@@ -181,14 +183,6 @@ export class InputManager {
|
|
|
181
183
|
this.setCursorPosition(this.cursorPosition + 1);
|
|
182
184
|
}
|
|
183
185
|
|
|
184
|
-
moveCursorToStart(): void {
|
|
185
|
-
this.setCursorPosition(0);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
moveCursorToEnd(): void {
|
|
189
|
-
this.setCursorPosition(this.inputText.length);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
186
|
// File selector methods
|
|
193
187
|
private async searchFiles(query: string): Promise<void> {
|
|
194
188
|
try {
|
|
@@ -357,6 +351,9 @@ export class InputManager {
|
|
|
357
351
|
} else if (command === "rewind") {
|
|
358
352
|
this.setShowRewindManager(true);
|
|
359
353
|
commandExecuted = true;
|
|
354
|
+
} else if (command === "help") {
|
|
355
|
+
this.setShowHelp(true);
|
|
356
|
+
commandExecuted = true;
|
|
360
357
|
}
|
|
361
358
|
}
|
|
362
359
|
})();
|
|
@@ -661,6 +658,15 @@ export class InputManager {
|
|
|
661
658
|
this.callbacks.onRewindManagerStateChange?.(show);
|
|
662
659
|
}
|
|
663
660
|
|
|
661
|
+
getShowHelp(): boolean {
|
|
662
|
+
return this.showHelp;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
setShowHelp(show: boolean): void {
|
|
666
|
+
this.showHelp = show;
|
|
667
|
+
this.callbacks.onHelpStateChange?.(show);
|
|
668
|
+
}
|
|
669
|
+
|
|
664
670
|
// Permission mode methods
|
|
665
671
|
getPermissionMode(): PermissionMode {
|
|
666
672
|
return this.permissionMode;
|
|
@@ -854,16 +860,6 @@ export class InputManager {
|
|
|
854
860
|
return true;
|
|
855
861
|
}
|
|
856
862
|
|
|
857
|
-
if (("home" in key && key.home) || (key.ctrl && input === "a")) {
|
|
858
|
-
this.moveCursorToStart();
|
|
859
|
-
return true;
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
if (("end" in key && key.end) || (key.ctrl && input === "e")) {
|
|
863
|
-
this.moveCursorToEnd();
|
|
864
|
-
return true;
|
|
865
|
-
}
|
|
866
|
-
|
|
867
863
|
// Handle Ctrl+V for pasting images
|
|
868
864
|
if (key.ctrl && input === "v") {
|
|
869
865
|
this.handlePasteImage().catch((error) => {
|
|
@@ -947,14 +943,16 @@ export class InputManager {
|
|
|
947
943
|
this.showHistorySearch ||
|
|
948
944
|
this.showBackgroundTaskManager ||
|
|
949
945
|
this.showMcpManager ||
|
|
950
|
-
this.showRewindManager
|
|
946
|
+
this.showRewindManager ||
|
|
947
|
+
this.showHelp
|
|
951
948
|
) {
|
|
952
949
|
if (
|
|
953
950
|
this.showBackgroundTaskManager ||
|
|
954
951
|
this.showMcpManager ||
|
|
955
|
-
this.showRewindManager
|
|
952
|
+
this.showRewindManager ||
|
|
953
|
+
this.showHelp
|
|
956
954
|
) {
|
|
957
|
-
// Task manager, MCP manager and
|
|
955
|
+
// Task manager, MCP manager, Rewind and Help don't need to handle input, handled by component itself
|
|
958
956
|
// Return true to indicate we've "handled" it (by ignoring it) so it doesn't leak to normal input
|
|
959
957
|
return true;
|
|
960
958
|
}
|
package/src/print-cli.ts
CHANGED
|
@@ -76,42 +76,10 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
|
|
|
76
76
|
process.stdout.write(chunk);
|
|
77
77
|
},
|
|
78
78
|
|
|
79
|
-
// Tool block callback - display tool name when tool starts
|
|
80
|
-
onToolBlockUpdated: (params) => {
|
|
81
|
-
// Print tool name only during 'running' stage (happens once per tool call)
|
|
82
|
-
if (params.stage === "running" && params.name) {
|
|
83
|
-
process.stdout.write(`\nš§ ${params.name}`);
|
|
84
|
-
if (params.compactParams) {
|
|
85
|
-
process.stdout.write(` ${params.compactParams}`);
|
|
86
|
-
}
|
|
87
|
-
process.stdout.write(`\n`);
|
|
88
|
-
}
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
// Subagent block callbacks
|
|
92
|
-
onSubAgentBlockAdded: (subagentId: string, parameters) => {
|
|
93
|
-
// Display subagent creation with indentation
|
|
94
|
-
process.stdout.write(
|
|
95
|
-
`\nš¤ Subagent [${parameters.subagent_type}]: ${parameters.description}\n`,
|
|
96
|
-
);
|
|
97
|
-
},
|
|
98
|
-
onSubAgentBlockUpdated: (subagentId: string, status) => {
|
|
99
|
-
// Display subagent status updates
|
|
100
|
-
const statusIconMap = {
|
|
101
|
-
active: "š",
|
|
102
|
-
completed: "ā
",
|
|
103
|
-
error: "ā",
|
|
104
|
-
aborted: "ā ļø",
|
|
105
|
-
} as const;
|
|
106
|
-
|
|
107
|
-
const statusIcon = statusIconMap[status] ?? "š";
|
|
108
|
-
process.stdout.write(` ${statusIcon} Subagent status: ${status}\n`);
|
|
109
|
-
},
|
|
110
79
|
// Subagent message callbacks
|
|
111
80
|
onSubagentAssistantMessageAdded: (subagentId: string) => {
|
|
112
81
|
subagentReasoningStates.set(subagentId, false);
|
|
113
82
|
subagentContentStates.set(subagentId, false);
|
|
114
|
-
// Subagent assistant message started - add indentation
|
|
115
83
|
process.stdout.write("\n ");
|
|
116
84
|
},
|
|
117
85
|
onSubagentAssistantReasoningUpdated: (
|
|
@@ -132,13 +100,27 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
|
|
|
132
100
|
process.stdout.write("\n š Response: ");
|
|
133
101
|
subagentContentStates.set(subagentId, true);
|
|
134
102
|
}
|
|
135
|
-
// Stream subagent content with indentation - output only the new chunk
|
|
136
103
|
process.stdout.write(chunk);
|
|
137
104
|
},
|
|
138
|
-
onSubagentUserMessageAdded: (
|
|
139
|
-
|
|
105
|
+
onSubagentUserMessageAdded: (
|
|
106
|
+
_subagentId: string,
|
|
107
|
+
params: { content: string },
|
|
108
|
+
) => {
|
|
140
109
|
process.stdout.write(`\n š¤ User: ${params.content}\n`);
|
|
141
110
|
},
|
|
111
|
+
|
|
112
|
+
// Tool block callback - display tool name when tool starts
|
|
113
|
+
onToolBlockUpdated: (params) => {
|
|
114
|
+
// Print tool name only during 'running' stage (happens once per tool call)
|
|
115
|
+
if (params.stage === "running" && params.name) {
|
|
116
|
+
process.stdout.write(`\nš§ ${params.name}`);
|
|
117
|
+
if (params.compactParams) {
|
|
118
|
+
process.stdout.write(` ${params.compactParams}`);
|
|
119
|
+
}
|
|
120
|
+
process.stdout.write(`\n`);
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
|
|
142
124
|
// Error block callback
|
|
143
125
|
onErrorBlockAdded: (error: string) => {
|
|
144
126
|
// Display error blocks with distinct formatting
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { SubagentBlock as SubagentBlockType } from "wave-agent-sdk";
|
|
3
|
-
interface SubagentBlockProps {
|
|
4
|
-
block: SubagentBlockType;
|
|
5
|
-
}
|
|
6
|
-
export declare const SubagentBlock: React.FC<SubagentBlockProps>;
|
|
7
|
-
export {};
|
|
8
|
-
//# sourceMappingURL=SubagentBlock.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SubagentBlock.d.ts","sourceRoot":"","sources":["../../src/components/SubagentBlock.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,aAAa,IAAI,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAIzE,UAAU,kBAAkB;IAC1B,KAAK,EAAE,iBAAiB,CAAC;CAC1B;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA6ItD,CAAC"}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo } from "react";
|
|
3
|
-
import { Box, Text } from "ink";
|
|
4
|
-
import { useChat } from "../contexts/useChat.js";
|
|
5
|
-
import { Markdown } from "./Markdown.js";
|
|
6
|
-
export const SubagentBlock = ({ block }) => {
|
|
7
|
-
const { subagentMessages, subagentLatestTokens } = useChat();
|
|
8
|
-
// Get messages for this subagent from context
|
|
9
|
-
const messages = useMemo(() => subagentMessages[block.subagentId] || [], [subagentMessages, block.subagentId]);
|
|
10
|
-
// Get latest turn tokens for this subagent
|
|
11
|
-
const latestTurnTokens = subagentLatestTokens[block.subagentId] || 0;
|
|
12
|
-
// If the subagent is running in the background, don't show the block
|
|
13
|
-
if (block.runInBackground) {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
// Status indicator mapping
|
|
17
|
-
const getStatusIndicator = (status) => {
|
|
18
|
-
switch (status) {
|
|
19
|
-
case "active":
|
|
20
|
-
return { icon: "š", color: "yellow" };
|
|
21
|
-
case "completed":
|
|
22
|
-
return { icon: "ā
", color: "green" };
|
|
23
|
-
case "error":
|
|
24
|
-
return { icon: "ā", color: "red" };
|
|
25
|
-
case "aborted":
|
|
26
|
-
return { icon: "ā¹ļø", color: "gray" };
|
|
27
|
-
default:
|
|
28
|
-
return { icon: "ā³", color: "gray" };
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
const statusInfo = getStatusIndicator(block.status);
|
|
32
|
-
// Find the last 2 tool names and their compact params, and count total tools
|
|
33
|
-
const getLastTwoTools = () => {
|
|
34
|
-
const tools = [];
|
|
35
|
-
let totalToolCount = 0;
|
|
36
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
37
|
-
const message = messages[i];
|
|
38
|
-
for (let j = message.blocks.length - 1; j >= 0; j--) {
|
|
39
|
-
const messageBlock = message.blocks[j];
|
|
40
|
-
if (messageBlock.type === "tool" && messageBlock.name) {
|
|
41
|
-
totalToolCount++;
|
|
42
|
-
if (tools.length < 2) {
|
|
43
|
-
tools.push({
|
|
44
|
-
name: messageBlock.name,
|
|
45
|
-
compactParams: messageBlock.compactParams,
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return { tools: tools.reverse(), totalToolCount }; // Reverse to show oldest first, newest last
|
|
52
|
-
};
|
|
53
|
-
const { tools: lastTwoTools } = getLastTwoTools();
|
|
54
|
-
// Get the last text message content if completed
|
|
55
|
-
const getLastTextMessage = () => {
|
|
56
|
-
if (block.status !== "completed")
|
|
57
|
-
return null;
|
|
58
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
59
|
-
const message = messages[i];
|
|
60
|
-
if (message.role === "assistant") {
|
|
61
|
-
for (let j = message.blocks.length - 1; j >= 0; j--) {
|
|
62
|
-
const messageBlock = message.blocks[j];
|
|
63
|
-
if (messageBlock.type === "text" && messageBlock.content) {
|
|
64
|
-
return messageBlock.content;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return null;
|
|
70
|
-
};
|
|
71
|
-
const lastTextMessage = getLastTextMessage();
|
|
72
|
-
return (_jsxs(Box, { borderRight: false, borderTop: false, borderBottom: false, borderStyle: "classic", borderColor: "magenta", paddingX: 1, flexDirection: "column", children: [_jsx(Box, { flexDirection: "row", gap: 1, children: _jsxs(Box, { flexDirection: "row", alignItems: "center", children: [_jsxs(Text, { color: "cyan", children: ["\uD83E\uDD16 ", block.subagentName] }), _jsxs(Text, { color: statusInfo.color, dimColor: false, children: [" ", statusInfo.icon] }), _jsxs(Text, { color: "gray", dimColor: true, children: [" ", "(", messages.length, " messages", latestTurnTokens > 0 && (_jsxs(_Fragment, { children: [" | ", _jsx(Text, { color: "blue", bold: true, children: latestTurnTokens.toLocaleString() }), " tokens"] })), ")"] })] }) }), lastTextMessage && (_jsx(Box, { children: _jsx(Markdown, { children: lastTextMessage }) })), block.status !== "completed" && lastTwoTools.length > 0 && (_jsx(Box, { flexDirection: "column", children: lastTwoTools.map((tool, index) => (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: "magenta", children: "\uD83D\uDD27 " }), _jsx(Text, { color: "white", children: tool.name }), tool.compactParams && (_jsxs(Text, { color: "gray", children: [" ", tool.compactParams] }))] }, index))) }))] }));
|
|
73
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { ToolBlock } from "wave-agent-sdk";
|
|
3
|
-
interface ToolResultDisplayProps {
|
|
4
|
-
block: ToolBlock;
|
|
5
|
-
isExpanded?: boolean;
|
|
6
|
-
}
|
|
7
|
-
export declare const ToolResultDisplay: React.FC<ToolResultDisplayProps>;
|
|
8
|
-
export {};
|
|
9
|
-
//# sourceMappingURL=ToolResultDisplay.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ToolResultDisplay.d.ts","sourceRoot":"","sources":["../../src/components/ToolResultDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,UAAU,sBAAsB;IAC9B,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAyI9D,CAAC"}
|