vzcode 1.47.0 → 1.49.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/dist/assets/{index-BMYXp1Uw.js → index-DrUY_A13.js} +60 -60
- package/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/client/App/index.tsx +1 -0
- package/src/client/SplitPaneResizeContext.tsx +1 -1
- package/src/client/VZCodeContext.tsx +4 -0
- package/src/client/VZSidebar/AIChat/DiffView.tsx +6 -3
- package/src/client/VZSidebar/index.tsx +23 -23
- package/src/client/vzReducer/createInitialState.ts +1 -1
- package/src/server/aiChatHandler/undoHandler.ts +97 -0
- package/src/server/handleAIChatUndo.ts +2 -0
- package/src/server/index.ts +4 -46
package/dist/index.html
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap"
|
|
21
21
|
rel="stylesheet"
|
|
22
22
|
/>
|
|
23
|
-
<script type="module" crossorigin src="/assets/index-
|
|
23
|
+
<script type="module" crossorigin src="/assets/index-DrUY_A13.js"></script>
|
|
24
24
|
<link rel="stylesheet" crossorigin href="/assets/index-BXyJ2hMf.css">
|
|
25
25
|
</head>
|
|
26
26
|
<body>
|
package/package.json
CHANGED
package/src/client/App/index.tsx
CHANGED
|
@@ -20,7 +20,7 @@ export type SplitPaneResizeContextValue = {
|
|
|
20
20
|
|
|
21
21
|
// Default widths for different sidebar views
|
|
22
22
|
const filesViewWidth = 300;
|
|
23
|
-
const aiChatViewWidth =
|
|
23
|
+
const aiChatViewWidth = 800;
|
|
24
24
|
const initialCodeEditorWidthDefault = 800;
|
|
25
25
|
|
|
26
26
|
const initialValue: SplitPaneResizeContextValue = {
|
|
@@ -129,6 +129,7 @@ export type VZCodeContextValue = {
|
|
|
129
129
|
aiChatMode: 'ask' | 'edit';
|
|
130
130
|
setAIChatMode: (mode: 'ask' | 'edit') => void;
|
|
131
131
|
aiChatEndpoint?: string;
|
|
132
|
+
aiChatUndoEndpoint?: string;
|
|
132
133
|
aiChatOptions?: { [key: string]: any };
|
|
133
134
|
setSearchResults: (files: ShareDBDoc<VizContent>) => void;
|
|
134
135
|
setSearchFileVisibility: (
|
|
@@ -215,6 +216,7 @@ export const VZCodeProvider = ({
|
|
|
215
216
|
liveKitConnection,
|
|
216
217
|
setLiveKitConnection,
|
|
217
218
|
aiChatEndpoint,
|
|
219
|
+
aiChatUndoEndpoint,
|
|
218
220
|
aiChatOptions,
|
|
219
221
|
}: {
|
|
220
222
|
content: VizContent;
|
|
@@ -235,6 +237,7 @@ export const VZCodeProvider = ({
|
|
|
235
237
|
liveKitConnection?: boolean;
|
|
236
238
|
setLiveKitConnection?: (state: boolean) => void;
|
|
237
239
|
aiChatEndpoint?: string;
|
|
240
|
+
aiChatUndoEndpoint?: string;
|
|
238
241
|
aiChatOptions?: { [key: string]: any };
|
|
239
242
|
}) => {
|
|
240
243
|
// Auto-run Pretter after local changes.
|
|
@@ -497,6 +500,7 @@ export const VZCodeProvider = ({
|
|
|
497
500
|
aiChatMode: state.aiChatMode,
|
|
498
501
|
setAIChatMode,
|
|
499
502
|
aiChatEndpoint,
|
|
503
|
+
aiChatUndoEndpoint,
|
|
500
504
|
aiChatOptions,
|
|
501
505
|
|
|
502
506
|
isSettingsOpen,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
1
|
+
import React, { useState, useContext } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
UnifiedFilesDiff,
|
|
4
4
|
parseUnifiedDiffStats,
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from '../../../utils/fileDiff';
|
|
7
7
|
import * as Diff2Html from 'diff2html';
|
|
8
8
|
import 'diff2html/bundles/css/diff2html.min.css';
|
|
9
|
+
import { VZCodeContext } from '../../VZCodeContext';
|
|
9
10
|
import './DiffView.scss';
|
|
10
11
|
|
|
11
12
|
interface DiffViewProps {
|
|
@@ -24,6 +25,7 @@ export const DiffView: React.FC<DiffViewProps> = ({
|
|
|
24
25
|
canUndo = false,
|
|
25
26
|
}) => {
|
|
26
27
|
const [isUndoing, setIsUndoing] = useState(false);
|
|
28
|
+
const { aiChatUndoEndpoint } = useContext(VZCodeContext);
|
|
27
29
|
|
|
28
30
|
const unifiedDiffs = Object.values(diffData).filter(
|
|
29
31
|
(diff) => diff.length > 0,
|
|
@@ -38,14 +40,15 @@ export const DiffView: React.FC<DiffViewProps> = ({
|
|
|
38
40
|
!messageId ||
|
|
39
41
|
!chatId ||
|
|
40
42
|
!beforeFiles ||
|
|
41
|
-
isUndoing
|
|
43
|
+
isUndoing ||
|
|
44
|
+
!aiChatUndoEndpoint
|
|
42
45
|
) {
|
|
43
46
|
return;
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
setIsUndoing(true);
|
|
47
50
|
try {
|
|
48
|
-
const response = await fetch(
|
|
51
|
+
const response = await fetch(aiChatUndoEndpoint, {
|
|
49
52
|
method: 'POST',
|
|
50
53
|
headers: {
|
|
51
54
|
'Content-Type': 'application/json',
|
|
@@ -298,6 +298,29 @@ export const VZSidebar = ({
|
|
|
298
298
|
tabIndex={-1}
|
|
299
299
|
>
|
|
300
300
|
<div className="sidebar-section-buttons">
|
|
301
|
+
{enableAIChat && (
|
|
302
|
+
<OverlayTrigger
|
|
303
|
+
placement="right"
|
|
304
|
+
overlay={
|
|
305
|
+
<Tooltip id="ai-chat-tooltip">
|
|
306
|
+
{aiChatToolTipText}
|
|
307
|
+
</Tooltip>
|
|
308
|
+
}
|
|
309
|
+
>
|
|
310
|
+
<i
|
|
311
|
+
id="ai-chat-icon"
|
|
312
|
+
className="icon-button icon-button-dark"
|
|
313
|
+
onClick={() => {
|
|
314
|
+
setIsAIChatOpen(true);
|
|
315
|
+
setIsSearchOpen(false);
|
|
316
|
+
setSidebarView(true); // Switch to AI chat view
|
|
317
|
+
}}
|
|
318
|
+
>
|
|
319
|
+
<SparklesSVG />
|
|
320
|
+
</i>
|
|
321
|
+
</OverlayTrigger>
|
|
322
|
+
)}
|
|
323
|
+
|
|
301
324
|
<OverlayTrigger
|
|
302
325
|
placement="right"
|
|
303
326
|
overlay={
|
|
@@ -340,29 +363,6 @@ export const VZSidebar = ({
|
|
|
340
363
|
</i>
|
|
341
364
|
</OverlayTrigger>
|
|
342
365
|
|
|
343
|
-
{enableAIChat && (
|
|
344
|
-
<OverlayTrigger
|
|
345
|
-
placement="right"
|
|
346
|
-
overlay={
|
|
347
|
-
<Tooltip id="ai-chat-tooltip">
|
|
348
|
-
{aiChatToolTipText}
|
|
349
|
-
</Tooltip>
|
|
350
|
-
}
|
|
351
|
-
>
|
|
352
|
-
<i
|
|
353
|
-
id="ai-chat-icon"
|
|
354
|
-
className="icon-button icon-button-dark"
|
|
355
|
-
onClick={() => {
|
|
356
|
-
setIsAIChatOpen(true);
|
|
357
|
-
setIsSearchOpen(false);
|
|
358
|
-
setSidebarView(true); // Switch to AI chat view
|
|
359
|
-
}}
|
|
360
|
-
>
|
|
361
|
-
<SparklesSVG />
|
|
362
|
-
</i>
|
|
363
|
-
</OverlayTrigger>
|
|
364
|
-
)}
|
|
365
|
-
|
|
366
366
|
<OverlayTrigger
|
|
367
367
|
placement="right"
|
|
368
368
|
overlay={
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { undoAIEdit } from './chatOperations.js';
|
|
2
|
+
import { handleError } from './errorHandling.js';
|
|
3
|
+
import { ShareDBDoc } from '../../types.js';
|
|
4
|
+
import { VizContent } from '@vizhub/viz-types';
|
|
5
|
+
|
|
6
|
+
const DEBUG = false;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Validates incoming request data for AI chat undo
|
|
10
|
+
*/
|
|
11
|
+
const validateUndoRequest = (req, res) => {
|
|
12
|
+
const { chatId, messageId } = req.body;
|
|
13
|
+
|
|
14
|
+
if (!chatId || typeof chatId !== 'string') {
|
|
15
|
+
res.status(400).json({
|
|
16
|
+
error:
|
|
17
|
+
'Invalid request: chatId is required and must be a string',
|
|
18
|
+
});
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!messageId || typeof messageId !== 'string') {
|
|
23
|
+
res.status(400).json({
|
|
24
|
+
error:
|
|
25
|
+
'Invalid request: messageId is required and must be a string',
|
|
26
|
+
});
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return true;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const handleAIChatUndo =
|
|
34
|
+
({
|
|
35
|
+
shareDBDoc,
|
|
36
|
+
}: {
|
|
37
|
+
shareDBDoc: ShareDBDoc<VizContent>;
|
|
38
|
+
}) =>
|
|
39
|
+
async (req: any, res: any) => {
|
|
40
|
+
const { chatId, messageId } = req.body;
|
|
41
|
+
|
|
42
|
+
if (DEBUG) {
|
|
43
|
+
console.log(
|
|
44
|
+
'[handleAIChatUndo] chatId:',
|
|
45
|
+
chatId,
|
|
46
|
+
'messageId:',
|
|
47
|
+
messageId,
|
|
48
|
+
'shareDBDoc:',
|
|
49
|
+
shareDBDoc,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Validate request
|
|
54
|
+
if (!validateUndoRequest(req, res)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const chat = shareDBDoc.data.chats?.[chatId];
|
|
60
|
+
if (!chat) {
|
|
61
|
+
res.status(404).json({
|
|
62
|
+
error: 'Chat not found',
|
|
63
|
+
});
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const message = chat.messages.find(
|
|
68
|
+
(msg) => msg.id === messageId,
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
if (
|
|
72
|
+
!message ||
|
|
73
|
+
message.role !== 'assistant' ||
|
|
74
|
+
!(message as any).beforeFiles
|
|
75
|
+
) {
|
|
76
|
+
res.status(400).json({
|
|
77
|
+
error: 'Invalid message for undo',
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Perform the undo operation
|
|
83
|
+
undoAIEdit(
|
|
84
|
+
shareDBDoc,
|
|
85
|
+
chatId,
|
|
86
|
+
messageId,
|
|
87
|
+
(message as any).beforeFiles,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
res.status(200).json({ success: true });
|
|
91
|
+
} catch (error) {
|
|
92
|
+
if (DEBUG) {
|
|
93
|
+
console.error('[handleAIChatUndo] Error:', error);
|
|
94
|
+
}
|
|
95
|
+
handleError(shareDBDoc, chatId, error, res);
|
|
96
|
+
}
|
|
97
|
+
};
|
package/src/server/index.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { computeInitialDocument } from './computeInitialDocument.js';
|
|
|
14
14
|
import { handleAIAssist } from './handleAIAssist.js';
|
|
15
15
|
import { handleAICopilot } from './handleAICopilot.js';
|
|
16
16
|
import { handleAIChatMessage } from './handleAIChatMessage.js';
|
|
17
|
-
import {
|
|
17
|
+
import { handleAIChatUndo } from './handleAIChatUndo.js';
|
|
18
18
|
import { isDirectory } from './isDirectory.js';
|
|
19
19
|
import { createToken } from './livekit.js';
|
|
20
20
|
import './setupEnv.js';
|
|
@@ -146,51 +146,9 @@ app.post(
|
|
|
146
146
|
app.post(
|
|
147
147
|
'/ai-chat-undo',
|
|
148
148
|
bodyParser.json(),
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (!chatId || !messageId) {
|
|
153
|
-
return res
|
|
154
|
-
.status(400)
|
|
155
|
-
.json({ error: 'Missing chatId or messageId' });
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
try {
|
|
159
|
-
const chat = shareDBDoc.data.chats?.[chatId];
|
|
160
|
-
if (!chat) {
|
|
161
|
-
return res
|
|
162
|
-
.status(404)
|
|
163
|
-
.json({ error: 'Chat not found' });
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const message = chat.messages.find(
|
|
167
|
-
(msg) => msg.id === messageId,
|
|
168
|
-
);
|
|
169
|
-
if (
|
|
170
|
-
!message ||
|
|
171
|
-
message.role !== 'assistant' ||
|
|
172
|
-
!message.beforeFiles
|
|
173
|
-
) {
|
|
174
|
-
return res
|
|
175
|
-
.status(400)
|
|
176
|
-
.json({ error: 'Invalid message for undo' });
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
undoAIEdit(
|
|
180
|
-
shareDBDoc,
|
|
181
|
-
chatId,
|
|
182
|
-
messageId,
|
|
183
|
-
message.beforeFiles,
|
|
184
|
-
);
|
|
185
|
-
|
|
186
|
-
res.status(200).json({ success: true });
|
|
187
|
-
} catch (error) {
|
|
188
|
-
console.error('Error undoing AI edit:', error);
|
|
189
|
-
res
|
|
190
|
-
.status(500)
|
|
191
|
-
.json({ error: 'Failed to undo edit' });
|
|
192
|
-
}
|
|
193
|
-
},
|
|
149
|
+
handleAIChatUndo({
|
|
150
|
+
shareDBDoc,
|
|
151
|
+
}),
|
|
194
152
|
);
|
|
195
153
|
|
|
196
154
|
// Livekit Token Generator
|