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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useMemo } from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { WRITE_TOOL_NAME, EDIT_TOOL_NAME } from "wave-agent-sdk";
|
|
4
|
+
import type { Change } from "wave-agent-sdk";
|
|
4
5
|
import { transformToolBlockToChanges } from "../utils/toolParameterTransforms.js";
|
|
5
6
|
import { diffLines, diffWords } from "diff";
|
|
6
7
|
|
|
@@ -8,351 +9,384 @@ interface DiffDisplayProps {
|
|
|
8
9
|
toolName?: string;
|
|
9
10
|
parameters?: string;
|
|
10
11
|
startLineNumber?: number;
|
|
12
|
+
/** Return the diff as an array of line elements instead of a rendered Box,
|
|
13
|
+
* so callers can slice/scroll through the lines. */
|
|
14
|
+
asLines?: boolean;
|
|
11
15
|
}
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
// Render word-level diff between two lines of text
|
|
18
|
+
const renderWordLevelDiff = (
|
|
19
|
+
oldLine: string,
|
|
20
|
+
newLine: string,
|
|
21
|
+
keyPrefix: string,
|
|
22
|
+
) => {
|
|
23
|
+
try {
|
|
24
|
+
const changes = diffWords(oldLine, newLine);
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (!showDiff || !toolName || !parameters) return [];
|
|
24
|
-
try {
|
|
25
|
-
// Use local transformation with JSON parsing and type guards
|
|
26
|
-
return transformToolBlockToChanges(toolName, parameters, startLineNumber);
|
|
27
|
-
} catch (error) {
|
|
28
|
-
console.warn("Error transforming tool block to changes:", error);
|
|
29
|
-
return [];
|
|
30
|
-
}
|
|
31
|
-
}, [toolName, parameters, showDiff, startLineNumber]);
|
|
32
|
-
|
|
33
|
-
// Render word-level diff between two lines of text
|
|
34
|
-
const renderWordLevelDiff = (
|
|
35
|
-
oldLine: string,
|
|
36
|
-
newLine: string,
|
|
37
|
-
keyPrefix: string,
|
|
38
|
-
) => {
|
|
39
|
-
try {
|
|
40
|
-
const changes = diffWords(oldLine, newLine);
|
|
41
|
-
|
|
42
|
-
const removedParts: React.ReactNode[] = [];
|
|
43
|
-
const addedParts: React.ReactNode[] = [];
|
|
44
|
-
|
|
45
|
-
changes.forEach((part, index) => {
|
|
46
|
-
if (part.removed) {
|
|
47
|
-
removedParts.push(
|
|
48
|
-
<Text
|
|
49
|
-
key={`removed-${keyPrefix}-${index}`}
|
|
50
|
-
color="black"
|
|
51
|
-
backgroundColor="red"
|
|
52
|
-
>
|
|
53
|
-
{part.value}
|
|
54
|
-
</Text>,
|
|
55
|
-
);
|
|
56
|
-
} else if (part.added) {
|
|
57
|
-
addedParts.push(
|
|
58
|
-
<Text
|
|
59
|
-
key={`added-${keyPrefix}-${index}`}
|
|
60
|
-
color="black"
|
|
61
|
-
backgroundColor="green"
|
|
62
|
-
>
|
|
63
|
-
{part.value}
|
|
64
|
-
</Text>,
|
|
65
|
-
);
|
|
66
|
-
} else {
|
|
67
|
-
// Unchanged parts
|
|
68
|
-
removedParts.push(
|
|
69
|
-
<Text key={`removed-unchanged-${keyPrefix}-${index}`} color="red">
|
|
70
|
-
{part.value}
|
|
71
|
-
</Text>,
|
|
72
|
-
);
|
|
73
|
-
addedParts.push(
|
|
74
|
-
<Text key={`added-unchanged-${keyPrefix}-${index}`} color="green">
|
|
75
|
-
{part.value}
|
|
76
|
-
</Text>,
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
});
|
|
26
|
+
const removedParts: React.ReactNode[] = [];
|
|
27
|
+
const addedParts: React.ReactNode[] = [];
|
|
80
28
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
29
|
+
changes.forEach((part, index) => {
|
|
30
|
+
if (part.removed) {
|
|
31
|
+
removedParts.push(
|
|
32
|
+
<Text
|
|
33
|
+
key={`removed-${keyPrefix}-${index}`}
|
|
34
|
+
color="black"
|
|
35
|
+
backgroundColor="red"
|
|
36
|
+
>
|
|
37
|
+
{part.value}
|
|
89
38
|
</Text>,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
39
|
+
);
|
|
40
|
+
} else if (part.added) {
|
|
41
|
+
addedParts.push(
|
|
42
|
+
<Text
|
|
43
|
+
key={`added-${keyPrefix}-${index}`}
|
|
44
|
+
color="black"
|
|
45
|
+
backgroundColor="green"
|
|
46
|
+
>
|
|
47
|
+
{part.value}
|
|
48
|
+
</Text>,
|
|
49
|
+
);
|
|
50
|
+
} else {
|
|
51
|
+
// Unchanged parts
|
|
52
|
+
removedParts.push(
|
|
53
|
+
<Text key={`removed-unchanged-${keyPrefix}-${index}`} color="red">
|
|
54
|
+
{part.value}
|
|
55
|
+
</Text>,
|
|
56
|
+
);
|
|
57
|
+
addedParts.push(
|
|
58
|
+
<Text key={`added-unchanged-${keyPrefix}-${index}`} color="green">
|
|
59
|
+
{part.value}
|
|
94
60
|
</Text>,
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
};
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
99
64
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
65
|
+
return { removedParts, addedParts };
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.warn("Error rendering word-level diff:", error);
|
|
68
|
+
// Fallback to simple line display
|
|
69
|
+
return {
|
|
70
|
+
removedParts: [
|
|
71
|
+
<Text key={`fallback-removed-${keyPrefix}`} color="red">
|
|
72
|
+
{oldLine}
|
|
73
|
+
</Text>,
|
|
74
|
+
],
|
|
75
|
+
addedParts: [
|
|
76
|
+
<Text key={`fallback-added-${keyPrefix}`} color="green">
|
|
77
|
+
{newLine}
|
|
78
|
+
</Text>,
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
};
|
|
104
83
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
// If we ever support context lines in the Change object, we need to be careful.
|
|
114
|
-
return Math.max(max, start + oldLines, start + newLines);
|
|
115
|
-
}, 0);
|
|
116
|
-
const maxDigits = Math.max(2, maxLineNum.toString().length);
|
|
84
|
+
/**
|
|
85
|
+
* Render the diff as an array of line elements (one ReactNode per row), so
|
|
86
|
+
* callers can slice/scroll through the lines. Returns an empty array when the
|
|
87
|
+
* tool doesn't produce a diff or the content can't be parsed.
|
|
88
|
+
*/
|
|
89
|
+
export function buildDiffLines(changes: Change[]): React.ReactNode[] {
|
|
90
|
+
try {
|
|
91
|
+
if (changes.length === 0) return [];
|
|
117
92
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
93
|
+
const maxLineNum = changes.reduce((max, change) => {
|
|
94
|
+
const oldLines = (change.oldContent || "").split("\n").length;
|
|
95
|
+
const newLines = (change.newContent || "").split("\n").length;
|
|
96
|
+
const start = change.startLineNumber || 1;
|
|
97
|
+
// For Edit tool, the diff might show context lines before/after the change.
|
|
98
|
+
// The startLineNumber is the line where old_string starts.
|
|
99
|
+
// diffLines will include context lines if they are part of the change object.
|
|
100
|
+
// However, our transformEditParameters currently only puts old_string/new_string.
|
|
101
|
+
// If we ever support context lines in the Change object, we need to be careful.
|
|
102
|
+
return Math.max(max, start + oldLines, start + newLines);
|
|
103
|
+
}, 0);
|
|
104
|
+
const maxDigits = Math.max(2, maxLineNum.toString().length);
|
|
130
105
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
106
|
+
const renderLine = (
|
|
107
|
+
oldLineNum: number | null,
|
|
108
|
+
newLineNum: number | null,
|
|
109
|
+
prefix: string,
|
|
110
|
+
content: React.ReactNode,
|
|
111
|
+
color: string,
|
|
112
|
+
key: string,
|
|
113
|
+
) => {
|
|
114
|
+
const formatNum = (num: number | null) =>
|
|
115
|
+
num === null
|
|
116
|
+
? " ".repeat(maxDigits)
|
|
117
|
+
: num.toString().padStart(maxDigits);
|
|
141
118
|
|
|
142
|
-
|
|
119
|
+
return (
|
|
120
|
+
<Box key={key} flexDirection="row">
|
|
121
|
+
<Text color="gray">{formatNum(oldLineNum)} </Text>
|
|
122
|
+
<Text color="gray">{formatNum(newLineNum)} </Text>
|
|
123
|
+
<Text color="gray">| </Text>
|
|
124
|
+
<Text color={color}>{prefix}</Text>
|
|
125
|
+
<Text color={color}>{content}</Text>
|
|
126
|
+
</Box>
|
|
127
|
+
);
|
|
128
|
+
};
|
|
143
129
|
|
|
144
|
-
|
|
145
|
-
try {
|
|
146
|
-
// Get line-level diff to understand the structure
|
|
147
|
-
const lineDiffs = diffLines(
|
|
148
|
-
change.oldContent || "",
|
|
149
|
-
change.newContent || "",
|
|
150
|
-
);
|
|
130
|
+
const allElements: React.ReactNode[] = [];
|
|
151
131
|
|
|
152
|
-
|
|
153
|
-
|
|
132
|
+
changes.forEach((change, changeIndex) => {
|
|
133
|
+
try {
|
|
134
|
+
// Get line-level diff to understand the structure
|
|
135
|
+
const lineDiffs = diffLines(
|
|
136
|
+
change.oldContent || "",
|
|
137
|
+
change.newContent || "",
|
|
138
|
+
);
|
|
154
139
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
for (let i = 0; i < lineDiffs.length; i++) {
|
|
158
|
-
const part = lineDiffs[i];
|
|
159
|
-
const lines = part.value.split("\n");
|
|
160
|
-
// diffLines might return a trailing empty string if the content ends with a newline
|
|
161
|
-
if (lines[lines.length - 1] === "") {
|
|
162
|
-
lines.pop();
|
|
163
|
-
}
|
|
140
|
+
let oldLineNum = change.startLineNumber || 1;
|
|
141
|
+
let newLineNum = change.startLineNumber || 1;
|
|
164
142
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
143
|
+
// Process line diffs
|
|
144
|
+
const diffElements: React.ReactNode[] = [];
|
|
145
|
+
for (let i = 0; i < lineDiffs.length; i++) {
|
|
146
|
+
const part = lineDiffs[i];
|
|
147
|
+
const lines = part.value.split("\n");
|
|
148
|
+
// diffLines might return a trailing empty string if the content ends with a newline
|
|
149
|
+
if (lines[lines.length - 1] === "") {
|
|
150
|
+
lines.pop();
|
|
151
|
+
}
|
|
173
152
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
);
|
|
182
|
-
diffElements.push(
|
|
183
|
-
renderLine(
|
|
184
|
-
oldLineNum++,
|
|
185
|
-
null,
|
|
186
|
-
"-",
|
|
187
|
-
removedParts,
|
|
188
|
-
"red",
|
|
189
|
-
`remove-${changeIndex}-${i}-${lineIndex}`,
|
|
190
|
-
),
|
|
191
|
-
);
|
|
192
|
-
diffElements.push(
|
|
193
|
-
renderLine(
|
|
194
|
-
null,
|
|
195
|
-
newLineNum++,
|
|
196
|
-
"+",
|
|
197
|
-
addedParts,
|
|
198
|
-
"green",
|
|
199
|
-
`add-${changeIndex}-${i}-${lineIndex}`,
|
|
200
|
-
),
|
|
201
|
-
);
|
|
202
|
-
});
|
|
203
|
-
i++; // Skip the added block
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
153
|
+
if (part.removed) {
|
|
154
|
+
// Look ahead for an added block
|
|
155
|
+
if (i + 1 < lineDiffs.length && lineDiffs[i + 1].added) {
|
|
156
|
+
const nextPart = lineDiffs[i + 1];
|
|
157
|
+
const addedLines = nextPart.value.split("\n");
|
|
158
|
+
if (addedLines[addedLines.length - 1] === "") {
|
|
159
|
+
addedLines.pop();
|
|
206
160
|
}
|
|
207
161
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
oldLineNum++,
|
|
213
|
-
null,
|
|
214
|
-
"-",
|
|
162
|
+
if (lines.length === addedLines.length) {
|
|
163
|
+
// Word-level diffing
|
|
164
|
+
lines.forEach((line, lineIndex) => {
|
|
165
|
+
const { removedParts, addedParts } = renderWordLevelDiff(
|
|
215
166
|
line,
|
|
216
|
-
|
|
217
|
-
`
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
167
|
+
addedLines[lineIndex],
|
|
168
|
+
`word-${changeIndex}-${i}-${lineIndex}`,
|
|
169
|
+
);
|
|
170
|
+
diffElements.push(
|
|
171
|
+
renderLine(
|
|
172
|
+
oldLineNum++,
|
|
173
|
+
null,
|
|
174
|
+
"-",
|
|
175
|
+
removedParts,
|
|
176
|
+
"red",
|
|
177
|
+
`remove-${changeIndex}-${i}-${lineIndex}`,
|
|
178
|
+
),
|
|
179
|
+
);
|
|
180
|
+
diffElements.push(
|
|
181
|
+
renderLine(
|
|
182
|
+
null,
|
|
183
|
+
newLineNum++,
|
|
184
|
+
"+",
|
|
185
|
+
addedParts,
|
|
186
|
+
"green",
|
|
187
|
+
`add-${changeIndex}-${i}-${lineIndex}`,
|
|
188
|
+
),
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
i++; // Skip the added block
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
238
195
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
196
|
+
// Fallback to standard removed rendering
|
|
197
|
+
lines.forEach((line, lineIndex) => {
|
|
198
|
+
diffElements.push(
|
|
199
|
+
renderLine(
|
|
200
|
+
oldLineNum++,
|
|
201
|
+
null,
|
|
202
|
+
"-",
|
|
203
|
+
line,
|
|
204
|
+
"red",
|
|
205
|
+
`remove-${changeIndex}-${i}-${lineIndex}`,
|
|
206
|
+
),
|
|
207
|
+
);
|
|
208
|
+
});
|
|
209
|
+
} else if (part.added) {
|
|
210
|
+
lines.forEach((line, lineIndex) => {
|
|
211
|
+
diffElements.push(
|
|
212
|
+
renderLine(
|
|
213
|
+
null,
|
|
214
|
+
newLineNum++,
|
|
215
|
+
"+",
|
|
216
|
+
line,
|
|
217
|
+
"green",
|
|
218
|
+
`add-${changeIndex}-${i}-${lineIndex}`,
|
|
219
|
+
),
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
} else {
|
|
223
|
+
// Context lines - show unchanged content
|
|
224
|
+
const isFirstBlock = i === 0;
|
|
225
|
+
const isLastBlock = i === lineDiffs.length - 1;
|
|
242
226
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
const skipCount = lines.length - 3;
|
|
247
|
-
oldLineNum += skipCount;
|
|
248
|
-
newLineNum += skipCount;
|
|
249
|
-
linesToDisplay = lines.slice(-3);
|
|
250
|
-
showEllipsisTop = true;
|
|
251
|
-
}
|
|
252
|
-
} else if (isLastBlock && !isFirstBlock) {
|
|
253
|
-
// Last block: keep first 3
|
|
254
|
-
if (lines.length > 3) {
|
|
255
|
-
linesToDisplay = lines.slice(0, 3);
|
|
256
|
-
showEllipsisBottom = true;
|
|
257
|
-
}
|
|
258
|
-
} else if (!isFirstBlock && !isLastBlock) {
|
|
259
|
-
// Middle block: keep first 3 and last 3
|
|
260
|
-
if (lines.length > 6) {
|
|
261
|
-
linesToDisplay = [...lines.slice(0, 3), ...lines.slice(-3)];
|
|
262
|
-
showEllipsisTop = false; // We'll put ellipsis in the middle
|
|
263
|
-
}
|
|
264
|
-
}
|
|
227
|
+
let linesToDisplay = lines;
|
|
228
|
+
let showEllipsisTop = false;
|
|
229
|
+
let showEllipsisBottom = false;
|
|
265
230
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
231
|
+
if (isFirstBlock && !isLastBlock) {
|
|
232
|
+
// First block: keep last 3
|
|
233
|
+
if (lines.length > 3) {
|
|
234
|
+
const skipCount = lines.length - 3;
|
|
235
|
+
oldLineNum += skipCount;
|
|
236
|
+
newLineNum += skipCount;
|
|
237
|
+
linesToDisplay = lines.slice(-3);
|
|
238
|
+
showEllipsisTop = true;
|
|
272
239
|
}
|
|
240
|
+
} else if (isLastBlock && !isFirstBlock) {
|
|
241
|
+
// Last block: keep first 3
|
|
242
|
+
if (lines.length > 3) {
|
|
243
|
+
linesToDisplay = lines.slice(0, 3);
|
|
244
|
+
showEllipsisBottom = true;
|
|
245
|
+
}
|
|
246
|
+
} else if (!isFirstBlock && !isLastBlock) {
|
|
247
|
+
// Middle block: keep first 3 and last 3
|
|
248
|
+
if (lines.length > 6) {
|
|
249
|
+
linesToDisplay = [...lines.slice(0, 3), ...lines.slice(-3)];
|
|
250
|
+
showEllipsisTop = false; // We'll put ellipsis in the middle
|
|
251
|
+
}
|
|
252
|
+
}
|
|
273
253
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
) {
|
|
282
|
-
const skipCount = lines.length - 6;
|
|
283
|
-
oldLineNum += skipCount;
|
|
284
|
-
newLineNum += skipCount;
|
|
285
|
-
diffElements.push(
|
|
286
|
-
<Box key={`ellipsis-mid-${changeIndex}-${i}`}>
|
|
287
|
-
<Text color="gray">
|
|
288
|
-
{" ".repeat(maxDigits * 2 + 2)}...
|
|
289
|
-
</Text>
|
|
290
|
-
</Box>,
|
|
291
|
-
);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
diffElements.push(
|
|
295
|
-
renderLine(
|
|
296
|
-
oldLineNum++,
|
|
297
|
-
newLineNum++,
|
|
298
|
-
" ",
|
|
299
|
-
line,
|
|
300
|
-
"white",
|
|
301
|
-
`context-${changeIndex}-${i}-${lineIndex}`,
|
|
302
|
-
),
|
|
303
|
-
);
|
|
304
|
-
});
|
|
254
|
+
if (showEllipsisTop) {
|
|
255
|
+
diffElements.push(
|
|
256
|
+
<Box key={`ellipsis-top-${changeIndex}-${i}`}>
|
|
257
|
+
<Text color="gray">{" ".repeat(maxDigits * 2 + 2)}...</Text>
|
|
258
|
+
</Box>,
|
|
259
|
+
);
|
|
260
|
+
}
|
|
305
261
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
262
|
+
linesToDisplay.forEach((line, lineIndex) => {
|
|
263
|
+
// If it's a middle block and we are at the split point
|
|
264
|
+
if (
|
|
265
|
+
!isFirstBlock &&
|
|
266
|
+
!isLastBlock &&
|
|
267
|
+
lines.length > 6 &&
|
|
268
|
+
lineIndex === 3
|
|
269
|
+
) {
|
|
270
|
+
const skipCount = lines.length - 6;
|
|
310
271
|
oldLineNum += skipCount;
|
|
311
272
|
newLineNum += skipCount;
|
|
312
273
|
diffElements.push(
|
|
313
|
-
<Box key={`ellipsis-
|
|
274
|
+
<Box key={`ellipsis-mid-${changeIndex}-${i}`}>
|
|
314
275
|
<Text color="gray">{" ".repeat(maxDigits * 2 + 2)}...</Text>
|
|
315
276
|
</Box>,
|
|
316
277
|
);
|
|
317
278
|
}
|
|
279
|
+
|
|
280
|
+
diffElements.push(
|
|
281
|
+
renderLine(
|
|
282
|
+
oldLineNum++,
|
|
283
|
+
newLineNum++,
|
|
284
|
+
" ",
|
|
285
|
+
line,
|
|
286
|
+
"white",
|
|
287
|
+
`context-${changeIndex}-${i}-${lineIndex}`,
|
|
288
|
+
),
|
|
289
|
+
);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
if (showEllipsisBottom) {
|
|
293
|
+
const skipCount = lines.length - linesToDisplay.length;
|
|
294
|
+
// We don't increment oldLineNum/newLineNum here because they are already incremented in the loop
|
|
295
|
+
// But we need to account for the lines we skipped at the end of this block
|
|
296
|
+
oldLineNum += skipCount;
|
|
297
|
+
newLineNum += skipCount;
|
|
298
|
+
diffElements.push(
|
|
299
|
+
<Box key={`ellipsis-bottom-${changeIndex}-${i}`}>
|
|
300
|
+
<Text color="gray">{" ".repeat(maxDigits * 2 + 2)}...</Text>
|
|
301
|
+
</Box>,
|
|
302
|
+
);
|
|
318
303
|
}
|
|
319
304
|
}
|
|
320
|
-
allElements.push(...diffElements);
|
|
321
|
-
} catch (error) {
|
|
322
|
-
console.warn(
|
|
323
|
-
`Error rendering diff for change ${changeIndex}:`,
|
|
324
|
-
error,
|
|
325
|
-
);
|
|
326
|
-
// Fallback to simple display
|
|
327
|
-
allElements.push(
|
|
328
|
-
<Box key={`fallback-${changeIndex}`} flexDirection="column">
|
|
329
|
-
<Text color="red">-{change.oldContent || ""}</Text>
|
|
330
|
-
<Text color="green">+{change.newContent || ""}</Text>
|
|
331
|
-
</Box>,
|
|
332
|
-
);
|
|
333
305
|
}
|
|
334
|
-
|
|
306
|
+
allElements.push(...diffElements);
|
|
307
|
+
} catch (error) {
|
|
308
|
+
console.warn(`Error rendering diff for change ${changeIndex}:`, error);
|
|
309
|
+
// Fallback to simple display
|
|
310
|
+
allElements.push(
|
|
311
|
+
<Box key={`fallback-${changeIndex}`} flexDirection="column">
|
|
312
|
+
<Text color="red">-{change.oldContent || ""}</Text>
|
|
313
|
+
<Text color="green">+{change.newContent || ""}</Text>
|
|
314
|
+
</Box>,
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
});
|
|
335
318
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
319
|
+
return allElements;
|
|
320
|
+
} catch (error) {
|
|
321
|
+
console.warn("Error rendering expanded diff:", error);
|
|
322
|
+
return [
|
|
323
|
+
<Box key="diff-error">
|
|
324
|
+
<Text color="gray">Error rendering diff display</Text>
|
|
325
|
+
</Box>,
|
|
326
|
+
];
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Convenience wrapper used by both <DiffDisplay> and ConfirmationDetails:
|
|
332
|
+
* transforms the raw tool parameters into change rows (empty array when the
|
|
333
|
+
* tool doesn't produce a diff).
|
|
334
|
+
*/
|
|
335
|
+
export function buildDiffLinesFromParams(params: {
|
|
336
|
+
toolName?: string;
|
|
337
|
+
parameters?: string;
|
|
338
|
+
startLineNumber?: number;
|
|
339
|
+
}): React.ReactNode[] {
|
|
340
|
+
const { toolName, parameters, startLineNumber } = params;
|
|
341
|
+
if (
|
|
342
|
+
!toolName ||
|
|
343
|
+
![WRITE_TOOL_NAME, EDIT_TOOL_NAME].includes(toolName) ||
|
|
344
|
+
!parameters
|
|
345
|
+
) {
|
|
346
|
+
return [];
|
|
347
|
+
}
|
|
348
|
+
let changes: Change[] = [];
|
|
349
|
+
try {
|
|
350
|
+
changes = transformToolBlockToChanges(
|
|
351
|
+
toolName,
|
|
352
|
+
parameters,
|
|
353
|
+
startLineNumber,
|
|
354
|
+
);
|
|
355
|
+
} catch (error) {
|
|
356
|
+
console.warn("Error transforming tool block to changes:", error);
|
|
357
|
+
return [];
|
|
358
|
+
}
|
|
359
|
+
return buildDiffLines(changes);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export const DiffDisplay = ({
|
|
363
|
+
toolName,
|
|
364
|
+
parameters,
|
|
365
|
+
startLineNumber,
|
|
366
|
+
asLines = false,
|
|
367
|
+
}: DiffDisplayProps): React.ReactNode => {
|
|
368
|
+
const showDiff =
|
|
369
|
+
toolName && [WRITE_TOOL_NAME, EDIT_TOOL_NAME].includes(toolName);
|
|
370
|
+
|
|
371
|
+
// Diff detection and transformation using typed parameters
|
|
372
|
+
const diffLines = useMemo(
|
|
373
|
+
() => buildDiffLinesFromParams({ toolName, parameters, startLineNumber }),
|
|
374
|
+
[toolName, parameters, startLineNumber],
|
|
375
|
+
);
|
|
346
376
|
|
|
347
377
|
// Don't render anything if no diff should be shown
|
|
348
378
|
if (!showDiff) {
|
|
349
|
-
return null;
|
|
379
|
+
return asLines ? [] : null;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (asLines) {
|
|
383
|
+
return diffLines;
|
|
350
384
|
}
|
|
351
385
|
|
|
352
386
|
return (
|
|
353
387
|
<Box flexDirection="column">
|
|
354
388
|
<Box paddingLeft={2} borderLeft borderColor="cyan" flexDirection="column">
|
|
355
|
-
{
|
|
389
|
+
<Box flexDirection="column">{diffLines}</Box>
|
|
356
390
|
</Box>
|
|
357
391
|
</Box>
|
|
358
392
|
);
|