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/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-BMYXp1Uw.js"></script>
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vzcode",
3
- "version": "1.47.0",
3
+ "version": "1.49.0",
4
4
  "description": "Multiplayer code editor system",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -118,6 +118,7 @@ function App() {
118
118
  liveKitConnection={liveKitConnection}
119
119
  setLiveKitConnection={setLiveKitConnection}
120
120
  aiChatEndpoint="/ai-chat-message"
121
+ aiChatUndoEndpoint="/ai-chat-undo"
121
122
  aiChatOptions={{}}
122
123
  >
123
124
  <LiveKitRoom
@@ -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 = 600;
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('/ai-chat-undo', {
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={
@@ -25,7 +25,7 @@ export const createInitialState = ({
25
25
  focusedChildIndex: null,
26
26
  },
27
27
  isSearchOpen: false,
28
- isAIChatOpen: false,
28
+ isAIChatOpen: true,
29
29
  aiChatFocused: false,
30
30
  aiChatMode: 'edit',
31
31
  isSettingsOpen: false,
@@ -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
+ };
@@ -0,0 +1,2 @@
1
+ // Re-export the handleAIChatUndo from the new modular structure
2
+ export { handleAIChatUndo } from './aiChatHandler/undoHandler.js';
@@ -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 { undoAIEdit } from './aiChatHandler/chatOperations.js';
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
- async (req, res) => {
150
- const { chatId, messageId } = req.body;
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