wave-code 1.0.10 → 1.1.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.
- package/bin/wave-code.js +8 -2
- package/dist/bundle/wave.mjs +3207 -0
- package/package.json +24 -25
- package/src/commands/update.ts +2 -7
- package/src/components/App.tsx +3 -7
- package/src/components/BtwDisplay.tsx +10 -1
- package/src/components/ChatInterface.tsx +21 -52
- package/src/components/ConfirmationDetails.tsx +144 -37
- package/src/components/DiffDisplay.tsx +335 -301
- package/src/components/InputBox.tsx +3 -1
- package/src/components/LoadingIndicator.tsx +16 -2
- package/src/components/MessageBlockItem.tsx +2 -4
- package/src/components/MessageList.tsx +75 -14
- package/src/components/ReasoningDisplay.tsx +2 -4
- package/src/components/SessionSelector.tsx +82 -11
- package/src/components/StatusCommand.tsx +2 -9
- package/src/components/ToolDisplay.tsx +2 -4
- package/src/contexts/useChat.tsx +156 -335
- package/src/daemon/commands.ts +57 -27
- package/src/daemon/jsonRpcClient.ts +1 -1
- package/src/daemon/socketClient.ts +2 -2
- package/src/hooks/useInputManager.ts +1 -1
- package/src/index.ts +57 -10
- package/src/managers/inputReducer.ts +186 -104
- package/src/print-cli.ts +21 -17
- package/src/reducers/selectorReducer.ts +10 -0
- package/src/session-selector-cli.tsx +269 -28
- package/src/stdio/agentBridge.ts +22 -21
- package/src/stdio/daemonServer.ts +3 -1
- package/src/utils/clipboard.ts +21 -0
- package/src/utils/highlightUtils.ts +46 -1
- package/src/utils/readPackageJson.ts +29 -0
- package/src/utils/streamingText.ts +11 -0
- package/src/utils/worktree.ts +191 -43
- package/dist/cli.d.ts +0 -6
- package/dist/cli.js +0 -53
- package/dist/commands/plugin/disable.d.ts +0 -5
- package/dist/commands/plugin/disable.js +0 -15
- package/dist/commands/plugin/enable.d.ts +0 -5
- package/dist/commands/plugin/enable.js +0 -15
- package/dist/commands/plugin/install.d.ts +0 -5
- package/dist/commands/plugin/install.js +0 -21
- package/dist/commands/plugin/list.d.ts +0 -1
- package/dist/commands/plugin/list.js +0 -31
- package/dist/commands/plugin/marketplace.d.ts +0 -10
- package/dist/commands/plugin/marketplace.js +0 -90
- package/dist/commands/plugin/uninstall.d.ts +0 -3
- package/dist/commands/plugin/uninstall.js +0 -16
- package/dist/commands/plugin/update.d.ts +0 -3
- package/dist/commands/plugin/update.js +0 -15
- package/dist/commands/update.d.ts +0 -1
- package/dist/commands/update.js +0 -97
- package/dist/components/AgentsManager.d.ts +0 -7
- package/dist/components/AgentsManager.js +0 -109
- package/dist/components/App.d.ts +0 -9
- package/dist/components/App.js +0 -76
- package/dist/components/BackgroundTaskManager.d.ts +0 -5
- package/dist/components/BackgroundTaskManager.js +0 -99
- package/dist/components/BangDisplay.d.ts +0 -8
- package/dist/components/BangDisplay.js +0 -17
- package/dist/components/BtwDisplay.d.ts +0 -7
- package/dist/components/BtwDisplay.js +0 -19
- package/dist/components/ChatInterface.d.ts +0 -2
- package/dist/components/ChatInterface.js +0 -61
- package/dist/components/CommandSelector.d.ts +0 -10
- package/dist/components/CommandSelector.js +0 -66
- package/dist/components/CompactDisplay.d.ts +0 -8
- package/dist/components/CompactDisplay.js +0 -13
- package/dist/components/ConfirmationDetails.d.ts +0 -9
- package/dist/components/ConfirmationDetails.js +0 -45
- package/dist/components/ConfirmationSelector.d.ts +0 -13
- package/dist/components/ConfirmationSelector.js +0 -127
- package/dist/components/DiffDisplay.d.ts +0 -8
- package/dist/components/DiffDisplay.js +0 -201
- package/dist/components/DiscoverView.d.ts +0 -2
- package/dist/components/DiscoverView.js +0 -37
- package/dist/components/FileSelector.d.ts +0 -11
- package/dist/components/FileSelector.js +0 -50
- package/dist/components/HelpView.d.ts +0 -7
- package/dist/components/HelpView.js +0 -74
- package/dist/components/HistorySearch.d.ts +0 -8
- package/dist/components/HistorySearch.js +0 -66
- package/dist/components/InputBox.d.ts +0 -24
- package/dist/components/InputBox.js +0 -149
- package/dist/components/InstalledView.d.ts +0 -2
- package/dist/components/InstalledView.js +0 -45
- package/dist/components/LoadingIndicator.d.ts +0 -10
- package/dist/components/LoadingIndicator.js +0 -6
- package/dist/components/LoginCommand.d.ts +0 -5
- package/dist/components/LoginCommand.js +0 -153
- package/dist/components/Markdown.d.ts +0 -5
- package/dist/components/Markdown.js +0 -127
- package/dist/components/MarketplaceAddForm.d.ts +0 -2
- package/dist/components/MarketplaceAddForm.js +0 -55
- package/dist/components/MarketplaceDetail.d.ts +0 -2
- package/dist/components/MarketplaceDetail.js +0 -74
- package/dist/components/MarketplaceList.d.ts +0 -8
- package/dist/components/MarketplaceList.js +0 -17
- package/dist/components/MarketplaceView.d.ts +0 -2
- package/dist/components/MarketplaceView.js +0 -41
- package/dist/components/McpManager.d.ts +0 -9
- package/dist/components/McpManager.js +0 -88
- package/dist/components/MessageBlockItem.d.ts +0 -8
- package/dist/components/MessageBlockItem.js +0 -15
- package/dist/components/MessageList.d.ts +0 -10
- package/dist/components/MessageList.js +0 -80
- package/dist/components/ModelSelector.d.ts +0 -8
- package/dist/components/ModelSelector.js +0 -45
- package/dist/components/Notifications.d.ts +0 -7
- package/dist/components/Notifications.js +0 -9
- package/dist/components/PlanDisplay.d.ts +0 -7
- package/dist/components/PlanDisplay.js +0 -6
- package/dist/components/PluginDetail.d.ts +0 -2
- package/dist/components/PluginDetail.js +0 -87
- package/dist/components/PluginList.d.ts +0 -13
- package/dist/components/PluginList.js +0 -15
- package/dist/components/PluginManagerShell.d.ts +0 -6
- package/dist/components/PluginManagerShell.js +0 -92
- package/dist/components/PluginManagerTypes.d.ts +0 -35
- package/dist/components/PluginManagerTypes.js +0 -1
- package/dist/components/QueuedMessageList.d.ts +0 -2
- package/dist/components/QueuedMessageList.js +0 -18
- package/dist/components/ReasoningDisplay.d.ts +0 -8
- package/dist/components/ReasoningDisplay.js +0 -13
- package/dist/components/RewindCommand.d.ts +0 -12
- package/dist/components/RewindCommand.js +0 -78
- package/dist/components/SessionSelector.d.ts +0 -12
- package/dist/components/SessionSelector.js +0 -47
- package/dist/components/StatusCommand.d.ts +0 -5
- package/dist/components/StatusCommand.js +0 -28
- package/dist/components/StatusLine.d.ts +0 -6
- package/dist/components/StatusLine.js +0 -9
- package/dist/components/TaskList.d.ts +0 -5
- package/dist/components/TaskList.js +0 -197
- package/dist/components/TaskNotificationMessage.d.ts +0 -5
- package/dist/components/TaskNotificationMessage.js +0 -12
- package/dist/components/ToolDisplay.d.ts +0 -9
- package/dist/components/ToolDisplay.js +0 -55
- package/dist/components/WorkflowManager.d.ts +0 -5
- package/dist/components/WorkflowManager.js +0 -102
- package/dist/components/WorktreeExitPrompt.d.ts +0 -12
- package/dist/components/WorktreeExitPrompt.js +0 -35
- package/dist/constants/commands.d.ts +0 -2
- package/dist/constants/commands.js +0 -92
- package/dist/contexts/PluginManagerContext.d.ts +0 -3
- package/dist/contexts/PluginManagerContext.js +0 -9
- package/dist/contexts/useAppConfig.d.ts +0 -10
- package/dist/contexts/useAppConfig.js +0 -13
- package/dist/contexts/useChat.d.ts +0 -101
- package/dist/contexts/useChat.js +0 -993
- package/dist/contracts/status.d.ts +0 -7
- package/dist/contracts/status.js +0 -1
- package/dist/daemon/commands.d.ts +0 -49
- package/dist/daemon/commands.js +0 -341
- package/dist/daemon/jsonRpcClient.d.ts +0 -38
- package/dist/daemon/jsonRpcClient.js +0 -129
- package/dist/daemon/socketClient.d.ts +0 -13
- package/dist/daemon/socketClient.js +0 -26
- package/dist/daemon-cli.d.ts +0 -10
- package/dist/daemon-cli.js +0 -15
- package/dist/hooks/useInputManager.d.ts +0 -75
- package/dist/hooks/useInputManager.js +0 -583
- package/dist/hooks/usePluginManager.d.ts +0 -4
- package/dist/hooks/usePluginManager.js +0 -265
- package/dist/hooks/useTasks.d.ts +0 -1
- package/dist/hooks/useTasks.js +0 -5
- package/dist/index.d.ts +0 -4
- package/dist/index.js +0 -447
- package/dist/managers/inputHandlers.d.ts +0 -30
- package/dist/managers/inputHandlers.js +0 -625
- package/dist/managers/inputReducer.d.ts +0 -271
- package/dist/managers/inputReducer.js +0 -1121
- package/dist/plugin-manager-cli.d.ts +0 -5
- package/dist/plugin-manager-cli.js +0 -12
- package/dist/print-cli.d.ts +0 -10
- package/dist/print-cli.js +0 -209
- package/dist/reducers/agentsManagerReducer.d.ts +0 -26
- package/dist/reducers/agentsManagerReducer.js +0 -54
- package/dist/reducers/backgroundTaskManagerReducer.d.ts +0 -62
- package/dist/reducers/backgroundTaskManagerReducer.js +0 -106
- package/dist/reducers/confirmationReducer.d.ts +0 -37
- package/dist/reducers/confirmationReducer.js +0 -193
- package/dist/reducers/helpSelectorReducer.d.ts +0 -25
- package/dist/reducers/helpSelectorReducer.js +0 -52
- package/dist/reducers/marketplaceAddFormReducer.d.ts +0 -24
- package/dist/reducers/marketplaceAddFormReducer.js +0 -58
- package/dist/reducers/mcpManagerReducer.d.ts +0 -37
- package/dist/reducers/mcpManagerReducer.js +0 -74
- package/dist/reducers/pluginDetailReducer.d.ts +0 -32
- package/dist/reducers/pluginDetailReducer.js +0 -70
- package/dist/reducers/questionReducer.d.ts +0 -82
- package/dist/reducers/questionReducer.js +0 -375
- package/dist/reducers/rewindSelectorReducer.d.ts +0 -21
- package/dist/reducers/rewindSelectorReducer.js +0 -37
- package/dist/reducers/selectorReducer.d.ts +0 -23
- package/dist/reducers/selectorReducer.js +0 -42
- package/dist/reducers/workflowManagerReducer.d.ts +0 -40
- package/dist/reducers/workflowManagerReducer.js +0 -100
- package/dist/session-selector-cli.d.ts +0 -3
- package/dist/session-selector-cli.js +0 -25
- package/dist/stdio/agentBridge.d.ts +0 -139
- package/dist/stdio/agentBridge.js +0 -999
- package/dist/stdio/daemonServer.d.ts +0 -67
- package/dist/stdio/daemonServer.js +0 -191
- package/dist/stdio/index.d.ts +0 -5
- package/dist/stdio/index.js +0 -5
- package/dist/stdio/jsonRpcConnection.d.ts +0 -39
- package/dist/stdio/jsonRpcConnection.js +0 -135
- package/dist/stdio/protocol.d.ts +0 -41
- package/dist/stdio/protocol.js +0 -26
- package/dist/stdio/stdioServer.d.ts +0 -36
- package/dist/stdio/stdioServer.js +0 -51
- package/dist/stdio-cli.d.ts +0 -8
- package/dist/stdio-cli.js +0 -15
- package/dist/types.d.ts +0 -20
- package/dist/types.js +0 -1
- package/dist/utils/bracketedPaste.d.ts +0 -39
- package/dist/utils/bracketedPaste.js +0 -122
- package/dist/utils/clipboard.d.ts +0 -21
- package/dist/utils/clipboard.js +0 -347
- package/dist/utils/constants.d.ts +0 -16
- package/dist/utils/constants.js +0 -18
- package/dist/utils/highlightUtils.d.ts +0 -1
- package/dist/utils/highlightUtils.js +0 -93
- package/dist/utils/inputUtils.d.ts +0 -17
- package/dist/utils/inputUtils.js +0 -67
- package/dist/utils/logger.d.ts +0 -71
- package/dist/utils/logger.js +0 -259
- package/dist/utils/markdownTable.d.ts +0 -34
- package/dist/utils/markdownTable.js +0 -302
- package/dist/utils/rewindCheckpoints.d.ts +0 -8
- package/dist/utils/rewindCheckpoints.js +0 -17
- package/dist/utils/throttle.d.ts +0 -14
- package/dist/utils/throttle.js +0 -55
- package/dist/utils/toolParameterTransforms.d.ts +0 -18
- package/dist/utils/toolParameterTransforms.js +0 -73
- package/dist/utils/usageSummary.d.ts +0 -28
- package/dist/utils/usageSummary.js +0 -121
- package/dist/utils/version.d.ts +0 -1
- package/dist/utils/version.js +0 -4
- package/dist/utils/worktree.d.ts +0 -35
- package/dist/utils/worktree.js +0 -219
|
@@ -369,7 +369,9 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
369
369
|
showModelSelector ||
|
|
370
370
|
showWorkflowManager || (
|
|
371
371
|
<Box flexDirection="column">
|
|
372
|
-
{escClearPending &&
|
|
372
|
+
{escClearPending && (
|
|
373
|
+
<Text color="gray">Press Esc again to clear input</Text>
|
|
374
|
+
)}
|
|
373
375
|
<Box
|
|
374
376
|
borderStyle="single"
|
|
375
377
|
borderColor="gray"
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
+
import { streamingTail } from "../utils/streamingText.js";
|
|
3
4
|
|
|
4
5
|
export interface LoadingIndicatorProps {
|
|
5
6
|
isLoading?: boolean;
|
|
6
7
|
isCommandRunning?: boolean;
|
|
7
8
|
isCompacting?: boolean;
|
|
8
9
|
latestTotalTokens?: number;
|
|
10
|
+
/** Accumulated streaming text from the compaction fork; its last 30
|
|
11
|
+
* characters render after the compacting hint (same tail style as the
|
|
12
|
+
* main-loop streaming blocks). */
|
|
13
|
+
compactionStream?: string;
|
|
9
14
|
}
|
|
10
15
|
|
|
11
16
|
export const LoadingIndicator = ({
|
|
@@ -13,12 +18,13 @@ export const LoadingIndicator = ({
|
|
|
13
18
|
isCommandRunning = false,
|
|
14
19
|
isCompacting = false,
|
|
15
20
|
latestTotalTokens = 0,
|
|
21
|
+
compactionStream = "",
|
|
16
22
|
}: LoadingIndicatorProps) => {
|
|
17
23
|
return (
|
|
18
24
|
<Box flexDirection="column">
|
|
19
25
|
{isLoading && !isCompacting && (
|
|
20
26
|
<Box>
|
|
21
|
-
<Text color="yellow">✻
|
|
27
|
+
<Text color="yellow">✻ Thinking </Text>
|
|
22
28
|
{latestTotalTokens > 0 && (
|
|
23
29
|
<>
|
|
24
30
|
<Text color="gray" dimColor>
|
|
@@ -47,7 +53,15 @@ export const LoadingIndicator = ({
|
|
|
47
53
|
)}
|
|
48
54
|
{isCommandRunning && <Text color="blue">✻ Command is running...</Text>}
|
|
49
55
|
{isCompacting && (
|
|
50
|
-
<
|
|
56
|
+
<Box>
|
|
57
|
+
<Text color="magenta">✻ Compacting</Text>
|
|
58
|
+
{compactionStream && (
|
|
59
|
+
<Text color="gray" wrap="truncate-end">
|
|
60
|
+
{" "}
|
|
61
|
+
{streamingTail(compactionStream)}
|
|
62
|
+
</Text>
|
|
63
|
+
)}
|
|
64
|
+
</Box>
|
|
51
65
|
)}
|
|
52
66
|
</Box>
|
|
53
67
|
);
|
|
@@ -8,6 +8,7 @@ import { CompactDisplay } from "./CompactDisplay.js";
|
|
|
8
8
|
import { ReasoningDisplay } from "./ReasoningDisplay.js";
|
|
9
9
|
import { Markdown } from "./Markdown.js";
|
|
10
10
|
import { TaskNotificationMessage } from "./TaskNotificationMessage.js";
|
|
11
|
+
import { streamingTail } from "../utils/streamingText.js";
|
|
11
12
|
|
|
12
13
|
export interface MessageBlockItemProps {
|
|
13
14
|
block: MessageBlock;
|
|
@@ -40,10 +41,7 @@ export const MessageBlockItem = ({
|
|
|
40
41
|
</Text>
|
|
41
42
|
) : block.stage === "streaming" ? (
|
|
42
43
|
<Text color="gray" wrap="truncate-end">
|
|
43
|
-
{(
|
|
44
|
-
const flat = block.content.replace(/\n/g, "\\n");
|
|
45
|
-
return flat.length > 30 ? `…${flat.slice(-30)}` : flat;
|
|
46
|
-
})()}
|
|
44
|
+
{streamingTail(block.content)}
|
|
47
45
|
</Text>
|
|
48
46
|
) : (
|
|
49
47
|
<Markdown>{block.content}</Markdown>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { useLayoutEffect, useRef } from "react";
|
|
2
2
|
import os from "os";
|
|
3
|
-
import { Box, Text, Static } from "ink";
|
|
3
|
+
import { Box, Text, Static, useWindowSize } from "ink";
|
|
4
4
|
import type { Message, MessageBlock } from "wave-agent-sdk";
|
|
5
5
|
import { MessageBlockItem } from "./MessageBlockItem.js";
|
|
6
6
|
|
|
@@ -10,22 +10,23 @@ const MAX_MESSAGES_EXPANDED = 10;
|
|
|
10
10
|
export interface MessageListProps {
|
|
11
11
|
messages: Message[];
|
|
12
12
|
isExpanded?: boolean;
|
|
13
|
-
forceStatic?: boolean;
|
|
14
13
|
version?: string;
|
|
15
14
|
workdir?: string;
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
export const MessageList = React.memo(
|
|
19
|
-
({
|
|
20
|
-
messages,
|
|
21
|
-
isExpanded = false,
|
|
22
|
-
forceStatic = false,
|
|
23
|
-
version,
|
|
24
|
-
workdir,
|
|
25
|
-
}: MessageListProps) => {
|
|
18
|
+
({ messages, isExpanded = false, version, workdir }: MessageListProps) => {
|
|
26
19
|
const maxMessages = isExpanded
|
|
27
20
|
? MAX_MESSAGES_EXPANDED
|
|
28
21
|
: MAX_MESSAGES_COLLAPSED;
|
|
22
|
+
// Bound the <Static> history to the terminal width. The static node is
|
|
23
|
+
// absolutely positioned, so without an explicit width Yoga measures it
|
|
24
|
+
// against its content: any row whose natural width exceeds the terminal
|
|
25
|
+
// (e.g. long tool compactParams) widens the node past the viewport, and
|
|
26
|
+
// the node's height stays at the pre-resize measurement while children
|
|
27
|
+
// re-layout at the wider width — leaving a block of blank rows between
|
|
28
|
+
// the last message and the input box on session restore.
|
|
29
|
+
const { columns } = useWindowSize();
|
|
29
30
|
|
|
30
31
|
const welcomeMessage = (
|
|
31
32
|
<Box flexDirection="column" paddingTop={1}>
|
|
@@ -81,7 +82,6 @@ export const MessageList = React.memo(
|
|
|
81
82
|
(item.block.type === "text" || item.block.type === "reasoning") &&
|
|
82
83
|
item.block.stage === "end";
|
|
83
84
|
const isDynamic =
|
|
84
|
-
!forceStatic &&
|
|
85
85
|
!isExpanded &&
|
|
86
86
|
isInLastMessage &&
|
|
87
87
|
!isBlockCompleted &&
|
|
@@ -103,11 +103,72 @@ export const MessageList = React.memo(
|
|
|
103
103
|
...staticBlocks.map((b) => ({ ...b, isWelcome: false })),
|
|
104
104
|
];
|
|
105
105
|
|
|
106
|
+
// Track the content that was written into the append-only <Static> zone for
|
|
107
|
+
// each block. Ink's <Static> never updates an already-rendered item, so when
|
|
108
|
+
// a text/reasoning block reopens (stage "end" -> "streaming") the frozen
|
|
109
|
+
// prefix stays on screen while the dynamic zone would re-render the FULL
|
|
110
|
+
// accumulated content — duplicating the first words. Rendering only the
|
|
111
|
+
// delta (content beyond the frozen prefix) in the dynamic zone avoids the
|
|
112
|
+
// overlap.
|
|
113
|
+
const frozenContentRef = useRef(new Map<string, string>());
|
|
114
|
+
// Mirrors <Static>'s internal index (the previous static items.length) so we
|
|
115
|
+
// know which static items are actually appended to the terminal output in
|
|
116
|
+
// this render pass. Only those items get their content frozen.
|
|
117
|
+
const staticIndexRef = useRef(0);
|
|
118
|
+
|
|
119
|
+
useLayoutEffect(() => {
|
|
120
|
+
staticIndexRef.current = staticItems.length;
|
|
121
|
+
}, [staticItems.length]);
|
|
122
|
+
|
|
123
|
+
// Record the content of static items being appended this pass, and prune
|
|
124
|
+
// keys for blocks that no longer exist (e.g. rewound or cleared messages).
|
|
125
|
+
// Only text/reasoning blocks carry content and can reopen (end -> streaming).
|
|
126
|
+
const currentKeys = new Set<string>();
|
|
127
|
+
staticItems.forEach((item, position) => {
|
|
128
|
+
if (item.isWelcome) return;
|
|
129
|
+
currentKeys.add(item.key);
|
|
130
|
+
if (
|
|
131
|
+
position >= staticIndexRef.current &&
|
|
132
|
+
(item.block!.type === "text" || item.block!.type === "reasoning")
|
|
133
|
+
) {
|
|
134
|
+
frozenContentRef.current.set(item.key, item.block!.content);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
for (const item of dynamicBlocks) {
|
|
138
|
+
currentKeys.add(item.key);
|
|
139
|
+
}
|
|
140
|
+
for (const key of frozenContentRef.current.keys()) {
|
|
141
|
+
if (!currentKeys.has(key)) {
|
|
142
|
+
frozenContentRef.current.delete(key);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Reopened blocks (in the dynamic zone but previously written to static)
|
|
147
|
+
// must render only the content beyond the frozen prefix, otherwise the
|
|
148
|
+
// already-displayed prefix appears twice on screen.
|
|
149
|
+
const dynamicBlocksWithDelta = dynamicBlocks.map((item) => {
|
|
150
|
+
const frozen = frozenContentRef.current.get(item.key);
|
|
151
|
+
if (
|
|
152
|
+
frozen !== undefined &&
|
|
153
|
+
(item.block.type === "text" || item.block.type === "reasoning") &&
|
|
154
|
+
item.block.content.length > frozen.length
|
|
155
|
+
) {
|
|
156
|
+
return {
|
|
157
|
+
...item,
|
|
158
|
+
block: {
|
|
159
|
+
...item.block,
|
|
160
|
+
content: item.block.content.slice(frozen.length),
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return item;
|
|
165
|
+
});
|
|
166
|
+
|
|
106
167
|
return (
|
|
107
168
|
<Box flexDirection="column" paddingBottom={1}>
|
|
108
169
|
{/* Static items (Welcome message + Static blocks) */}
|
|
109
170
|
{staticItems.length > 0 && (
|
|
110
|
-
<Static items={staticItems}>
|
|
171
|
+
<Static items={staticItems} style={{ width: columns }}>
|
|
111
172
|
{(item) => {
|
|
112
173
|
if (item.isWelcome) {
|
|
113
174
|
return (
|
|
@@ -136,9 +197,9 @@ export const MessageList = React.memo(
|
|
|
136
197
|
)}
|
|
137
198
|
|
|
138
199
|
{/* Dynamic blocks */}
|
|
139
|
-
{
|
|
200
|
+
{dynamicBlocksWithDelta.length > 0 && (
|
|
140
201
|
<Box flexDirection="column">
|
|
141
|
-
{
|
|
202
|
+
{dynamicBlocksWithDelta.map((item) => (
|
|
142
203
|
<MessageBlockItem
|
|
143
204
|
key={item.key}
|
|
144
205
|
block={item.block}
|
|
@@ -2,6 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import type { ReasoningBlock } from "wave-agent-sdk";
|
|
4
4
|
import { Markdown } from "./Markdown.js";
|
|
5
|
+
import { streamingTail } from "../utils/streamingText.js";
|
|
5
6
|
|
|
6
7
|
interface ReasoningDisplayProps {
|
|
7
8
|
block: ReasoningBlock;
|
|
@@ -32,10 +33,7 @@ export const ReasoningDisplay: React.FC<ReasoningDisplayProps> = ({
|
|
|
32
33
|
<Text color="white">{content}</Text>
|
|
33
34
|
) : stage === "streaming" ? (
|
|
34
35
|
<Text color="gray" wrap="truncate-end">
|
|
35
|
-
{` ${(
|
|
36
|
-
const flat = content.replace(/\n/g, "\\n");
|
|
37
|
-
return flat.length > 30 ? `…${flat.slice(-30)}` : flat;
|
|
38
|
-
})()}`}
|
|
36
|
+
{` ${streamingTail(content)}`}
|
|
39
37
|
</Text>
|
|
40
38
|
) : (
|
|
41
39
|
<Markdown>{content}</Markdown>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useReducer, useEffect } from "react";
|
|
1
|
+
import React, { useReducer, useEffect, useRef } from "react";
|
|
2
2
|
import { Box, Text, useInput } from "ink";
|
|
3
3
|
import type { SessionMetadata } from "wave-agent-sdk";
|
|
4
4
|
import {
|
|
@@ -12,34 +12,87 @@ export interface SessionSelectorProps {
|
|
|
12
12
|
sessions: SessionItem[];
|
|
13
13
|
onSelect: (sessionId: string) => void;
|
|
14
14
|
onCancel: () => void;
|
|
15
|
+
/**
|
|
16
|
+
* Same-repo worktree paths (from `git worktree list`). The Ctrl+W
|
|
17
|
+
* all-worktrees toggle is only enabled when more than one worktree exists.
|
|
18
|
+
*/
|
|
19
|
+
worktreePaths?: string[];
|
|
20
|
+
/** Show each session's project directory at the end of its row. */
|
|
21
|
+
showProjectPath?: boolean;
|
|
22
|
+
/** Emitted with the new scope when the user toggles all-projects (Ctrl+A). */
|
|
23
|
+
onToggleAllProjects?: (showAllProjects: boolean) => void;
|
|
24
|
+
/** Emitted with the new scope when the user toggles all-worktrees (Ctrl+W). */
|
|
25
|
+
onToggleAllWorktrees?: (showAllWorktrees: boolean) => void;
|
|
15
26
|
}
|
|
16
27
|
|
|
17
28
|
export const SessionSelector: React.FC<SessionSelectorProps> = ({
|
|
18
29
|
sessions,
|
|
19
30
|
onSelect,
|
|
20
31
|
onCancel,
|
|
32
|
+
worktreePaths = [],
|
|
33
|
+
showProjectPath = false,
|
|
34
|
+
onToggleAllProjects,
|
|
35
|
+
onToggleAllWorktrees,
|
|
21
36
|
}) => {
|
|
22
37
|
const [state, dispatch] = useReducer(selectorReducer<SessionItem>, {
|
|
23
38
|
selectedIndex: 0,
|
|
24
39
|
pendingDecision: null,
|
|
25
40
|
items: [],
|
|
41
|
+
showAllProjects: false,
|
|
42
|
+
showAllWorktrees: false,
|
|
26
43
|
} as SelectorState<SessionItem>);
|
|
27
44
|
|
|
28
|
-
const {
|
|
45
|
+
const {
|
|
46
|
+
selectedIndex,
|
|
47
|
+
pendingDecision,
|
|
48
|
+
items,
|
|
49
|
+
showAllProjects,
|
|
50
|
+
showAllWorktrees,
|
|
51
|
+
} = state;
|
|
29
52
|
|
|
30
53
|
// Sync sessions into reducer state
|
|
31
54
|
useEffect(() => {
|
|
32
55
|
dispatch({ type: "SET_ITEMS", items: sessions });
|
|
33
56
|
}, [sessions]);
|
|
34
57
|
|
|
35
|
-
useInput((
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
58
|
+
useInput((input, key) => {
|
|
59
|
+
// Ctrl+A — toggle all-projects scope (only when the parent supports it)
|
|
60
|
+
if (key.ctrl && input.toLowerCase() === "a" && onToggleAllProjects) {
|
|
61
|
+
dispatch({ type: "TOGGLE_ALL_PROJECTS" });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// Ctrl+W — toggle all-worktrees scope (only with multiple worktrees)
|
|
65
|
+
if (
|
|
66
|
+
key.ctrl &&
|
|
67
|
+
input.toLowerCase() === "w" &&
|
|
68
|
+
onToggleAllWorktrees &&
|
|
69
|
+
worktreePaths.length > 1
|
|
70
|
+
) {
|
|
71
|
+
dispatch({ type: "TOGGLE_ALL_WORKTREES" });
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
dispatch({ type: "HANDLE_KEY", key, hasInsert: false });
|
|
41
75
|
});
|
|
42
76
|
|
|
77
|
+
// Report scope toggles to the parent so it can reload the session list.
|
|
78
|
+
// Skip the initial render — the parent already starts in the default scope.
|
|
79
|
+
const projectsFirstRender = useRef(true);
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
if (projectsFirstRender.current) {
|
|
82
|
+
projectsFirstRender.current = false;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
onToggleAllProjects?.(showAllProjects ?? false);
|
|
86
|
+
}, [showAllProjects, onToggleAllProjects]);
|
|
87
|
+
const worktreesFirstRender = useRef(true);
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
if (worktreesFirstRender.current) {
|
|
90
|
+
worktreesFirstRender.current = false;
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
onToggleAllWorktrees?.(showAllWorktrees ?? false);
|
|
94
|
+
}, [showAllWorktrees, onToggleAllWorktrees]);
|
|
95
|
+
|
|
43
96
|
useEffect(() => {
|
|
44
97
|
if (pendingDecision === "select") {
|
|
45
98
|
if (items.length > 0 && selectedIndex < items.length) {
|
|
@@ -82,6 +135,20 @@ export const SessionSelector: React.FC<SessionSelectorProps> = ({
|
|
|
82
135
|
startIndex + MAX_VISIBLE_ITEMS,
|
|
83
136
|
);
|
|
84
137
|
|
|
138
|
+
const hints = [
|
|
139
|
+
onToggleAllProjects
|
|
140
|
+
? `Ctrl+A ${showAllProjects ? "current directory" : "all projects"}`
|
|
141
|
+
: null,
|
|
142
|
+
onToggleAllWorktrees && worktreePaths.length > 1
|
|
143
|
+
? `Ctrl+W ${showAllWorktrees ? "current worktree" : "all worktrees"}`
|
|
144
|
+
: null,
|
|
145
|
+
"↑↓ select",
|
|
146
|
+
"Enter confirm",
|
|
147
|
+
"Esc cancel",
|
|
148
|
+
]
|
|
149
|
+
.filter((hint): hint is string => hint !== null)
|
|
150
|
+
.join(" · ");
|
|
151
|
+
|
|
85
152
|
return (
|
|
86
153
|
<Box
|
|
87
154
|
flexDirection="column"
|
|
@@ -124,8 +191,12 @@ export const SessionSelector: React.FC<SessionSelectorProps> = ({
|
|
|
124
191
|
color={isSelected ? "black" : "white"}
|
|
125
192
|
wrap="truncate-end"
|
|
126
193
|
>
|
|
127
|
-
{session.id} | {lastActiveAt} |
|
|
128
|
-
tokens
|
|
194
|
+
{session.id.slice(0, 8)} | {lastActiveAt} |{" "}
|
|
195
|
+
{session.latestTotalTokens} tokens
|
|
196
|
+
{session.branch ? ` | [${session.branch}]` : ""}
|
|
197
|
+
{showProjectPath && session.workdir
|
|
198
|
+
? ` | ${session.workdir}`
|
|
199
|
+
: ""}
|
|
129
200
|
</Text>
|
|
130
201
|
</Box>
|
|
131
202
|
</Box>
|
|
@@ -150,7 +221,7 @@ export const SessionSelector: React.FC<SessionSelectorProps> = ({
|
|
|
150
221
|
)}
|
|
151
222
|
|
|
152
223
|
<Box>
|
|
153
|
-
<Text dimColor
|
|
224
|
+
<Text dimColor>{hints}</Text>
|
|
154
225
|
</Box>
|
|
155
226
|
</Box>
|
|
156
227
|
);
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Box, Text, useInput } from "ink";
|
|
3
3
|
import { useChat } from "../contexts/useChat.js";
|
|
4
|
-
import
|
|
5
|
-
import path from "path";
|
|
6
|
-
import { fileURLToPath } from "url";
|
|
7
|
-
|
|
8
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
-
const __dirname = path.dirname(__filename);
|
|
4
|
+
import { readNearestPackageJson } from "../utils/readPackageJson.js";
|
|
10
5
|
|
|
11
6
|
export interface StatusCommandProps {
|
|
12
7
|
onCancel: () => void;
|
|
@@ -27,9 +22,7 @@ export const StatusCommand: React.FC<StatusCommandProps> = ({ onCancel }) => {
|
|
|
27
22
|
|
|
28
23
|
let version = "unknown";
|
|
29
24
|
try {
|
|
30
|
-
|
|
31
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
32
|
-
version = pkg.version;
|
|
25
|
+
version = readNearestPackageJson().version;
|
|
33
26
|
} catch {
|
|
34
27
|
// Fallback if package.json cannot be read
|
|
35
28
|
}
|
|
@@ -3,6 +3,7 @@ import { Box, Text } from "ink";
|
|
|
3
3
|
import type { ToolBlock } from "wave-agent-sdk";
|
|
4
4
|
import { getLastLines } from "wave-agent-sdk";
|
|
5
5
|
import { DiffDisplay } from "./DiffDisplay.js";
|
|
6
|
+
import { streamingTail } from "../utils/streamingText.js";
|
|
6
7
|
|
|
7
8
|
interface ToolDisplayProps {
|
|
8
9
|
block: ToolBlock;
|
|
@@ -81,10 +82,7 @@ export const ToolDisplay: React.FC<ToolDisplayProps> = ({
|
|
|
81
82
|
parameters &&
|
|
82
83
|
!compactParams && (
|
|
83
84
|
<Text color="gray" wrap="truncate-end">
|
|
84
|
-
{` ${(
|
|
85
|
-
const flat = parameters.replace(/\n/g, "\\n");
|
|
86
|
-
return flat.length > 30 ? `…${flat.slice(-30)}` : flat;
|
|
87
|
-
})()}`}
|
|
85
|
+
{` ${streamingTail(parameters)}`}
|
|
88
86
|
</Text>
|
|
89
87
|
)}
|
|
90
88
|
{/* Display image indicator */}
|