wave-code 1.0.9 → 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 +172 -350
- 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/stdio/jsonRpcConnection.ts +19 -1
- package/src/stdio/stdioServer.ts +17 -0
- 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 -992
- 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 -30
- package/dist/stdio/jsonRpcConnection.js +0 -127
- package/dist/stdio/protocol.d.ts +0 -41
- package/dist/stdio/protocol.js +0 -26
- package/dist/stdio/stdioServer.d.ts +0 -28
- package/dist/stdio/stdioServer.js +0 -36
- 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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wave-code",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "CLI-based code assistant powered by AI, built with React and Ink",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -15,8 +15,7 @@
|
|
|
15
15
|
"ink",
|
|
16
16
|
"typescript"
|
|
17
17
|
],
|
|
18
|
-
"main": "dist/
|
|
19
|
-
"types": "dist/index.d.ts",
|
|
18
|
+
"main": "dist/bundle/wave.mjs",
|
|
20
19
|
"type": "module",
|
|
21
20
|
"bin": {
|
|
22
21
|
"wave-code": "bin/wave-code.js",
|
|
@@ -29,49 +28,49 @@
|
|
|
29
28
|
"README.md"
|
|
30
29
|
],
|
|
31
30
|
"dependencies": {
|
|
31
|
+
"@vscode/ripgrep": "^1.18.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/react": "^19.1.8",
|
|
35
|
+
"@types/semver": "^7.7.1",
|
|
36
|
+
"@types/yargs": "^17.0.0",
|
|
37
|
+
"@vitest/coverage-v8": "^4.1.7",
|
|
32
38
|
"chalk": "^5.6.2",
|
|
33
39
|
"diff": "^8.0.2",
|
|
40
|
+
"esbuild": "^0.28.1",
|
|
41
|
+
"eslint-plugin-react": "^7.37.5",
|
|
42
|
+
"eslint-plugin-react-hooks": "^5.2.0",
|
|
34
43
|
"glob": "^13.0.0",
|
|
35
44
|
"highlight.js": "^11.11.1",
|
|
36
|
-
"ink": "^
|
|
45
|
+
"ink": "^7.1.1",
|
|
46
|
+
"ink-testing-library": "^4.0.0",
|
|
37
47
|
"marked": "^17.0.2",
|
|
38
48
|
"node-html-parser": "^7.0.2",
|
|
39
49
|
"react": "^19.2.4",
|
|
40
50
|
"react-dom": "19.2.4",
|
|
51
|
+
"rimraf": "^6.1.2",
|
|
41
52
|
"semver": "^7.7.4",
|
|
42
53
|
"string-width": "^8.2.2",
|
|
54
|
+
"tsx": "^4.20.4",
|
|
55
|
+
"vitest": "^4.1.7",
|
|
43
56
|
"wrap-ansi": "^10.0.0",
|
|
44
57
|
"yargs": "^17.7.2",
|
|
45
58
|
"zod": "^3.23.8",
|
|
46
|
-
"wave-agent-sdk": "1.0
|
|
47
|
-
},
|
|
48
|
-
"devDependencies": {
|
|
49
|
-
"@types/react": "^19.1.8",
|
|
50
|
-
"@types/semver": "^7.7.1",
|
|
51
|
-
"@types/yargs": "^17.0.0",
|
|
52
|
-
"@vitest/coverage-v8": "^4.1.7",
|
|
53
|
-
"eslint-plugin-react": "^7.37.5",
|
|
54
|
-
"eslint-plugin-react-hooks": "^5.2.0",
|
|
55
|
-
"ink-testing-library": "^4.0.0",
|
|
56
|
-
"rimraf": "^6.1.2",
|
|
57
|
-
"tsc-alias": "^1.8.16",
|
|
58
|
-
"tsx": "^4.20.4",
|
|
59
|
-
"vitest": "^4.1.7"
|
|
60
|
-
},
|
|
61
|
-
"peerDependencies": {
|
|
62
|
-
"react": ">=18.0.0"
|
|
59
|
+
"wave-agent-sdk": "1.1.0"
|
|
63
60
|
},
|
|
64
61
|
"engines": {
|
|
65
|
-
"node": ">=
|
|
62
|
+
"node": ">=22"
|
|
66
63
|
},
|
|
67
64
|
"license": "MIT",
|
|
68
65
|
"scripts": {
|
|
69
|
-
"wave": "
|
|
70
|
-
"build": "rimraf dist &&
|
|
66
|
+
"wave": "tsx --tsconfig tsconfig.dev.json src/index.ts",
|
|
67
|
+
"build": "rimraf dist && node scripts/bundle.mjs",
|
|
71
68
|
"type-check": "tsc --noEmit --incremental",
|
|
72
|
-
"watch": "tsc -p tsconfig.build.json --watch & tsc-alias -p tsconfig.build.json --watch",
|
|
73
69
|
"test": "vitest run --reporter=dot",
|
|
74
70
|
"test:coverage": "vitest run --coverage --reporter=dot",
|
|
71
|
+
"test:unit": "vitest run --reporter=dot --exclude 'tests/integration/**' --exclude '**/*.integration.test.ts'",
|
|
72
|
+
"test:unit:coverage": "vitest run --coverage --reporter=dot --exclude 'tests/integration/**' --exclude '**/*.integration.test.ts'",
|
|
73
|
+
"test:integration": "vitest run --reporter=dot tests/integration .integration.test",
|
|
75
74
|
"lint": "eslint --cache",
|
|
76
75
|
"format": "prettier --write ."
|
|
77
76
|
}
|
package/src/commands/update.ts
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import { spawnSync } from "child_process";
|
|
2
|
-
import { readFileSync } from "fs";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import { fileURLToPath } from "url";
|
|
5
2
|
import https from "https";
|
|
6
3
|
import chalk from "chalk";
|
|
7
4
|
import { isUpdateAvailable } from "../utils/version.js";
|
|
5
|
+
import { readNearestPackageJson } from "../utils/readPackageJson.js";
|
|
8
6
|
|
|
9
|
-
const
|
|
10
|
-
const packageJsonPath = path.resolve(__dirname, "../../package.json");
|
|
11
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
12
|
-
const currentVersion = packageJson.version;
|
|
7
|
+
const currentVersion = readNearestPackageJson().version;
|
|
13
8
|
|
|
14
9
|
async function getLatestVersion(): Promise<string> {
|
|
15
10
|
return new Promise((resolve, reject) => {
|
package/src/components/App.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useState, useEffect, useCallback } from "react";
|
|
2
2
|
import { useInput } from "ink";
|
|
3
3
|
import { ChatInterface } from "./ChatInterface.js";
|
|
4
|
-
import { ChatProvider
|
|
4
|
+
import { ChatProvider } from "../contexts/useChat.js";
|
|
5
5
|
import { AppProvider } from "../contexts/useAppConfig.js";
|
|
6
6
|
import { WorktreeExitPrompt } from "./WorktreeExitPrompt.js";
|
|
7
7
|
import {
|
|
@@ -22,12 +22,11 @@ interface AppWithProvidersProps extends BaseAppProps {
|
|
|
22
22
|
onExit: (shouldRemove: boolean) => void;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
/** Wraps ChatInterface with worktree exit handling
|
|
25
|
+
/** Wraps ChatInterface with worktree exit handling. */
|
|
26
26
|
const ChatWithExitPrompt: React.FC<{
|
|
27
27
|
worktreeSession: NonNullable<BaseAppProps["worktreeSession"]>;
|
|
28
28
|
onExit: (shouldRemove: boolean) => void;
|
|
29
29
|
}> = ({ worktreeSession, onExit }) => {
|
|
30
|
-
const { triggerWorktreeRemoveHook } = useChat();
|
|
31
30
|
const [isExiting, setIsExiting] = useState(false);
|
|
32
31
|
const [worktreeStatus, setWorktreeStatus] = useState<{
|
|
33
32
|
hasUncommittedChanges: boolean;
|
|
@@ -80,10 +79,7 @@ const ChatWithExitPrompt: React.FC<{
|
|
|
80
79
|
hasUncommittedChanges={worktreeStatus.hasUncommittedChanges}
|
|
81
80
|
hasNewCommits={worktreeStatus.hasNewCommits}
|
|
82
81
|
onKeep={() => onExit(false)}
|
|
83
|
-
onRemove={
|
|
84
|
-
await triggerWorktreeRemoveHook(worktreeSession.path);
|
|
85
|
-
onExit(true);
|
|
86
|
-
}}
|
|
82
|
+
onRemove={() => onExit(true)}
|
|
87
83
|
onCancel={() => setIsExiting(false)}
|
|
88
84
|
/>
|
|
89
85
|
);
|
|
@@ -2,6 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { Markdown } from "./Markdown.js";
|
|
4
4
|
import { BtwState } from "../managers/inputReducer.js";
|
|
5
|
+
import { streamingTail } from "../utils/streamingText.js";
|
|
5
6
|
|
|
6
7
|
interface BtwDisplayProps {
|
|
7
8
|
btwState: BtwState;
|
|
@@ -36,7 +37,15 @@ export const BtwDisplay: React.FC<BtwDisplayProps> = ({ btwState }) => {
|
|
|
36
37
|
)}
|
|
37
38
|
<Box marginTop={1} flexDirection="column">
|
|
38
39
|
{btwState.isLoading ? (
|
|
39
|
-
<
|
|
40
|
+
<Box>
|
|
41
|
+
<Text color="gray">✻ Answering</Text>
|
|
42
|
+
{btwState.answer && (
|
|
43
|
+
<Text color="gray" wrap="truncate-end">
|
|
44
|
+
{" "}
|
|
45
|
+
{streamingTail(btwState.answer)}
|
|
46
|
+
</Text>
|
|
47
|
+
)}
|
|
48
|
+
</Box>
|
|
40
49
|
) : isError ? (
|
|
41
50
|
<Text color="error">{answer}</Text>
|
|
42
51
|
) : (
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import React, { useState,
|
|
2
|
-
import { Box,
|
|
3
|
-
import type { DOMElement } from "ink";
|
|
1
|
+
import React, { useState, useEffect, useCallback } from "react";
|
|
2
|
+
import { Box, useWindowSize } from "ink";
|
|
4
3
|
import { authService } from "wave-agent-sdk";
|
|
5
4
|
import { MessageList } from "./MessageList.js";
|
|
6
5
|
import { InputBox } from "./InputBox.js";
|
|
@@ -18,6 +17,7 @@ export const ChatInterface: React.FC = () => {
|
|
|
18
17
|
isLoading,
|
|
19
18
|
isCommandRunning,
|
|
20
19
|
isCompacting,
|
|
20
|
+
compactionStream,
|
|
21
21
|
sendMessage,
|
|
22
22
|
abortMessage,
|
|
23
23
|
mcpServers,
|
|
@@ -30,23 +30,26 @@ export const ChatInterface: React.FC = () => {
|
|
|
30
30
|
slashCommands,
|
|
31
31
|
hasSlashCommand,
|
|
32
32
|
isConfirmationVisible,
|
|
33
|
-
hasPendingConfirmations,
|
|
34
33
|
confirmingTool,
|
|
35
34
|
handleConfirmationDecision,
|
|
36
35
|
handleConfirmationCancel,
|
|
37
36
|
version,
|
|
38
37
|
workdir,
|
|
39
38
|
remountKey,
|
|
40
|
-
forceRemount,
|
|
41
39
|
getGatewayConfig,
|
|
42
40
|
} = useChat();
|
|
43
41
|
|
|
44
42
|
const displayMessages = messages;
|
|
45
43
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
const { rows } = useWindowSize();
|
|
45
|
+
|
|
46
|
+
// Reserve terminal rows for the pending tool block in the message list and
|
|
47
|
+
// the ConfirmationSelector, so the confirmation details stay within Ink's
|
|
48
|
+
// incremental-rendering height. When dynamic output >= terminal rows, Ink
|
|
49
|
+
// falls back to a fullscreen clear + redraw on every frame, which makes the
|
|
50
|
+
// confirmation options flicker while navigating.
|
|
51
|
+
const CONFIRMATION_UI_RESERVE = 14;
|
|
52
|
+
const detailsMaxHeight = Math.max(rows - CONFIRMATION_UI_RESERVE, 1);
|
|
50
53
|
|
|
51
54
|
// Compute whether the user has any usable auth/direct-API config,
|
|
52
55
|
// so the welcome page can prompt /login when neither is present.
|
|
@@ -70,36 +73,16 @@ export const ChatInterface: React.FC = () => {
|
|
|
70
73
|
|
|
71
74
|
const showLoginHint = !hasAuth;
|
|
72
75
|
|
|
73
|
-
// Handle forceStatic mode for overflow and request remount when exiting
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
if (isConfirmationVisible && chatInterfaceRef.current) {
|
|
76
|
-
const { height } = measureElement(chatInterfaceRef.current);
|
|
77
|
-
if (height > terminalHeight) {
|
|
78
|
-
setForceStatic(true);
|
|
79
|
-
}
|
|
80
|
-
} else if (forceStatic && !hasPendingConfirmations) {
|
|
81
|
-
setForceStatic(false);
|
|
82
|
-
forceRemount();
|
|
83
|
-
}
|
|
84
|
-
}, [
|
|
85
|
-
isConfirmationVisible,
|
|
86
|
-
terminalHeight,
|
|
87
|
-
forceStatic,
|
|
88
|
-
hasPendingConfirmations,
|
|
89
|
-
forceRemount,
|
|
90
|
-
]);
|
|
91
|
-
|
|
92
76
|
if (!sessionId) return null;
|
|
93
77
|
|
|
94
78
|
return (
|
|
95
|
-
<Box
|
|
79
|
+
<Box flexDirection="column">
|
|
96
80
|
<MessageList
|
|
97
81
|
key={remountKey}
|
|
98
82
|
messages={displayMessages}
|
|
99
83
|
isExpanded={isExpanded}
|
|
100
84
|
version={version}
|
|
101
85
|
workdir={workdir}
|
|
102
|
-
forceStatic={forceStatic}
|
|
103
86
|
/>
|
|
104
87
|
|
|
105
88
|
{!isConfirmationVisible && !isExpanded && (
|
|
@@ -110,6 +93,7 @@ export const ChatInterface: React.FC = () => {
|
|
|
110
93
|
isCommandRunning={isCommandRunning}
|
|
111
94
|
isCompacting={isCompacting}
|
|
112
95
|
latestTotalTokens={latestTotalTokens}
|
|
96
|
+
compactionStream={compactionStream}
|
|
113
97
|
/>
|
|
114
98
|
)}
|
|
115
99
|
<TaskList />
|
|
@@ -134,28 +118,13 @@ export const ChatInterface: React.FC = () => {
|
|
|
134
118
|
|
|
135
119
|
{isConfirmationVisible && (
|
|
136
120
|
<>
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
planContent={confirmingTool!.planContent}
|
|
145
|
-
warning={confirmingTool!.warning}
|
|
146
|
-
isExpanded={isExpanded}
|
|
147
|
-
/>
|
|
148
|
-
)}
|
|
149
|
-
</Static>
|
|
150
|
-
) : (
|
|
151
|
-
<ConfirmationDetails
|
|
152
|
-
toolName={confirmingTool!.name}
|
|
153
|
-
toolInput={confirmingTool!.input}
|
|
154
|
-
planContent={confirmingTool!.planContent}
|
|
155
|
-
warning={confirmingTool!.warning}
|
|
156
|
-
isExpanded={isExpanded}
|
|
157
|
-
/>
|
|
158
|
-
)}
|
|
121
|
+
<ConfirmationDetails
|
|
122
|
+
toolName={confirmingTool!.name}
|
|
123
|
+
toolInput={confirmingTool!.input}
|
|
124
|
+
planContent={confirmingTool!.planContent}
|
|
125
|
+
warning={confirmingTool!.warning}
|
|
126
|
+
maxHeight={detailsMaxHeight}
|
|
127
|
+
/>
|
|
159
128
|
<ConfirmationSelector
|
|
160
129
|
toolName={confirmingTool!.name}
|
|
161
130
|
toolInput={confirmingTool!.input}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Box, Text } from "ink";
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { Box, Text, useInput } from "ink";
|
|
3
3
|
import {
|
|
4
4
|
BASH_TOOL_NAME,
|
|
5
5
|
EDIT_TOOL_NAME,
|
|
@@ -9,8 +9,7 @@ import {
|
|
|
9
9
|
ASK_USER_QUESTION_TOOL_NAME,
|
|
10
10
|
ARTIFACT_TOOL_NAME,
|
|
11
11
|
} from "wave-agent-sdk";
|
|
12
|
-
import {
|
|
13
|
-
import { PlanDisplay } from "./PlanDisplay.js";
|
|
12
|
+
import { buildDiffLinesFromParams } from "./DiffDisplay.js";
|
|
14
13
|
import { highlightToAnsi } from "../utils/highlightUtils.js";
|
|
15
14
|
|
|
16
15
|
// Helper function to generate descriptive action text
|
|
@@ -42,12 +41,20 @@ const getActionDescription = (
|
|
|
42
41
|
}
|
|
43
42
|
};
|
|
44
43
|
|
|
44
|
+
// Row budget for the scroll indicators (↑ more / ↓ more, up to one each).
|
|
45
|
+
const SCROLL_INDICATOR_BUDGET = 2;
|
|
46
|
+
// Row budget for the fixed scroll-key hint shown when content is scrollable.
|
|
47
|
+
const SCROLL_HINT_BUDGET = 1;
|
|
48
|
+
|
|
45
49
|
export interface ConfirmationDetailsProps {
|
|
46
50
|
toolName: string;
|
|
47
51
|
toolInput?: Record<string, unknown>;
|
|
48
52
|
planContent?: string;
|
|
49
53
|
warning?: string;
|
|
50
|
-
|
|
54
|
+
/** Available height (rows) for the whole details block, computed by
|
|
55
|
+
* ChatInterface from the terminal size. Used to size the scrollable
|
|
56
|
+
* content area so the dynamic output never exceeds terminal height. */
|
|
57
|
+
maxHeight?: number;
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
export const ConfirmationDetails: React.FC<ConfirmationDetailsProps> = ({
|
|
@@ -55,56 +62,156 @@ export const ConfirmationDetails: React.FC<ConfirmationDetailsProps> = ({
|
|
|
55
62
|
toolInput,
|
|
56
63
|
planContent,
|
|
57
64
|
warning,
|
|
58
|
-
|
|
65
|
+
maxHeight,
|
|
59
66
|
}) => {
|
|
60
67
|
const startLineNumber =
|
|
61
68
|
(toolInput?.startLineNumber as number | undefined) ??
|
|
62
69
|
(toolName === WRITE_TOOL_NAME ? 1 : undefined);
|
|
63
70
|
|
|
64
|
-
const
|
|
71
|
+
const headerRows = 2 + (warning ? 1 : 0);
|
|
72
|
+
|
|
73
|
+
// Number of content rows rendered at once. The header stays fixed above the
|
|
74
|
+
// scrollable area; rows are budgeted for the scroll indicators and hint.
|
|
75
|
+
const visibleCount = Math.max(
|
|
76
|
+
1,
|
|
77
|
+
(maxHeight ?? 24) -
|
|
78
|
+
headerRows -
|
|
79
|
+
SCROLL_INDICATOR_BUDGET -
|
|
80
|
+
SCROLL_HINT_BUDGET,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
// Content linearized into rows so the details area can be scrolled with
|
|
84
|
+
// PgUp/PgDn while the confirmation options stay fixed at the bottom.
|
|
85
|
+
const diffLines = buildDiffLinesFromParams({
|
|
86
|
+
toolName,
|
|
87
|
+
parameters: JSON.stringify(toolInput),
|
|
88
|
+
startLineNumber,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const showToolInput =
|
|
92
|
+
toolName !== WRITE_TOOL_NAME &&
|
|
93
|
+
toolName !== EDIT_TOOL_NAME &&
|
|
94
|
+
toolName !== EXIT_PLAN_MODE_TOOL_NAME &&
|
|
95
|
+
toolName !== ENTER_PLAN_MODE_TOOL_NAME &&
|
|
96
|
+
toolName !== ASK_USER_QUESTION_TOOL_NAME &&
|
|
97
|
+
toolName !== BASH_TOOL_NAME &&
|
|
98
|
+
!!toolInput;
|
|
99
|
+
|
|
100
|
+
const jsonLines = showToolInput
|
|
101
|
+
? highlightToAnsi(JSON.stringify(toolInput, null, 2), "json")
|
|
102
|
+
.split("\n")
|
|
103
|
+
.map((line, index) => (
|
|
104
|
+
<Box
|
|
105
|
+
key={`json-${index}`}
|
|
106
|
+
paddingLeft={2}
|
|
107
|
+
borderLeft
|
|
108
|
+
borderColor="cyan"
|
|
109
|
+
>
|
|
110
|
+
<Text>{line || " "}</Text>
|
|
111
|
+
</Box>
|
|
112
|
+
))
|
|
113
|
+
: [];
|
|
114
|
+
|
|
115
|
+
const showPlan =
|
|
116
|
+
toolName !== ASK_USER_QUESTION_TOOL_NAME &&
|
|
117
|
+
toolName === EXIT_PLAN_MODE_TOOL_NAME &&
|
|
118
|
+
!!planContent;
|
|
119
|
+
|
|
120
|
+
const planLines = showPlan
|
|
121
|
+
? planContent!.split("\n").map((line, index) => (
|
|
122
|
+
<Box key={`plan-${index}`}>
|
|
123
|
+
<Text>{line || " "}</Text>
|
|
124
|
+
</Box>
|
|
125
|
+
))
|
|
126
|
+
: [];
|
|
127
|
+
|
|
128
|
+
const contentLines: React.ReactNode[] = [
|
|
129
|
+
...diffLines,
|
|
130
|
+
...jsonLines,
|
|
131
|
+
...planLines,
|
|
132
|
+
];
|
|
133
|
+
const totalLines = contentLines.length;
|
|
134
|
+
const maxScroll = Math.max(0, totalLines - visibleCount);
|
|
135
|
+
|
|
136
|
+
const [scrollOffset, setScrollOffset] = useState(0);
|
|
137
|
+
|
|
138
|
+
// Reset scrolling when a new confirmation appears.
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
setScrollOffset(0);
|
|
141
|
+
}, [toolName, toolInput, planContent]);
|
|
142
|
+
|
|
143
|
+
const halfPage = Math.max(1, Math.ceil(visibleCount / 2));
|
|
144
|
+
useInput((input, key) => {
|
|
145
|
+
if (key.pageUp) {
|
|
146
|
+
setScrollOffset((offset) => Math.max(0, offset - visibleCount));
|
|
147
|
+
}
|
|
148
|
+
if (key.pageDown) {
|
|
149
|
+
setScrollOffset((offset) => Math.min(maxScroll, offset + visibleCount));
|
|
150
|
+
}
|
|
151
|
+
// Ctrl+u/Ctrl+d scroll half a page — fallback for keyboards without
|
|
152
|
+
// PgUp/PgDn (aligned with Claude Code's modal pager keys).
|
|
153
|
+
if (key.ctrl && input === "u") {
|
|
154
|
+
setScrollOffset((offset) => Math.max(0, offset - halfPage));
|
|
155
|
+
}
|
|
156
|
+
if (key.ctrl && input === "d") {
|
|
157
|
+
setScrollOffset((offset) => Math.min(maxScroll, offset + halfPage));
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const clampedOffset = Math.min(scrollOffset, maxScroll);
|
|
162
|
+
const visibleLines = contentLines.slice(
|
|
163
|
+
clampedOffset,
|
|
164
|
+
clampedOffset + visibleCount,
|
|
165
|
+
);
|
|
166
|
+
const hasMoreAbove = clampedOffset > 0;
|
|
167
|
+
const hasMoreBelow = clampedOffset + visibleCount < totalLines;
|
|
168
|
+
|
|
169
|
+
return (
|
|
65
170
|
<Box
|
|
66
171
|
flexDirection="column"
|
|
172
|
+
flexShrink={0}
|
|
67
173
|
borderStyle="single"
|
|
68
174
|
borderColor="yellow"
|
|
69
175
|
borderBottom={false}
|
|
70
176
|
borderLeft={false}
|
|
71
177
|
borderRight={false}
|
|
72
178
|
>
|
|
73
|
-
<Text color="yellow" bold>
|
|
179
|
+
<Text color="yellow" bold wrap="truncate-end">
|
|
74
180
|
Tool: {toolName}
|
|
75
181
|
</Text>
|
|
76
|
-
<Text color="yellow"
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
{toolName !== WRITE_TOOL_NAME &&
|
|
86
|
-
toolName !== EDIT_TOOL_NAME &&
|
|
87
|
-
toolName !== EXIT_PLAN_MODE_TOOL_NAME &&
|
|
88
|
-
toolName !== ENTER_PLAN_MODE_TOOL_NAME &&
|
|
89
|
-
toolName !== ASK_USER_QUESTION_TOOL_NAME &&
|
|
90
|
-
toolName !== BASH_TOOL_NAME &&
|
|
91
|
-
!!toolInput && (
|
|
92
|
-
<Box paddingLeft={2} borderLeft borderColor="cyan">
|
|
93
|
-
<Text>
|
|
94
|
-
{highlightToAnsi(JSON.stringify(toolInput, null, 2), "json")}
|
|
95
|
-
</Text>
|
|
96
|
-
</Box>
|
|
97
|
-
)}
|
|
182
|
+
<Text color="yellow" wrap="truncate-end">
|
|
183
|
+
{getActionDescription(toolName, toolInput)}
|
|
184
|
+
</Text>
|
|
185
|
+
{warning && (
|
|
186
|
+
<Text color="red" wrap="truncate-end">
|
|
187
|
+
⚠ {warning}
|
|
188
|
+
</Text>
|
|
189
|
+
)}
|
|
98
190
|
|
|
99
|
-
{
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
191
|
+
{hasMoreAbove && (
|
|
192
|
+
<Box>
|
|
193
|
+
<Text color="gray" dimColor>
|
|
194
|
+
↑ {clampedOffset} more
|
|
195
|
+
</Text>
|
|
196
|
+
</Box>
|
|
197
|
+
)}
|
|
198
|
+
{visibleLines}
|
|
199
|
+
{hasMoreBelow && (
|
|
200
|
+
<Box>
|
|
201
|
+
<Text color="gray" dimColor>
|
|
202
|
+
↓ {totalLines - clampedOffset - visibleCount} more
|
|
203
|
+
</Text>
|
|
204
|
+
</Box>
|
|
205
|
+
)}
|
|
206
|
+
{(hasMoreAbove || hasMoreBelow) && (
|
|
207
|
+
<Box>
|
|
208
|
+
<Text color="gray" dimColor>
|
|
209
|
+
PgUp/PgDn page • Ctrl+u/d half page
|
|
210
|
+
</Text>
|
|
211
|
+
</Box>
|
|
212
|
+
)}
|
|
104
213
|
</Box>
|
|
105
214
|
);
|
|
106
|
-
|
|
107
|
-
return content;
|
|
108
215
|
};
|
|
109
216
|
|
|
110
217
|
ConfirmationDetails.displayName = "ConfirmationDetails";
|