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
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Text } from "ink";
|
|
3
|
-
const MAX_VISIBLE_ITEMS = 3;
|
|
4
|
-
export const PluginList = ({ plugins, selectedIndex, }) => {
|
|
5
|
-
if (plugins.length === 0) {
|
|
6
|
-
return (_jsx(Box, { padding: 1, children: _jsx(Text, { dimColor: true, children: "No plugins found." }) }));
|
|
7
|
-
}
|
|
8
|
-
const startIndex = Math.max(0, Math.min(selectedIndex - Math.floor(MAX_VISIBLE_ITEMS / 2), Math.max(0, plugins.length - MAX_VISIBLE_ITEMS)));
|
|
9
|
-
const visiblePlugins = plugins.slice(startIndex, startIndex + MAX_VISIBLE_ITEMS);
|
|
10
|
-
return (_jsx(Box, { flexDirection: "column", children: visiblePlugins.map((plugin, index) => {
|
|
11
|
-
const isSelected = index + startIndex === selectedIndex;
|
|
12
|
-
const pluginId = `${plugin.name}@${plugin.marketplace}`;
|
|
13
|
-
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: isSelected ? "cyan" : undefined, children: [isSelected ? "> " : " ", _jsx(Text, { bold: true, children: plugin.name }), _jsxs(Text, { dimColor: true, children: [" @", plugin.marketplace] }), plugin.version && _jsxs(Text, { color: "blue", children: [" v", plugin.version] })] }) }), _jsx(Box, { marginLeft: 4, children: _jsx(Text, { dimColor: true, children: plugin.description }) })] }, pluginId));
|
|
14
|
-
}) }));
|
|
15
|
-
};
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Text, useInput } from "ink";
|
|
3
|
-
import { usePluginManager } from "../hooks/usePluginManager.js";
|
|
4
|
-
import { DiscoverView } from "./DiscoverView.js";
|
|
5
|
-
import { InstalledView } from "./InstalledView.js";
|
|
6
|
-
import { MarketplaceView } from "./MarketplaceView.js";
|
|
7
|
-
import { MarketplaceDetail } from "./MarketplaceDetail.js";
|
|
8
|
-
import { PluginDetail } from "./PluginDetail.js";
|
|
9
|
-
import { MarketplaceAddForm } from "./MarketplaceAddForm.js";
|
|
10
|
-
import { PluginManagerContext } from "../contexts/PluginManagerContext.js";
|
|
11
|
-
export const PluginManagerShell = ({ children, onCancel, onPluginInstalled }) => {
|
|
12
|
-
const pluginManager = usePluginManager({ onPluginInstalled });
|
|
13
|
-
const { state, actions, discoverablePlugins } = pluginManager;
|
|
14
|
-
const setView = (view) => {
|
|
15
|
-
if (view !== "PLUGIN_DETAIL" &&
|
|
16
|
-
view !== "MARKETPLACE_DETAIL" &&
|
|
17
|
-
view !== "ADD_MARKETPLACE") {
|
|
18
|
-
actions.setSelectedId(null);
|
|
19
|
-
}
|
|
20
|
-
actions.setView(view);
|
|
21
|
-
};
|
|
22
|
-
useInput((input, key) => {
|
|
23
|
-
if (key.tab) {
|
|
24
|
-
const views = ["DISCOVER", "INSTALLED", "MARKETPLACES"];
|
|
25
|
-
const currentIndex = views.indexOf(state.currentView === "PLUGIN_DETAIL"
|
|
26
|
-
? discoverablePlugins.find((p) => `${p.name}@${p.marketplace}` === state.selectedId)
|
|
27
|
-
? "DISCOVER"
|
|
28
|
-
: "INSTALLED"
|
|
29
|
-
: state.currentView === "MARKETPLACE_DETAIL" ||
|
|
30
|
-
state.currentView === "ADD_MARKETPLACE"
|
|
31
|
-
? "MARKETPLACES"
|
|
32
|
-
: state.currentView);
|
|
33
|
-
let nextIndex;
|
|
34
|
-
if (key.shift) {
|
|
35
|
-
nextIndex = (currentIndex - 1 + views.length) % views.length;
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
nextIndex = (currentIndex + 1) % views.length;
|
|
39
|
-
}
|
|
40
|
-
setView(views[nextIndex]);
|
|
41
|
-
}
|
|
42
|
-
if (key.escape) {
|
|
43
|
-
if (state.currentView === "PLUGIN_DETAIL") {
|
|
44
|
-
const isFromDiscover = discoverablePlugins.find((p) => `${p.name}@${p.marketplace}` === state.selectedId);
|
|
45
|
-
setView(isFromDiscover ? "DISCOVER" : "INSTALLED");
|
|
46
|
-
}
|
|
47
|
-
else if (state.currentView === "MARKETPLACE_DETAIL" ||
|
|
48
|
-
state.currentView === "ADD_MARKETPLACE") {
|
|
49
|
-
setView("MARKETPLACES");
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
onCancel?.();
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
const renderView = () => {
|
|
57
|
-
if (state.isLoading && !state.selectedId) {
|
|
58
|
-
return (_jsx(Box, { padding: 1, children: _jsx(Text, { color: "yellow", children: "Loading..." }) }));
|
|
59
|
-
}
|
|
60
|
-
switch (state.currentView) {
|
|
61
|
-
case "DISCOVER":
|
|
62
|
-
return _jsx(DiscoverView, {});
|
|
63
|
-
case "INSTALLED":
|
|
64
|
-
return _jsx(InstalledView, {});
|
|
65
|
-
case "MARKETPLACES":
|
|
66
|
-
return _jsx(MarketplaceView, {});
|
|
67
|
-
case "MARKETPLACE_DETAIL":
|
|
68
|
-
return _jsx(MarketplaceDetail, {});
|
|
69
|
-
case "PLUGIN_DETAIL":
|
|
70
|
-
return _jsx(PluginDetail, {});
|
|
71
|
-
case "ADD_MARKETPLACE":
|
|
72
|
-
return _jsx(MarketplaceAddForm, {});
|
|
73
|
-
default:
|
|
74
|
-
return _jsx(DiscoverView, {});
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
return (_jsx(PluginManagerContext.Provider, { value: pluginManager, children: _jsxs(Box, { flexDirection: "column", width: "100%", height: "100%", borderStyle: "round", borderColor: "cyan", children: [_jsxs(Box, { paddingX: 1, borderStyle: "single", borderBottom: true, borderTop: false, borderLeft: false, borderRight: false, children: [_jsx(Box, { marginRight: 2, children: _jsx(Text, { bold: true, color: "cyan", children: "Plugin Manager" }) }), _jsxs(Box, { children: [_jsxs(Text, { color: state.currentView === "DISCOVER" ||
|
|
78
|
-
(state.currentView === "PLUGIN_DETAIL" &&
|
|
79
|
-
!!discoverablePlugins.find((p) => `${p.name}@${p.marketplace}` === state.selectedId))
|
|
80
|
-
? "yellow"
|
|
81
|
-
: undefined, children: [" ", "Discover", " "] }), _jsxs(Text, { color: state.currentView === "INSTALLED" ||
|
|
82
|
-
(state.currentView === "PLUGIN_DETAIL" &&
|
|
83
|
-
!discoverablePlugins.find((p) => `${p.name}@${p.marketplace}` === state.selectedId))
|
|
84
|
-
? "yellow"
|
|
85
|
-
: undefined, children: [" ", "Installed", " "] }), _jsxs(Text, { color: state.currentView === "MARKETPLACES" ||
|
|
86
|
-
state.currentView === "MARKETPLACE_DETAIL" ||
|
|
87
|
-
state.currentView === "ADD_MARKETPLACE"
|
|
88
|
-
? "yellow"
|
|
89
|
-
: undefined, children: [" ", "Marketplaces", " "] })] })] }), _jsxs(Box, { flexGrow: 1, flexDirection: "column", padding: 1, children: [renderView(), children] }), _jsxs(Box, { paddingX: 1, borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, children: [_jsx(Box, { flexGrow: 1, children: _jsx(Text, { dimColor: true, children: state.isLoading
|
|
90
|
-
? "Loading..."
|
|
91
|
-
: "Use Tab to switch views, arrows to navigate, Enter to select, Esc to go back" }) }), state.isLoading && (_jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "yellow", bold: true, children: "\u231B Processing..." }) })), state.successMessage && (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { color: "green", bold: true, children: ["\u2713 ", state.successMessage] }) })), state.error && (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { color: "red", bold: true, children: ["\u2717 Error: ", state.error] }) }))] })] }) }));
|
|
92
|
-
};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { KnownMarketplace, InstalledPlugin, MarketplacePluginEntry } from "wave-agent-sdk";
|
|
2
|
-
export type ViewType = "DISCOVER" | "INSTALLED" | "MARKETPLACES" | "PLUGIN_DETAIL" | "MARKETPLACE_DETAIL" | "ADD_MARKETPLACE";
|
|
3
|
-
export interface PluginManagerState {
|
|
4
|
-
currentView: ViewType;
|
|
5
|
-
selectedId: string | null;
|
|
6
|
-
isLoading: boolean;
|
|
7
|
-
error: string | null;
|
|
8
|
-
successMessage: string | null;
|
|
9
|
-
searchQuery: string;
|
|
10
|
-
}
|
|
11
|
-
export interface PluginManagerContextType {
|
|
12
|
-
state: PluginManagerState;
|
|
13
|
-
marketplaces: KnownMarketplace[];
|
|
14
|
-
installedPlugins: (InstalledPlugin & {
|
|
15
|
-
enabled: boolean;
|
|
16
|
-
})[];
|
|
17
|
-
discoverablePlugins: (MarketplacePluginEntry & {
|
|
18
|
-
marketplace: string;
|
|
19
|
-
installed: boolean;
|
|
20
|
-
version?: string;
|
|
21
|
-
})[];
|
|
22
|
-
actions: {
|
|
23
|
-
setView: (view: ViewType) => void;
|
|
24
|
-
setSelectedId: (id: string | null) => void;
|
|
25
|
-
addMarketplace: (source: string, scope?: "user" | "project" | "local") => Promise<void>;
|
|
26
|
-
removeMarketplace: (name: string, scope?: "user" | "project" | "local") => Promise<void>;
|
|
27
|
-
updateMarketplace: (name: string) => Promise<void>;
|
|
28
|
-
installPlugin: (name: string, marketplace: string, scope?: "user" | "project" | "local") => Promise<void>;
|
|
29
|
-
uninstallPlugin: (name: string, marketplace: string) => Promise<void>;
|
|
30
|
-
updatePlugin: (name: string, marketplace: string) => Promise<void>;
|
|
31
|
-
toggleAutoUpdate: (name: string, enabled: boolean) => Promise<void>;
|
|
32
|
-
refresh: () => Promise<void>;
|
|
33
|
-
clearPluginFeedback: () => void;
|
|
34
|
-
};
|
|
35
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useChat } from "../contexts/useChat.js";
|
|
3
|
-
import { Box, Text } from "ink";
|
|
4
|
-
export const QueuedMessageList = () => {
|
|
5
|
-
const { queuedMessages = [] } = useChat();
|
|
6
|
-
if (queuedMessages.length === 0) {
|
|
7
|
-
return null;
|
|
8
|
-
}
|
|
9
|
-
return (_jsxs(Box, { flexDirection: "column", children: [queuedMessages.map((msg, index) => {
|
|
10
|
-
const content = msg.content.trim();
|
|
11
|
-
const hasImages = msg.images && msg.images.length > 0;
|
|
12
|
-
const prefix = msg.type === "bang" ? "! " : "";
|
|
13
|
-
const displayText = prefix + (content || (hasImages ? "[Images]" : ""));
|
|
14
|
-
return (_jsxs(Box, { children: [_jsxs(Text, { color: "gray", children: ["[", index + 1, "] "] }), _jsx(Text, { color: "gray", italic: true, children: displayText.length > 55
|
|
15
|
-
? `${displayText.substring(0, 52)}...`
|
|
16
|
-
: displayText })] }, msg.id ?? index));
|
|
17
|
-
}), _jsxs(Text, { color: "gray", dimColor: true, children: [" ", "\u2191 recall"] })] }));
|
|
18
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Text } from "ink";
|
|
3
|
-
import { Markdown } from "./Markdown.js";
|
|
4
|
-
export const ReasoningDisplay = ({ block, isExpanded = false, }) => {
|
|
5
|
-
const { content, stage } = block;
|
|
6
|
-
if (!content || !content.trim()) {
|
|
7
|
-
return null;
|
|
8
|
-
}
|
|
9
|
-
return (_jsx(Box, { borderRight: false, borderTop: false, borderBottom: false, borderStyle: "classic", borderColor: "blue", paddingLeft: 1, children: _jsx(Box, { flexDirection: "column", children: isExpanded ? (_jsx(Text, { color: "white", children: content })) : stage === "streaming" ? (_jsx(Text, { color: "gray", wrap: "truncate-end", children: ` ${(() => {
|
|
10
|
-
const flat = content.replace(/\n/g, "\\n");
|
|
11
|
-
return flat.length > 30 ? `…${flat.slice(-30)}` : flat;
|
|
12
|
-
})()}` })) : (_jsx(Markdown, { children: content })) }) }));
|
|
13
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { Message } from "wave-agent-sdk";
|
|
3
|
-
export interface RewindCommandProps {
|
|
4
|
-
messages: Message[];
|
|
5
|
-
onSelect: (index: number) => void;
|
|
6
|
-
onCancel: () => void;
|
|
7
|
-
getFullMessageThread?: () => Promise<{
|
|
8
|
-
messages: Message[];
|
|
9
|
-
sessionIds: string[];
|
|
10
|
-
}>;
|
|
11
|
-
}
|
|
12
|
-
export declare const RewindCommand: React.FC<RewindCommandProps>;
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useReducer, useEffect } from "react";
|
|
3
|
-
import { Box, Text, useInput } from "ink";
|
|
4
|
-
import { getMessageContent } from "wave-agent-sdk";
|
|
5
|
-
import { rewindSelectorReducer } from "../reducers/rewindSelectorReducer.js";
|
|
6
|
-
import { isUserCheckpointMessage } from "../utils/rewindCheckpoints.js";
|
|
7
|
-
export const RewindCommand = ({ messages: initialMessages, onSelect, onCancel, getFullMessageThread, }) => {
|
|
8
|
-
const [messages, setMessages] = useState(initialMessages);
|
|
9
|
-
const [isLoading, setIsLoading] = useState(!!getFullMessageThread);
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
if (getFullMessageThread) {
|
|
12
|
-
getFullMessageThread().then(({ messages: fullMessages }) => {
|
|
13
|
-
setMessages(fullMessages);
|
|
14
|
-
setIsLoading(false);
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
}, [getFullMessageThread]);
|
|
18
|
-
// Filter user messages as checkpoints, excluding meta messages and
|
|
19
|
-
// system-generated user-role messages (task notifications, hook injections).
|
|
20
|
-
// Compaction is append-only: the same message id appears twice on the full
|
|
21
|
-
// thread (pre-compact history + post-compact append), so dedupe by id and
|
|
22
|
-
// keep the last occurrence (matching the folded view the user sees).
|
|
23
|
-
const checkpointMap = new Map();
|
|
24
|
-
messages.forEach((msg, index) => {
|
|
25
|
-
if (!isUserCheckpointMessage(msg))
|
|
26
|
-
return;
|
|
27
|
-
checkpointMap.set(msg.id ?? `index:${index}`, { msg, index });
|
|
28
|
-
});
|
|
29
|
-
const checkpoints = Array.from(checkpointMap.values());
|
|
30
|
-
const MAX_VISIBLE_ITEMS = 3;
|
|
31
|
-
const [state, dispatch] = useReducer(rewindSelectorReducer, {
|
|
32
|
-
selectedIndex: checkpoints.length - 1,
|
|
33
|
-
pendingDecision: null,
|
|
34
|
-
});
|
|
35
|
-
const { selectedIndex, pendingDecision } = state;
|
|
36
|
-
// Update selectedIndex when checkpoints change (after loading full thread)
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
dispatch({ type: "RESET_INDEX", index: checkpoints.length - 1 });
|
|
39
|
-
}, [checkpoints.length]);
|
|
40
|
-
// Handle decisions from reducer
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
if (!pendingDecision)
|
|
43
|
-
return;
|
|
44
|
-
if (pendingDecision === "select") {
|
|
45
|
-
if (checkpoints.length > 0 && selectedIndex >= 0) {
|
|
46
|
-
onSelect(checkpoints[selectedIndex].index);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
else if (pendingDecision === "cancel") {
|
|
50
|
-
onCancel();
|
|
51
|
-
}
|
|
52
|
-
dispatch({ type: "CLEAR_DECISION" });
|
|
53
|
-
}, [pendingDecision, selectedIndex, checkpoints, onSelect, onCancel]);
|
|
54
|
-
useInput((input, key) => {
|
|
55
|
-
dispatch({
|
|
56
|
-
type: "HANDLE_KEY",
|
|
57
|
-
key,
|
|
58
|
-
maxIndex: checkpoints.length - 1,
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
if (isLoading) {
|
|
62
|
-
return (_jsx(Box, { flexDirection: "column", paddingX: 1, borderStyle: "single", borderColor: "cyan", borderLeft: false, borderRight: false, children: _jsx(Text, { color: "cyan", children: "Loading full message thread..." }) }));
|
|
63
|
-
}
|
|
64
|
-
if (checkpoints.length === 0) {
|
|
65
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, borderStyle: "single", borderColor: "yellow", borderLeft: false, borderRight: false, children: [_jsx(Text, { color: "yellow", children: "No user messages found to rewind to." }), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] }));
|
|
66
|
-
}
|
|
67
|
-
// Calculate visible window
|
|
68
|
-
const startIndex = Math.max(0, Math.min(selectedIndex - Math.floor(MAX_VISIBLE_ITEMS / 2), Math.max(0, checkpoints.length - MAX_VISIBLE_ITEMS)));
|
|
69
|
-
const visibleCheckpoints = checkpoints.slice(startIndex, startIndex + MAX_VISIBLE_ITEMS);
|
|
70
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, gap: 1, borderStyle: "single", borderColor: "cyan", borderLeft: false, borderRight: false, children: [_jsx(Box, { children: _jsx(Text, { color: "cyan", bold: true, children: "Rewind: Select a message to revert to" }) }), _jsx(Box, { flexDirection: "column", children: visibleCheckpoints.map((checkpoint, index) => {
|
|
71
|
-
const actualIndex = startIndex + index;
|
|
72
|
-
const isSelected = actualIndex === selectedIndex;
|
|
73
|
-
const content = getMessageContent(checkpoint.msg)
|
|
74
|
-
.replace(/\n/g, "\\n")
|
|
75
|
-
.substring(0, 60);
|
|
76
|
-
return (_jsx(Box, { children: _jsxs(Text, { color: isSelected ? "black" : "white", backgroundColor: isSelected ? "cyan" : undefined, children: [isSelected ? "▶ " : " ", "[", checkpoint.index, "]", " ", content || "(No text content)", actualIndex === checkpoints.length - 1 ? " (Latest)" : ""] }) }, checkpoint.index));
|
|
77
|
-
}) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate \u2022 Enter to rewind \u2022 Esc to cancel" }) }), _jsx(Box, { children: _jsx(Text, { color: "red", dimColor: true, children: "Warning: This will delete all subsequent messages and revert file and task list changes." }) })] }));
|
|
78
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { SessionMetadata } from "wave-agent-sdk";
|
|
3
|
-
type SessionItem = SessionMetadata & {
|
|
4
|
-
firstMessage?: string;
|
|
5
|
-
};
|
|
6
|
-
export interface SessionSelectorProps {
|
|
7
|
-
sessions: SessionItem[];
|
|
8
|
-
onSelect: (sessionId: string) => void;
|
|
9
|
-
onCancel: () => void;
|
|
10
|
-
}
|
|
11
|
-
export declare const SessionSelector: React.FC<SessionSelectorProps>;
|
|
12
|
-
export {};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useReducer, useEffect } from "react";
|
|
3
|
-
import { Box, Text, useInput } from "ink";
|
|
4
|
-
import { selectorReducer, } from "../reducers/selectorReducer.js";
|
|
5
|
-
export const SessionSelector = ({ sessions, onSelect, onCancel, }) => {
|
|
6
|
-
const [state, dispatch] = useReducer((selectorReducer), {
|
|
7
|
-
selectedIndex: 0,
|
|
8
|
-
pendingDecision: null,
|
|
9
|
-
items: [],
|
|
10
|
-
});
|
|
11
|
-
const { selectedIndex, pendingDecision, items } = state;
|
|
12
|
-
// Sync sessions into reducer state
|
|
13
|
-
useEffect(() => {
|
|
14
|
-
dispatch({ type: "SET_ITEMS", items: sessions });
|
|
15
|
-
}, [sessions]);
|
|
16
|
-
useInput((_input, key) => {
|
|
17
|
-
dispatch({
|
|
18
|
-
type: "HANDLE_KEY",
|
|
19
|
-
key,
|
|
20
|
-
hasInsert: false,
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
if (pendingDecision === "select") {
|
|
25
|
-
if (items.length > 0 && selectedIndex < items.length) {
|
|
26
|
-
onSelect(items[selectedIndex].id);
|
|
27
|
-
}
|
|
28
|
-
dispatch({ type: "CLEAR_DECISION" });
|
|
29
|
-
}
|
|
30
|
-
else if (pendingDecision === "cancel") {
|
|
31
|
-
onCancel();
|
|
32
|
-
dispatch({ type: "CLEAR_DECISION" });
|
|
33
|
-
}
|
|
34
|
-
}, [pendingDecision, selectedIndex, items, onSelect, onCancel]);
|
|
35
|
-
if (sessions.length === 0) {
|
|
36
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", borderLeft: false, borderRight: false, paddingX: 1, width: "100%", children: [_jsx(Text, { color: "yellow", children: "No sessions found." }), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] }));
|
|
37
|
-
}
|
|
38
|
-
const MAX_VISIBLE_ITEMS = 3;
|
|
39
|
-
const startIndex = Math.max(0, Math.min(selectedIndex - Math.floor(MAX_VISIBLE_ITEMS / 2), Math.max(0, sessions.length - MAX_VISIBLE_ITEMS)));
|
|
40
|
-
const displaySessions = sessions.slice(startIndex, startIndex + MAX_VISIBLE_ITEMS);
|
|
41
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, gap: 1, borderStyle: "single", borderColor: "cyan", borderLeft: false, borderRight: false, width: "100%", children: [_jsx(Box, { children: _jsx(Text, { color: "cyan", bold: true, children: "Select a session to resume" }) }), _jsx(Box, { flexDirection: "column", children: displaySessions.map((session, index) => {
|
|
42
|
-
const actualIndex = startIndex + index;
|
|
43
|
-
const isSelected = actualIndex === selectedIndex;
|
|
44
|
-
const lastActiveAt = new Date(session.lastActiveAt).toLocaleString();
|
|
45
|
-
return (_jsxs(Box, { flexDirection: "column", width: "100%", children: [_jsxs(Box, { width: "100%", children: [_jsx(Box, { backgroundColor: isSelected ? "cyan" : undefined, flexShrink: 0, children: _jsx(Text, { color: isSelected ? "black" : "white", children: isSelected ? "▶ " : " " }) }), _jsx(Box, { backgroundColor: isSelected ? "cyan" : undefined, flexGrow: 1, children: _jsxs(Text, { color: isSelected ? "black" : "white", wrap: "truncate-end", children: [session.id, " | ", lastActiveAt, " | ", session.latestTotalTokens, " ", "tokens"] }) })] }), isSelected && session.firstMessage && (_jsx(Box, { marginLeft: 2, width: "100%", children: _jsx(Text, { dimColor: true, italic: true, wrap: "truncate-end", children: session.firstMessage.replace(/\n/g, "\\n") }) }))] }, session.id));
|
|
46
|
-
}) }), sessions.length > MAX_VISIBLE_ITEMS && (_jsx(Box, { children: _jsxs(Text, { dimColor: true, children: ["... showing ", displaySessions.length, " of ", sessions.length, " sessions"] }) })), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate \u2022 Enter to select \u2022 Esc to cancel" }) })] }));
|
|
47
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Text, useInput } from "ink";
|
|
3
|
-
import { useChat } from "../contexts/useChat.js";
|
|
4
|
-
import fs from "fs";
|
|
5
|
-
import path from "path";
|
|
6
|
-
import { fileURLToPath } from "url";
|
|
7
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
-
const __dirname = path.dirname(__filename);
|
|
9
|
-
export const StatusCommand = ({ onCancel }) => {
|
|
10
|
-
const { sessionId, workingDirectory, getGatewayConfig, getModelConfig } = useChat();
|
|
11
|
-
useInput((_, key) => {
|
|
12
|
-
if (key.escape) {
|
|
13
|
-
onCancel();
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
const gatewayConfig = getGatewayConfig();
|
|
17
|
-
const modelConfig = getModelConfig();
|
|
18
|
-
let version = "unknown";
|
|
19
|
-
try {
|
|
20
|
-
const pkgPath = path.resolve(__dirname, "../../package.json");
|
|
21
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
22
|
-
version = pkg.version;
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
25
|
-
// Fallback if package.json cannot be read
|
|
26
|
-
}
|
|
27
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", borderLeft: false, borderRight: false, paddingX: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "cyan", bold: true, underline: true, children: "Agent Status" }) }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "Version:" }) }), _jsx(Text, { color: "white", children: version })] }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "Session ID:" }) }), _jsx(Text, { color: "white", children: sessionId })] }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "cwd:" }) }), _jsx(Text, { color: "white", wrap: "wrap", children: workingDirectory })] }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "Wave base URL:" }) }), _jsx(Text, { color: "white", children: gatewayConfig.baseURL })] }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "Model:" }) }), _jsx(Text, { color: "white", children: modelConfig.model })] }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "Fast model:" }) }), _jsx(Text, { color: "white", children: modelConfig.fastModel })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Esc to cancel" }) })] }));
|
|
28
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Text } from "ink";
|
|
3
|
-
export const StatusLine = ({ permissionMode, isShellCommand, }) => {
|
|
4
|
-
return (_jsx(Box, { children: isShellCommand ? (_jsxs(Text, { color: "gray", children: ["Shell: ", _jsx(Text, { color: "yellow", children: "Run shell command" })] })) : (_jsxs(Text, { color: "gray", children: ["Mode:", " ", _jsx(Text, { color: permissionMode === "plan"
|
|
5
|
-
? "yellow"
|
|
6
|
-
: permissionMode === "bypassPermissions"
|
|
7
|
-
? "red"
|
|
8
|
-
: "cyan", bold: permissionMode === "bypassPermissions", children: permissionMode }), " ", "(Shift+Tab to cycle)"] })) }));
|
|
9
|
-
};
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { Task, TaskStatus } from "wave-agent-sdk";
|
|
3
|
-
export declare const getStatusIcon: (status: TaskStatus) => React.ReactNode;
|
|
4
|
-
export declare function sortTasksByPriority(tasks: Task[], completionTimestamps: Map<string, number>, now: number, needsTruncation: boolean): Task[];
|
|
5
|
-
export declare const TaskList: React.FC;
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import { useChat } from "../contexts/useChat.js";
|
|
4
|
-
import { Box, Text, useStdout } from "ink";
|
|
5
|
-
import { useTasks } from "../hooks/useTasks.js";
|
|
6
|
-
const RECENTLY_COMPLETED_TTL_MS = 30000;
|
|
7
|
-
const AUTO_HIDE_DELAY_MS = 5000;
|
|
8
|
-
export const getStatusIcon = (status) => {
|
|
9
|
-
switch (status) {
|
|
10
|
-
case "pending":
|
|
11
|
-
return _jsx(Text, { color: "gray", children: "\u25A1" });
|
|
12
|
-
case "in_progress":
|
|
13
|
-
return _jsx(Text, { color: "yellow", children: "\u25A0" });
|
|
14
|
-
case "completed":
|
|
15
|
-
return _jsx(Text, { color: "green", children: "\u2713" });
|
|
16
|
-
case "deleted":
|
|
17
|
-
return _jsx(Text, { color: "red", children: "\u2715" });
|
|
18
|
-
default:
|
|
19
|
-
return _jsx(Text, { color: "gray", children: "?" });
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
function byIdAsc(a, b) {
|
|
23
|
-
const aNum = parseInt(a.id, 10);
|
|
24
|
-
const bNum = parseInt(b.id, 10);
|
|
25
|
-
if (!isNaN(aNum) && !isNaN(bNum)) {
|
|
26
|
-
return aNum - bNum;
|
|
27
|
-
}
|
|
28
|
-
return a.id.localeCompare(b.id);
|
|
29
|
-
}
|
|
30
|
-
export function sortTasksByPriority(tasks, completionTimestamps, now, needsTruncation) {
|
|
31
|
-
if (!needsTruncation) {
|
|
32
|
-
// No truncation needed — sort by ID for stable ordering
|
|
33
|
-
return [...tasks].sort(byIdAsc);
|
|
34
|
-
}
|
|
35
|
-
// When truncation is needed, prioritize:
|
|
36
|
-
// recently completed > in_progress > pending (unblocked first) > older completed > deleted
|
|
37
|
-
const recentCompleted = [];
|
|
38
|
-
const olderCompleted = [];
|
|
39
|
-
for (const task of tasks.filter((t) => t.status === "completed")) {
|
|
40
|
-
const ts = completionTimestamps.get(task.id);
|
|
41
|
-
if (ts && now - ts < RECENTLY_COMPLETED_TTL_MS) {
|
|
42
|
-
recentCompleted.push(task);
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
olderCompleted.push(task);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
recentCompleted.sort(byIdAsc);
|
|
49
|
-
olderCompleted.sort(byIdAsc);
|
|
50
|
-
const inProgress = tasks
|
|
51
|
-
.filter((t) => t.status === "in_progress")
|
|
52
|
-
.sort(byIdAsc);
|
|
53
|
-
const unresolvedTaskIds = new Set(tasks.filter((t) => t.status !== "completed").map((t) => t.id));
|
|
54
|
-
const pending = tasks
|
|
55
|
-
.filter((t) => t.status === "pending")
|
|
56
|
-
.sort((a, b) => {
|
|
57
|
-
const aBlocked = a.blockedBy.some((id) => unresolvedTaskIds.has(id));
|
|
58
|
-
const bBlocked = b.blockedBy.some((id) => unresolvedTaskIds.has(id));
|
|
59
|
-
if (aBlocked !== bBlocked)
|
|
60
|
-
return aBlocked ? 1 : -1;
|
|
61
|
-
return byIdAsc(a, b);
|
|
62
|
-
});
|
|
63
|
-
const deleted = tasks.filter((t) => t.status === "deleted").sort(byIdAsc);
|
|
64
|
-
return [
|
|
65
|
-
...recentCompleted,
|
|
66
|
-
...inProgress,
|
|
67
|
-
...pending,
|
|
68
|
-
...olderCompleted,
|
|
69
|
-
...deleted,
|
|
70
|
-
];
|
|
71
|
-
}
|
|
72
|
-
function getDisplayLimit(rows) {
|
|
73
|
-
const available = rows ?? 24;
|
|
74
|
-
return available <= 10 ? 0 : Math.min(10, Math.max(3, available - 14));
|
|
75
|
-
}
|
|
76
|
-
export const TaskList = () => {
|
|
77
|
-
const tasks = useTasks();
|
|
78
|
-
const { isTaskListVisible, isBtwActive } = useChat();
|
|
79
|
-
const { stdout } = useStdout();
|
|
80
|
-
const completionTimestampsRef = React.useRef(new Map());
|
|
81
|
-
const previousCompletedIdsRef = React.useRef(null);
|
|
82
|
-
const autoHideTimerRef = React.useRef(null);
|
|
83
|
-
const [autoHidden, setAutoHidden] = React.useState(false);
|
|
84
|
-
// 是否在当前展示期间观察到过未完成任务;用于区分“任务在眼前完成”与“加载时已全部完成”
|
|
85
|
-
const hadIncompleteRef = React.useRef(false);
|
|
86
|
-
const [, forceUpdate] = React.useState(0);
|
|
87
|
-
const now = Date.now();
|
|
88
|
-
const activeTasks = tasks.filter((t) => t.status !== "deleted");
|
|
89
|
-
// Track completion timestamps: only set when a task newly transitions to completed
|
|
90
|
-
if (previousCompletedIdsRef.current === null) {
|
|
91
|
-
previousCompletedIdsRef.current = new Set(tasks.filter((t) => t.status === "completed").map((t) => t.id));
|
|
92
|
-
}
|
|
93
|
-
const currentCompletedIds = new Set(tasks.filter((t) => t.status === "completed").map((t) => t.id));
|
|
94
|
-
for (const id of currentCompletedIds) {
|
|
95
|
-
if (!previousCompletedIdsRef.current.has(id)) {
|
|
96
|
-
completionTimestampsRef.current.set(id, now);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
for (const id of completionTimestampsRef.current.keys()) {
|
|
100
|
-
if (!currentCompletedIds.has(id)) {
|
|
101
|
-
completionTimestampsRef.current.delete(id);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
previousCompletedIdsRef.current = currentCompletedIds;
|
|
105
|
-
// Schedule re-render when the next recent completion expires
|
|
106
|
-
React.useEffect(() => {
|
|
107
|
-
if (completionTimestampsRef.current.size === 0)
|
|
108
|
-
return;
|
|
109
|
-
const currentNow = Date.now();
|
|
110
|
-
let earliestExpiry = Infinity;
|
|
111
|
-
for (const ts of completionTimestampsRef.current.values()) {
|
|
112
|
-
const expiry = ts + RECENTLY_COMPLETED_TTL_MS;
|
|
113
|
-
if (expiry > currentNow && expiry < earliestExpiry) {
|
|
114
|
-
earliestExpiry = expiry;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
if (earliestExpiry === Infinity)
|
|
118
|
-
return;
|
|
119
|
-
const timer = setTimeout(() => forceUpdate((n) => n + 1), earliestExpiry - currentNow);
|
|
120
|
-
return () => clearTimeout(timer);
|
|
121
|
-
}, [tasks]);
|
|
122
|
-
// Auto-hide logic: when all active tasks are completed
|
|
123
|
-
const allCompleted = activeTasks.length > 0 &&
|
|
124
|
-
activeTasks.every((t) => t.status === "completed");
|
|
125
|
-
// 观察到任务从“存在未完成”变为“全部完成”时保留 5 秒再隐藏;
|
|
126
|
-
// 加载或恢复到已全部完成的会话时立即隐藏,避免先闪现再消失
|
|
127
|
-
React.useEffect(() => {
|
|
128
|
-
if (activeTasks.length === 0) {
|
|
129
|
-
hadIncompleteRef.current = false;
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
if (!allCompleted) {
|
|
133
|
-
hadIncompleteRef.current = true;
|
|
134
|
-
if (autoHidden) {
|
|
135
|
-
setAutoHidden(false);
|
|
136
|
-
}
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
if (!hadIncompleteRef.current) {
|
|
140
|
-
if (!autoHidden) {
|
|
141
|
-
setAutoHidden(true);
|
|
142
|
-
}
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
if (!autoHidden) {
|
|
146
|
-
autoHideTimerRef.current = setTimeout(() => {
|
|
147
|
-
setAutoHidden(true);
|
|
148
|
-
}, AUTO_HIDE_DELAY_MS);
|
|
149
|
-
}
|
|
150
|
-
return () => {
|
|
151
|
-
if (autoHideTimerRef.current) {
|
|
152
|
-
clearTimeout(autoHideTimerRef.current);
|
|
153
|
-
autoHideTimerRef.current = null;
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
}, [allCompleted, autoHidden, activeTasks.length]);
|
|
157
|
-
if (tasks.length === 0 ||
|
|
158
|
-
!isTaskListVisible ||
|
|
159
|
-
isBtwActive ||
|
|
160
|
-
autoHidden ||
|
|
161
|
-
(allCompleted && !hadIncompleteRef.current)) {
|
|
162
|
-
return null;
|
|
163
|
-
}
|
|
164
|
-
const displayLimit = getDisplayLimit(stdout?.rows);
|
|
165
|
-
const needsTruncation = tasks.length > displayLimit;
|
|
166
|
-
const sorted = sortTasksByPriority(tasks, completionTimestampsRef.current, now, needsTruncation);
|
|
167
|
-
const displayed = displayLimit > 0 ? sorted.slice(0, displayLimit) : [];
|
|
168
|
-
const hidden = displayLimit > 0 ? sorted.slice(displayLimit) : sorted;
|
|
169
|
-
const doneCount = tasks.filter((t) => t.status === "completed").length;
|
|
170
|
-
const inProgressCount = tasks.filter((t) => t.status === "in_progress").length;
|
|
171
|
-
const openCount = tasks.filter((t) => t.status === "pending").length;
|
|
172
|
-
// Summary parts for hidden tasks
|
|
173
|
-
const hiddenInProgress = hidden.filter((t) => t.status === "in_progress").length;
|
|
174
|
-
const hiddenPending = hidden.filter((t) => t.status === "pending").length;
|
|
175
|
-
const hiddenCompleted = hidden.filter((t) => t.status === "completed").length;
|
|
176
|
-
const summaryParts = [];
|
|
177
|
-
if (hiddenInProgress > 0)
|
|
178
|
-
summaryParts.push(`${hiddenInProgress} in progress`);
|
|
179
|
-
if (hiddenPending > 0)
|
|
180
|
-
summaryParts.push(`${hiddenPending} pending`);
|
|
181
|
-
if (hiddenCompleted > 0)
|
|
182
|
-
summaryParts.push(`${hiddenCompleted} completed`);
|
|
183
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: [tasks.length, " tasks (", doneCount, " done, ", inProgressCount, " in progress,", " ", openCount, " open)"] }), displayed.map((task) => {
|
|
184
|
-
const isDimmed = task.status === "completed" || task.status === "deleted";
|
|
185
|
-
const unresolvedTaskIds = new Set(tasks.filter((t) => t.status !== "completed").map((t) => t.id));
|
|
186
|
-
const isBlocked = task.blockedBy &&
|
|
187
|
-
task.blockedBy.some((id) => unresolvedTaskIds.has(id));
|
|
188
|
-
const blockingTaskIds = isBlocked
|
|
189
|
-
? task.blockedBy.map((id) => `#${id}`)
|
|
190
|
-
: [];
|
|
191
|
-
const blockedByText = isBlocked && blockingTaskIds.length > 0
|
|
192
|
-
? ` (Blocked by: ${blockingTaskIds.join(", ")})`
|
|
193
|
-
: "";
|
|
194
|
-
const fullText = `${task.subject}${blockedByText}`;
|
|
195
|
-
return (_jsxs(Box, { gap: 1, children: [getStatusIcon(task.status), _jsx(Text, { dimColor: isDimmed, wrap: "truncate-end", children: fullText })] }, task.id));
|
|
196
|
-
}), displayLimit > 0 && hidden.length > 0 && (_jsxs(Text, { dimColor: true, children: [" \u2026 +", summaryParts.join(", ")] }))] }));
|
|
197
|
-
};
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { TaskNotificationBlock } from "wave-agent-sdk";
|
|
2
|
-
export interface TaskNotificationMessageProps {
|
|
3
|
-
block: TaskNotificationBlock;
|
|
4
|
-
}
|
|
5
|
-
export declare const TaskNotificationMessage: ({ block, }: TaskNotificationMessageProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Text } from "ink";
|
|
3
|
-
const statusColor = {
|
|
4
|
-
completed: "green",
|
|
5
|
-
failed: "red",
|
|
6
|
-
killed: "yellow",
|
|
7
|
-
aborted: "gray",
|
|
8
|
-
};
|
|
9
|
-
export const TaskNotificationMessage = ({ block, }) => {
|
|
10
|
-
const color = statusColor[block.status];
|
|
11
|
-
return (_jsx(Box, { flexDirection: "column", children: _jsxs(Box, { children: [_jsx(Text, { color: color, children: "\u25C6 " }), _jsx(Text, { color: "white", children: block.summary })] }) }));
|
|
12
|
-
};
|