wave-code 0.6.5 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/commands/plugin/disable.d.ts.map +1 -1
- package/dist/commands/plugin/disable.js +3 -10
- package/dist/commands/plugin/enable.d.ts.map +1 -1
- package/dist/commands/plugin/enable.js +3 -10
- package/dist/commands/plugin/install.d.ts.map +1 -1
- package/dist/commands/plugin/install.js +4 -11
- package/dist/commands/plugin/list.d.ts.map +1 -1
- package/dist/commands/plugin/list.js +5 -39
- package/dist/commands/plugin/marketplace.js +9 -9
- package/dist/commands/plugin/uninstall.d.ts.map +1 -1
- package/dist/commands/plugin/uninstall.js +4 -17
- package/dist/commands/plugin/update.js +3 -3
- package/dist/components/App.d.ts +1 -0
- package/dist/components/App.d.ts.map +1 -1
- package/dist/components/App.js +4 -4
- package/dist/components/BackgroundTaskManager.d.ts.map +1 -1
- package/dist/components/BackgroundTaskManager.js +34 -18
- package/dist/components/ChatInterface.d.ts.map +1 -1
- package/dist/components/ChatInterface.js +28 -15
- package/dist/components/ConfirmationDetails.d.ts +1 -0
- package/dist/components/ConfirmationDetails.d.ts.map +1 -1
- package/dist/components/ConfirmationDetails.js +7 -14
- package/dist/components/ConfirmationSelector.d.ts +1 -0
- package/dist/components/ConfirmationSelector.d.ts.map +1 -1
- package/dist/components/ConfirmationSelector.js +164 -117
- package/dist/components/DiffDisplay.d.ts +1 -0
- package/dist/components/DiffDisplay.d.ts.map +1 -1
- package/dist/components/DiffDisplay.js +94 -36
- package/dist/components/HistorySearch.d.ts.map +1 -1
- package/dist/components/HistorySearch.js +26 -20
- package/dist/components/Markdown.d.ts.map +1 -1
- package/dist/components/Markdown.js +3 -1
- package/dist/components/McpManager.d.ts.map +1 -1
- package/dist/components/McpManager.js +49 -52
- package/dist/components/MessageBlockItem.d.ts +9 -0
- package/dist/components/MessageBlockItem.d.ts.map +1 -0
- package/dist/components/MessageBlockItem.js +11 -0
- package/dist/components/MessageList.d.ts +2 -4
- package/dist/components/MessageList.d.ts.map +1 -1
- package/dist/components/MessageList.js +28 -23
- package/dist/components/PluginDetail.d.ts.map +1 -1
- package/dist/components/PluginDetail.js +19 -22
- package/dist/components/SessionSelector.d.ts.map +1 -1
- package/dist/components/SessionSelector.js +8 -5
- package/dist/components/TaskList.d.ts.map +1 -1
- package/dist/components/TaskList.js +2 -5
- package/dist/components/ToolDisplay.d.ts.map +1 -1
- package/dist/components/ToolDisplay.js +1 -1
- package/dist/contexts/useChat.d.ts +1 -0
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +20 -3
- package/dist/hooks/usePluginManager.d.ts.map +1 -1
- package/dist/hooks/usePluginManager.js +20 -39
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -0
- package/dist/print-cli.d.ts +1 -0
- package/dist/print-cli.d.ts.map +1 -1
- package/dist/print-cli.js +2 -1
- package/dist/utils/highlightUtils.d.ts +2 -0
- package/dist/utils/highlightUtils.d.ts.map +1 -0
- package/dist/utils/highlightUtils.js +69 -0
- package/dist/utils/toolParameterTransforms.d.ts +2 -6
- package/dist/utils/toolParameterTransforms.d.ts.map +1 -1
- package/dist/utils/toolParameterTransforms.js +10 -14
- package/package.json +4 -2
- package/src/cli.tsx +3 -0
- package/src/commands/plugin/disable.ts +3 -17
- package/src/commands/plugin/enable.ts +3 -17
- package/src/commands/plugin/install.ts +4 -18
- package/src/commands/plugin/list.ts +5 -55
- package/src/commands/plugin/marketplace.ts +9 -9
- package/src/commands/plugin/uninstall.ts +4 -26
- package/src/commands/plugin/update.ts +3 -3
- package/src/components/App.tsx +10 -2
- package/src/components/BackgroundTaskManager.tsx +69 -44
- package/src/components/ChatInterface.tsx +35 -23
- package/src/components/ConfirmationDetails.tsx +13 -15
- package/src/components/ConfirmationSelector.tsx +207 -128
- package/src/components/DiffDisplay.tsx +164 -75
- package/src/components/HistorySearch.tsx +31 -25
- package/src/components/Markdown.tsx +3 -1
- package/src/components/McpManager.tsx +51 -59
- package/src/components/MessageBlockItem.tsx +83 -0
- package/src/components/MessageList.tsx +55 -52
- package/src/components/PluginDetail.tsx +30 -31
- package/src/components/SessionSelector.tsx +8 -5
- package/src/components/TaskList.tsx +2 -5
- package/src/components/ToolDisplay.tsx +5 -1
- package/src/contexts/useChat.tsx +22 -2
- package/src/hooks/usePluginManager.ts +21 -57
- package/src/index.ts +17 -0
- package/src/print-cli.ts +3 -0
- package/src/utils/highlightUtils.ts +76 -0
- package/src/utils/toolParameterTransforms.ts +11 -20
- package/dist/components/MessageItem.d.ts +0 -8
- package/dist/components/MessageItem.d.ts.map +0 -1
- package/dist/components/MessageItem.js +0 -13
- package/src/components/MessageItem.tsx +0 -81
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PluginCore } from "wave-agent-sdk";
|
|
2
2
|
|
|
3
3
|
export async function addMarketplaceCommand(argv: { input: string }) {
|
|
4
|
-
const
|
|
4
|
+
const pluginCore = new PluginCore(process.cwd());
|
|
5
5
|
try {
|
|
6
|
-
const marketplace = await
|
|
6
|
+
const marketplace = await pluginCore.addMarketplace(argv.input);
|
|
7
7
|
const source = marketplace.source;
|
|
8
8
|
let sourceInfo = "";
|
|
9
9
|
if (source.source === "directory") {
|
|
@@ -25,9 +25,9 @@ export async function addMarketplaceCommand(argv: { input: string }) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export async function listMarketplacesCommand() {
|
|
28
|
-
const
|
|
28
|
+
const pluginCore = new PluginCore(process.cwd());
|
|
29
29
|
try {
|
|
30
|
-
const marketplaces = await
|
|
30
|
+
const marketplaces = await pluginCore.listMarketplaces();
|
|
31
31
|
if (marketplaces.length === 0) {
|
|
32
32
|
console.log("No marketplaces registered.");
|
|
33
33
|
} else {
|
|
@@ -57,9 +57,9 @@ export async function listMarketplacesCommand() {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
export async function removeMarketplaceCommand(argv: { name: string }) {
|
|
60
|
-
const
|
|
60
|
+
const pluginCore = new PluginCore(process.cwd());
|
|
61
61
|
try {
|
|
62
|
-
await
|
|
62
|
+
await pluginCore.removeMarketplace(argv.name);
|
|
63
63
|
console.log(`Successfully removed marketplace: ${argv.name}`);
|
|
64
64
|
process.exit(0);
|
|
65
65
|
} catch (error) {
|
|
@@ -70,14 +70,14 @@ export async function removeMarketplaceCommand(argv: { name: string }) {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
export async function updateMarketplaceCommand(argv: { name?: string }) {
|
|
73
|
-
const
|
|
73
|
+
const pluginCore = new PluginCore(process.cwd());
|
|
74
74
|
try {
|
|
75
75
|
console.log(
|
|
76
76
|
argv.name
|
|
77
77
|
? `Updating marketplace: ${argv.name}...`
|
|
78
78
|
: "Updating all marketplaces...",
|
|
79
79
|
);
|
|
80
|
-
await
|
|
80
|
+
await pluginCore.updateMarketplace(argv.name);
|
|
81
81
|
console.log("Successfully updated.");
|
|
82
82
|
process.exit(0);
|
|
83
83
|
} catch (error) {
|
|
@@ -1,35 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
MarketplaceService,
|
|
3
|
-
ConfigurationService,
|
|
4
|
-
PluginManager,
|
|
5
|
-
PluginScopeManager,
|
|
6
|
-
} from "wave-agent-sdk";
|
|
1
|
+
import { PluginCore } from "wave-agent-sdk";
|
|
7
2
|
|
|
8
3
|
export async function uninstallPluginCommand(argv: { plugin: string }) {
|
|
9
|
-
const marketplaceService = new MarketplaceService();
|
|
10
4
|
const workdir = process.cwd();
|
|
5
|
+
const pluginCore = new PluginCore(workdir);
|
|
11
6
|
|
|
12
7
|
try {
|
|
13
|
-
await
|
|
8
|
+
await pluginCore.uninstallPlugin(argv.plugin);
|
|
14
9
|
console.log(`Successfully uninstalled plugin: ${argv.plugin}`);
|
|
15
|
-
|
|
16
|
-
const configurationService = new ConfigurationService();
|
|
17
|
-
const pluginManager = new PluginManager({ workdir });
|
|
18
|
-
const scopeManager = new PluginScopeManager({
|
|
19
|
-
workdir,
|
|
20
|
-
configurationService,
|
|
21
|
-
pluginManager,
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
await scopeManager.removePluginFromAllScopes(argv.plugin);
|
|
26
|
-
console.log(`Cleaned up plugin configuration from all scopes`);
|
|
27
|
-
} catch (error) {
|
|
28
|
-
console.warn(
|
|
29
|
-
`Warning: Could not clean up all plugin configurations: ${error instanceof Error ? error.message : String(error)}`,
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
10
|
+
console.log(`Cleaned up plugin configuration from all scopes`);
|
|
33
11
|
process.exit(0);
|
|
34
12
|
} catch (error) {
|
|
35
13
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PluginCore } from "wave-agent-sdk";
|
|
2
2
|
|
|
3
3
|
export async function updatePluginCommand(argv: { plugin: string }) {
|
|
4
|
-
const
|
|
4
|
+
const pluginCore = new PluginCore(process.cwd());
|
|
5
5
|
|
|
6
6
|
try {
|
|
7
|
-
const updated = await
|
|
7
|
+
const updated = await pluginCore.updatePlugin(argv.plugin);
|
|
8
8
|
console.log(
|
|
9
9
|
`Successfully updated plugin: ${updated.name} v${updated.version} from ${updated.marketplace}`,
|
|
10
10
|
);
|
package/src/components/App.tsx
CHANGED
|
@@ -9,14 +9,20 @@ interface AppProps {
|
|
|
9
9
|
continueLastSession?: boolean;
|
|
10
10
|
bypassPermissions?: boolean;
|
|
11
11
|
pluginDirs?: string[];
|
|
12
|
+
tools?: string[];
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
const AppWithProviders: React.FC<{
|
|
15
16
|
bypassPermissions?: boolean;
|
|
16
17
|
pluginDirs?: string[];
|
|
17
|
-
|
|
18
|
+
tools?: string[];
|
|
19
|
+
}> = ({ bypassPermissions, pluginDirs, tools }) => {
|
|
18
20
|
return (
|
|
19
|
-
<ChatProvider
|
|
21
|
+
<ChatProvider
|
|
22
|
+
bypassPermissions={bypassPermissions}
|
|
23
|
+
pluginDirs={pluginDirs}
|
|
24
|
+
tools={tools}
|
|
25
|
+
>
|
|
20
26
|
<ChatInterfaceWithRemount />
|
|
21
27
|
</ChatProvider>
|
|
22
28
|
);
|
|
@@ -74,6 +80,7 @@ export const App: React.FC<AppProps> = ({
|
|
|
74
80
|
continueLastSession,
|
|
75
81
|
bypassPermissions,
|
|
76
82
|
pluginDirs,
|
|
83
|
+
tools,
|
|
77
84
|
}) => {
|
|
78
85
|
return (
|
|
79
86
|
<AppProvider
|
|
@@ -83,6 +90,7 @@ export const App: React.FC<AppProps> = ({
|
|
|
83
90
|
<AppWithProviders
|
|
84
91
|
bypassPermissions={bypassPermissions}
|
|
85
92
|
pluginDirs={pluginDirs}
|
|
93
|
+
tools={tools}
|
|
86
94
|
/>
|
|
87
95
|
</AppProvider>
|
|
88
96
|
);
|
|
@@ -23,6 +23,7 @@ export const BackgroundTaskManager: React.FC<BackgroundTaskManagerProps> = ({
|
|
|
23
23
|
useChat();
|
|
24
24
|
const [tasks, setTasks] = useState<Task[]>([]);
|
|
25
25
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
26
|
+
const MAX_VISIBLE_ITEMS = 3;
|
|
26
27
|
const [viewMode, setViewMode] = useState<"list" | "detail">("list");
|
|
27
28
|
const [detailTaskId, setDetailTaskId] = useState<string | null>(null);
|
|
28
29
|
const [detailOutput, setDetailOutput] = useState<{
|
|
@@ -70,15 +71,28 @@ export const BackgroundTaskManager: React.FC<BackgroundTaskManagerProps> = ({
|
|
|
70
71
|
stopBackgroundTask(taskId);
|
|
71
72
|
};
|
|
72
73
|
|
|
74
|
+
// Calculate visible window
|
|
75
|
+
const startIndex = Math.max(
|
|
76
|
+
0,
|
|
77
|
+
Math.min(
|
|
78
|
+
selectedIndex - Math.floor(MAX_VISIBLE_ITEMS / 2),
|
|
79
|
+
Math.max(0, tasks.length - MAX_VISIBLE_ITEMS),
|
|
80
|
+
),
|
|
81
|
+
);
|
|
82
|
+
const visibleTasks = tasks.slice(startIndex, startIndex + MAX_VISIBLE_ITEMS);
|
|
83
|
+
|
|
73
84
|
useInput((input, key) => {
|
|
74
85
|
if (viewMode === "list") {
|
|
75
86
|
// List mode navigation
|
|
76
87
|
if (key.return) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
88
|
+
setSelectedIndex((prev) => {
|
|
89
|
+
if (tasks.length > 0 && prev < tasks.length) {
|
|
90
|
+
const selectedTask = tasks[prev];
|
|
91
|
+
setDetailTaskId(selectedTask.id);
|
|
92
|
+
setViewMode("detail");
|
|
93
|
+
}
|
|
94
|
+
return prev;
|
|
95
|
+
});
|
|
82
96
|
return;
|
|
83
97
|
}
|
|
84
98
|
|
|
@@ -88,20 +102,25 @@ export const BackgroundTaskManager: React.FC<BackgroundTaskManagerProps> = ({
|
|
|
88
102
|
}
|
|
89
103
|
|
|
90
104
|
if (key.upArrow) {
|
|
91
|
-
setSelectedIndex(Math.max(0,
|
|
105
|
+
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
92
106
|
return;
|
|
93
107
|
}
|
|
94
108
|
|
|
95
109
|
if (key.downArrow) {
|
|
96
|
-
setSelectedIndex(Math.min(tasks.length - 1,
|
|
110
|
+
setSelectedIndex((prev) => Math.min(tasks.length - 1, prev + 1));
|
|
97
111
|
return;
|
|
98
112
|
}
|
|
99
113
|
|
|
100
|
-
if (input === "k"
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
114
|
+
if (input === "k") {
|
|
115
|
+
setSelectedIndex((prev) => {
|
|
116
|
+
if (tasks.length > 0 && prev < tasks.length) {
|
|
117
|
+
const selectedTask = tasks[prev];
|
|
118
|
+
if (selectedTask.status === "running") {
|
|
119
|
+
stopTask(selectedTask.id);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return prev;
|
|
123
|
+
});
|
|
105
124
|
return;
|
|
106
125
|
}
|
|
107
126
|
} else if (viewMode === "detail") {
|
|
@@ -273,40 +292,46 @@ export const BackgroundTaskManager: React.FC<BackgroundTaskManagerProps> = ({
|
|
|
273
292
|
</Box>
|
|
274
293
|
<Text dimColor>Select a task to view details</Text>
|
|
275
294
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
task.
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
Started: {formatTime(task.startTime)}
|
|
302
|
-
{task.runtime !== undefined &&
|
|
303
|
-
` | Runtime: ${formatDuration(task.runtime)}`}
|
|
304
|
-
{task.exitCode !== undefined && ` | Exit: ${task.exitCode}`}
|
|
295
|
+
<Box flexDirection="column">
|
|
296
|
+
{visibleTasks.map((task, index) => {
|
|
297
|
+
const actualIndex = startIndex + index;
|
|
298
|
+
const isSelected = actualIndex === selectedIndex;
|
|
299
|
+
return (
|
|
300
|
+
<Box key={task.id} flexDirection="column">
|
|
301
|
+
<Text
|
|
302
|
+
color={isSelected ? "black" : "white"}
|
|
303
|
+
backgroundColor={isSelected ? "cyan" : undefined}
|
|
304
|
+
>
|
|
305
|
+
{isSelected ? "▶ " : " "}
|
|
306
|
+
{actualIndex + 1}. [{task.id}] {task.type}
|
|
307
|
+
{task.description ? `: ${task.description}` : ""}
|
|
308
|
+
<Text
|
|
309
|
+
color={
|
|
310
|
+
task.status === "running"
|
|
311
|
+
? "green"
|
|
312
|
+
: task.status === "completed"
|
|
313
|
+
? "blue"
|
|
314
|
+
: "red"
|
|
315
|
+
}
|
|
316
|
+
>
|
|
317
|
+
{" "}
|
|
318
|
+
({task.status})
|
|
319
|
+
</Text>
|
|
305
320
|
</Text>
|
|
321
|
+
{isSelected && (
|
|
322
|
+
<Box marginLeft={4} flexDirection="column">
|
|
323
|
+
<Text color="gray" dimColor>
|
|
324
|
+
Started: {formatTime(task.startTime)}
|
|
325
|
+
{task.runtime !== undefined &&
|
|
326
|
+
` | Runtime: ${formatDuration(task.runtime)}`}
|
|
327
|
+
{task.exitCode !== undefined && ` | Exit: ${task.exitCode}`}
|
|
328
|
+
</Text>
|
|
329
|
+
</Box>
|
|
330
|
+
)}
|
|
306
331
|
</Box>
|
|
307
|
-
)
|
|
308
|
-
|
|
309
|
-
|
|
332
|
+
);
|
|
333
|
+
})}
|
|
334
|
+
</Box>
|
|
310
335
|
|
|
311
336
|
<Box marginTop={1}>
|
|
312
337
|
<Text dimColor>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useCallback } from "react";
|
|
1
|
+
import React, { useState, useCallback, useLayoutEffect } from "react";
|
|
2
2
|
import { Box, useStdout } from "ink";
|
|
3
3
|
import { MessageList } from "./MessageList.js";
|
|
4
4
|
import { InputBox } from "./InputBox.js";
|
|
@@ -12,7 +12,9 @@ import type { PermissionDecision } from "wave-agent-sdk";
|
|
|
12
12
|
|
|
13
13
|
export const ChatInterface: React.FC = () => {
|
|
14
14
|
const { stdout } = useStdout();
|
|
15
|
-
const [
|
|
15
|
+
const [detailsHeight, setDetailsHeight] = useState(0);
|
|
16
|
+
const [selectorHeight, setSelectorHeight] = useState(0);
|
|
17
|
+
const [isConfirmationTooTall, setIsConfirmationTooTall] = useState(false);
|
|
16
18
|
|
|
17
19
|
const {
|
|
18
20
|
messages,
|
|
@@ -36,39 +38,49 @@ export const ChatInterface: React.FC = () => {
|
|
|
36
38
|
setWasLastDetailsTooTall,
|
|
37
39
|
} = useChat();
|
|
38
40
|
|
|
39
|
-
const
|
|
40
|
-
(height
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
const handleDetailsHeightMeasured = useCallback((height: number) => {
|
|
42
|
+
setDetailsHeight(height);
|
|
43
|
+
}, []);
|
|
44
|
+
|
|
45
|
+
const handleSelectorHeightMeasured = useCallback((height: number) => {
|
|
46
|
+
setSelectorHeight(height);
|
|
47
|
+
}, []);
|
|
48
|
+
|
|
49
|
+
useLayoutEffect(() => {
|
|
50
|
+
const terminalHeight = stdout?.rows || 24;
|
|
51
|
+
const totalHeight = detailsHeight + selectorHeight;
|
|
52
|
+
if (totalHeight > terminalHeight) {
|
|
53
|
+
setIsConfirmationTooTall(true);
|
|
54
|
+
} else {
|
|
55
|
+
setIsConfirmationTooTall(false);
|
|
56
|
+
}
|
|
57
|
+
}, [detailsHeight, selectorHeight, stdout?.rows]);
|
|
50
58
|
|
|
51
59
|
const handleConfirmationCancel = useCallback(() => {
|
|
52
|
-
if (
|
|
60
|
+
if (isConfirmationTooTall) {
|
|
53
61
|
setWasLastDetailsTooTall((prev) => prev + 1);
|
|
54
|
-
|
|
62
|
+
setIsConfirmationTooTall(false);
|
|
55
63
|
}
|
|
56
64
|
originalHandleConfirmationCancel();
|
|
57
65
|
}, [
|
|
58
|
-
|
|
66
|
+
isConfirmationTooTall,
|
|
59
67
|
originalHandleConfirmationCancel,
|
|
60
68
|
setWasLastDetailsTooTall,
|
|
61
69
|
]);
|
|
62
70
|
|
|
63
71
|
const wrappedHandleConfirmationDecision = useCallback(
|
|
64
72
|
(decision: PermissionDecision) => {
|
|
65
|
-
if (
|
|
73
|
+
if (isConfirmationTooTall) {
|
|
66
74
|
setWasLastDetailsTooTall((prev) => prev + 1);
|
|
67
|
-
|
|
75
|
+
setIsConfirmationTooTall(false);
|
|
68
76
|
}
|
|
69
77
|
handleConfirmationDecision(decision);
|
|
70
78
|
},
|
|
71
|
-
[
|
|
79
|
+
[
|
|
80
|
+
isConfirmationTooTall,
|
|
81
|
+
handleConfirmationDecision,
|
|
82
|
+
setWasLastDetailsTooTall,
|
|
83
|
+
],
|
|
72
84
|
);
|
|
73
85
|
|
|
74
86
|
if (!sessionId) return null;
|
|
@@ -77,10 +89,8 @@ export const ChatInterface: React.FC = () => {
|
|
|
77
89
|
<Box flexDirection="column">
|
|
78
90
|
<MessageList
|
|
79
91
|
messages={messages}
|
|
80
|
-
isLoading={isLoading}
|
|
81
|
-
isCommandRunning={isCommandRunning}
|
|
82
92
|
isExpanded={isExpanded}
|
|
83
|
-
|
|
93
|
+
hideDynamicBlocks={isConfirmationVisible}
|
|
84
94
|
/>
|
|
85
95
|
|
|
86
96
|
{(isLoading || isCommandRunning || isCompressing) &&
|
|
@@ -101,7 +111,8 @@ export const ChatInterface: React.FC = () => {
|
|
|
101
111
|
toolName={confirmingTool!.name}
|
|
102
112
|
toolInput={confirmingTool!.input}
|
|
103
113
|
isExpanded={isExpanded}
|
|
104
|
-
onHeightMeasured={
|
|
114
|
+
onHeightMeasured={handleDetailsHeightMeasured}
|
|
115
|
+
isStatic={isConfirmationTooTall}
|
|
105
116
|
/>
|
|
106
117
|
<ConfirmationSelector
|
|
107
118
|
toolName={confirmingTool!.name}
|
|
@@ -112,6 +123,7 @@ export const ChatInterface: React.FC = () => {
|
|
|
112
123
|
onDecision={wrappedHandleConfirmationDecision}
|
|
113
124
|
onCancel={handleConfirmationCancel}
|
|
114
125
|
onAbort={abortMessage}
|
|
126
|
+
onHeightMeasured={handleSelectorHeightMeasured}
|
|
115
127
|
/>
|
|
116
128
|
</>
|
|
117
129
|
)}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import React, { useLayoutEffect, useRef
|
|
1
|
+
import React, { useLayoutEffect, useRef } from "react";
|
|
2
2
|
import { Box, Text, useStdout, measureElement, Static } from "ink";
|
|
3
3
|
import {
|
|
4
4
|
BASH_TOOL_NAME,
|
|
5
5
|
EDIT_TOOL_NAME,
|
|
6
|
-
MULTI_EDIT_TOOL_NAME,
|
|
7
|
-
DELETE_FILE_TOOL_NAME,
|
|
8
6
|
WRITE_TOOL_NAME,
|
|
9
7
|
EXIT_PLAN_MODE_TOOL_NAME,
|
|
10
8
|
ASK_USER_QUESTION_TOOL_NAME,
|
|
@@ -26,10 +24,6 @@ const getActionDescription = (
|
|
|
26
24
|
return `Execute command: ${toolInput.command || "unknown command"}`;
|
|
27
25
|
case EDIT_TOOL_NAME:
|
|
28
26
|
return `Edit file: ${toolInput.file_path || "unknown file"}`;
|
|
29
|
-
case MULTI_EDIT_TOOL_NAME:
|
|
30
|
-
return `Edit multiple sections in: ${toolInput.file_path || "unknown file"}`;
|
|
31
|
-
case DELETE_FILE_TOOL_NAME:
|
|
32
|
-
return `Delete file: ${toolInput.target_file || "unknown file"}`;
|
|
33
27
|
case WRITE_TOOL_NAME:
|
|
34
28
|
return `Write to file: ${toolInput.file_path || "unknown file"}`;
|
|
35
29
|
case EXIT_PLAN_MODE_TOOL_NAME:
|
|
@@ -46,6 +40,7 @@ export interface ConfirmationDetailsProps {
|
|
|
46
40
|
toolInput?: Record<string, unknown>;
|
|
47
41
|
isExpanded?: boolean;
|
|
48
42
|
onHeightMeasured?: (height: number) => void;
|
|
43
|
+
isStatic?: boolean;
|
|
49
44
|
}
|
|
50
45
|
|
|
51
46
|
export const ConfirmationDetails: React.FC<ConfirmationDetailsProps> = ({
|
|
@@ -53,21 +48,21 @@ export const ConfirmationDetails: React.FC<ConfirmationDetailsProps> = ({
|
|
|
53
48
|
toolInput,
|
|
54
49
|
isExpanded = false,
|
|
55
50
|
onHeightMeasured,
|
|
51
|
+
isStatic = false,
|
|
56
52
|
}) => {
|
|
57
53
|
const { stdout } = useStdout();
|
|
58
|
-
const [isStatic, setIsStatic] = useState(false);
|
|
59
54
|
const boxRef = useRef(null);
|
|
60
55
|
|
|
56
|
+
const startLineNumber =
|
|
57
|
+
(toolInput?.startLineNumber as number | undefined) ??
|
|
58
|
+
(toolName === WRITE_TOOL_NAME ? 1 : undefined);
|
|
59
|
+
|
|
61
60
|
useLayoutEffect(() => {
|
|
62
61
|
if (boxRef.current) {
|
|
63
62
|
const { height } = measureElement(boxRef.current);
|
|
64
|
-
const terminalHeight = stdout?.rows || 24;
|
|
65
|
-
if (height > terminalHeight - 10) {
|
|
66
|
-
setIsStatic(true);
|
|
67
|
-
}
|
|
68
63
|
onHeightMeasured?.(height);
|
|
69
64
|
}
|
|
70
|
-
}, [stdout?.rows, onHeightMeasured]);
|
|
65
|
+
}, [stdout?.rows, onHeightMeasured, toolInput, isExpanded]);
|
|
71
66
|
|
|
72
67
|
const content = (
|
|
73
68
|
<Box
|
|
@@ -78,14 +73,17 @@ export const ConfirmationDetails: React.FC<ConfirmationDetailsProps> = ({
|
|
|
78
73
|
borderBottom={false}
|
|
79
74
|
borderLeft={false}
|
|
80
75
|
borderRight={false}
|
|
81
|
-
paddingTop={1}
|
|
82
76
|
>
|
|
83
77
|
<Text color="yellow" bold>
|
|
84
78
|
Tool: {toolName}
|
|
85
79
|
</Text>
|
|
86
80
|
<Text color="yellow">{getActionDescription(toolName, toolInput)}</Text>
|
|
87
81
|
|
|
88
|
-
<DiffDisplay
|
|
82
|
+
<DiffDisplay
|
|
83
|
+
toolName={toolName}
|
|
84
|
+
parameters={JSON.stringify(toolInput)}
|
|
85
|
+
startLineNumber={startLineNumber}
|
|
86
|
+
/>
|
|
89
87
|
|
|
90
88
|
{toolName !== ASK_USER_QUESTION_TOOL_NAME &&
|
|
91
89
|
toolName === EXIT_PLAN_MODE_TOOL_NAME &&
|