vzcode 2.7.0 → 2.9.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.
Files changed (41) hide show
  1. package/dist/assets/{buildWorker-wLkQ0yz1.js → buildWorker-D4WATavZ.js} +27 -27
  2. package/dist/assets/{index-DL2VQRps.js → index-C_mFOLqJ.js} +175 -176
  3. package/dist/cli.js +0 -2
  4. package/dist/index.html +1 -1
  5. package/dist/server/aiChatHandler/chatOperations.js +1 -1
  6. package/dist/server/computeInitialDocument.js +1 -1
  7. package/dist/server/index.js +2 -2
  8. package/package.json +10 -3
  9. package/src/cli.ts +0 -3
  10. package/src/client/AIAssist/AIAssistCodeMirrorKeyMap.ts +4 -4
  11. package/src/client/AIAssist/startAIAssist.ts +1 -7
  12. package/src/client/App/useShareDB.ts +1 -1
  13. package/src/client/CodeEditor/InteractiveWidgets/rotateWidget.ts +1 -1
  14. package/src/client/CodeEditor/getOrCreateEditor.tsx +5 -15
  15. package/src/client/CodeEditor/index.tsx +4 -3
  16. package/src/client/CodeEditor/rainbowBrackets.ts +0 -1
  17. package/src/client/CodeErrorOverlay/index.tsx +1 -1
  18. package/src/client/RunCodeWidget/index.tsx +1 -1
  19. package/src/client/SplitPaneResizeContext.tsx +0 -1
  20. package/src/client/VZCodeContext/useVZCodeState.ts +30 -17
  21. package/src/client/VZKeyboardShortcutsDoc.tsx +3 -18
  22. package/src/client/VZMiddle.tsx +0 -6
  23. package/src/client/VZSidebar/AIChat/DiffView.tsx +6 -28
  24. package/src/client/VZSidebar/AIChat/Message.tsx +1 -6
  25. package/src/client/VZSidebar/AIChat/MessageList.tsx +1 -3
  26. package/src/client/VZSidebar/AIChat/useSpeechRecognition.ts +1 -2
  27. package/src/client/VZSidebar/DirectoryListing.tsx +0 -1
  28. package/src/client/VZSidebar/VisualEditor.tsx +3 -3
  29. package/src/client/VZSidebar/VoiceChatModal.tsx +0 -1
  30. package/src/client/VZSidebar/aiCopyPaste.ts +0 -2
  31. package/src/client/index.ts +4 -1
  32. package/src/client/useFileCRUD.ts +0 -1
  33. package/src/client/useKeyboardShortcuts.ts +6 -2
  34. package/src/client/vzReducer/closeTabsReducer.ts +1 -1
  35. package/src/client/vzReducer/createInitialState.test.ts +25 -0
  36. package/src/client/vzReducer/createInitialState.ts +1 -1
  37. package/src/client/vzReducer/searchReducer.test.ts +16 -16
  38. package/src/client/vzReducer/searchReducer.ts +2 -2
  39. package/src/server/aiChatHandler/chatOperations.ts +1 -4
  40. package/src/server/computeInitialDocument.ts +1 -1
  41. package/src/server/index.ts +2 -2
package/dist/cli.js CHANGED
@@ -75,8 +75,6 @@ function startServerInBackground(workingDirectory) {
75
75
  }
76
76
  // Fallback function to launch the browser version
77
77
  async function launchBrowserVersion(workingDirectory) {
78
- const { default: open } = await import('open');
79
- const serverModule = await import('./server/index.js');
80
78
  // Note: The server/index.js will use process.cwd() automatically
81
79
  // and we're already in the correct working directory
82
80
  console.log(`Starting VZCode server from: ${workingDirectory}`);
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-DL2VQRps.js"></script>
23
+ <script type="module" crossorigin src="/assets/index-C_mFOLqJ.js"></script>
24
24
  <link rel="stylesheet" crossorigin href="/assets/index-Bjj9VRMn.css">
25
25
  </head>
26
26
  <body>
@@ -1,4 +1,4 @@
1
- import { dateToTimestamp, } from '@vizhub/viz-utils';
1
+ import { dateToTimestamp } from '@vizhub/viz-utils';
2
2
  import { randomId } from '../../randomId.js';
3
3
  import { diff } from '../../ot.js';
4
4
  /**
@@ -65,7 +65,7 @@ export const computeInitialDocument = ({ fullPath }) => {
65
65
  * Stack for recursively traversing directories.
66
66
  * @type {string[]}
67
67
  */
68
- let files = [];
68
+ const files = [];
69
69
  const ignoreFileMatcher = createIgnore().add(ignoreFilePattern);
70
70
  const isIgnoreFile = (fileName) => ignoreFileMatcher.ignores(fileName);
71
71
  const unsearchedDirectories = [
@@ -191,7 +191,7 @@ const save = () => {
191
191
  }
192
192
  // handle deleting files and directories.
193
193
  if (previous && !current) {
194
- let stats = fs.statSync(previous.name);
194
+ const stats = fs.statSync(previous.name);
195
195
  //Check if the file path we are trying to delete is a directory
196
196
  if (!stats.isDirectory()) {
197
197
  fs.unlinkSync(previous.name);
@@ -290,7 +290,7 @@ server.listen(port, async () => {
290
290
  // Note: ngrok support can be added when the package is properly installed
291
291
  // Sets the port to the one specified in the environment
292
292
  // variable (for development) or the default port.
293
- let livePort = process.env.EDITOR_PORT || port;
293
+ const livePort = process.env.EDITOR_PORT || port;
294
294
  console.log(`EDITOR_PORT: ${process.env.EDITOR_PORT}`);
295
295
  console.log(`Editor is live at http://localhost:${livePort}`);
296
296
  open(`http://localhost:${livePort}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vzcode",
3
- "version": "2.7.0",
3
+ "version": "2.9.0",
4
4
  "description": "Multiplayer code editor system",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -14,6 +14,8 @@
14
14
  "test-interactive": "cd test/sampleDirectories/visualEditor && node --import \"data:text/javascript,import { register } from 'node:module'; import { pathToFileURL } from 'node:url'; register('ts-node/esm', pathToFileURL('./'));\" ../../../src/server/index.ts",
15
15
  "prettier": "prettier {*.*,**/*.*} --write",
16
16
  "typecheck": "tsc --noEmit",
17
+ "lint": "eslint . --ext .js,.ts,.tsx",
18
+ "lint:fix": "eslint . --ext .js,.ts,.tsx --fix",
17
19
  "dev": "cross-env EDITOR_PORT=5173 concurrently \"npm run test-interactive\" \"vite\"",
18
20
  "build": "vite build && npm run build:server",
19
21
  "build:server": "tsc --project tsconfig.server.json",
@@ -118,7 +120,7 @@
118
120
  "@codemirror/state": "^6.5.2",
119
121
  "@codemirror/theme-one-dark": "^6.1.3",
120
122
  "@codemirror/view": "^6.38.1",
121
- "@langchain/core": "^0.3.70",
123
+ "@langchain/core": "^0.3.71",
122
124
  "@langchain/openai": "^0.6.7",
123
125
  "@lezer/highlight": "^1.2.1",
124
126
  "@livekit/components-react": "^2.9.14",
@@ -169,7 +171,7 @@
169
171
  "react-bootstrap": "^2.10.10",
170
172
  "react-dom": "^18",
171
173
  "react-markdown": "^10.1.0",
172
- "react-router-dom": "^7.8.0",
174
+ "react-router-dom": "^7.8.1",
173
175
  "remark-gfm": "^4.0.1",
174
176
  "sharedb": "^5.2.2",
175
177
  "sharedb-client-browser": "^5.2.2",
@@ -182,10 +184,15 @@
182
184
  "@tauri-apps/cli": "^2.7.1",
183
185
  "@types/react": "^18",
184
186
  "@types/react-dom": "^18",
187
+ "@typescript-eslint/eslint-plugin": "^8.39.1",
188
+ "@typescript-eslint/parser": "^8.39.1",
185
189
  "@vitejs/plugin-react": "^5.0.0",
186
190
  "concurrently": "^9.2.0",
187
191
  "cross-env": "^10.0.0",
188
192
  "eslint": "^9.33.0",
193
+ "eslint-plugin-jsx-a11y": "^6.10.2",
194
+ "eslint-plugin-react": "^7.37.5",
195
+ "eslint-plugin-react-hooks": "^5.2.0",
189
196
  "globals": "^16.3.0",
190
197
  "npm-check-updates": "^18.0.2",
191
198
  "prettier": "^3.6.2",
package/src/cli.ts CHANGED
@@ -153,9 +153,6 @@ function startServerInBackground(
153
153
  async function launchBrowserVersion(
154
154
  workingDirectory: string,
155
155
  ): Promise<void> {
156
- const { default: open } = await import('open');
157
- const serverModule = await import('./server/index.js');
158
-
159
156
  // Note: The server/index.js will use process.cwd() automatically
160
157
  // and we're already in the correct working directory
161
158
  console.log(
@@ -3,9 +3,9 @@ import { ShareDBDoc, TabState } from '../../types';
3
3
  import { VizContent } from '@vizhub/viz-types';
4
4
 
5
5
  export const AIAssistCodeMirrorKeyMap = ({
6
- shareDBDoc,
7
- fileId,
8
- tabList,
6
+ shareDBDoc: _shareDBDoc,
7
+ fileId: _fileId,
8
+ tabList: _tabList,
9
9
  }: {
10
10
  shareDBDoc: ShareDBDoc<VizContent>;
11
11
  fileId: string;
@@ -14,7 +14,7 @@ export const AIAssistCodeMirrorKeyMap = ({
14
14
  keymap.of([
15
15
  {
16
16
  key: 'control-m',
17
- run: (view: EditorView) => {
17
+ run: (_view: EditorView) => {
18
18
  // if (
19
19
  // shareDBDoc.data.aiStreams === undefined ||
20
20
  // shareDBDoc.data.aiStreams[mostRecentStreamId] ===
@@ -1,15 +1,9 @@
1
1
  import { EditorView } from 'codemirror';
2
2
  import { ShareDBDoc, TabState } from '../../types';
3
- import {
4
- VizFile,
5
- VizFileId,
6
- VizContent,
7
- } from '@vizhub/viz-types';
3
+ import { VizFileId, VizContent } from '@vizhub/viz-types';
8
4
  import { RequestId } from '../generateRequestId';
9
5
  import { formatFile } from './formatFile';
10
6
 
11
- const debug = false;
12
-
13
7
  // Enables inclusion of code from open tabs as context.
14
8
  const enableTabContext = false;
15
9
 
@@ -1,4 +1,4 @@
1
- import { useEffect, useState, useRef } from 'react';
1
+ import { useEffect, useState } from 'react';
2
2
  import { randomId } from '../../randomId';
3
3
  import { ShareDBDoc } from '../../types';
4
4
  import { VizContent } from '@vizhub/viz-types';
@@ -94,7 +94,7 @@ class RotationCircle extends WidgetType {
94
94
  this.angle = angle;
95
95
  }
96
96
 
97
- toDOM(view: EditorView): HTMLElement {
97
+ toDOM(_view: EditorView): HTMLElement {
98
98
  const parent = document.createElement('div');
99
99
 
100
100
  parent.setAttribute('style', 'width:20px;height:20px');
@@ -24,12 +24,7 @@ import {
24
24
  } from '@codemirror/lint';
25
25
 
26
26
  import { json1Presence, textUnicode } from '../../ot';
27
- import {
28
- PaneId,
29
- ShareDBDoc,
30
- TabState,
31
- Username,
32
- } from '../../types';
27
+ import { PaneId, ShareDBDoc, Username } from '../../types';
33
28
  import { VizFileId, VizContent } from '@vizhub/viz-types';
34
29
  import { json1PresenceBroadcast } from './json1PresenceBroadcast';
35
30
  import { json1PresenceDisplay } from './json1PresenceDisplay';
@@ -72,9 +67,6 @@ import {
72
67
  } from '@valtown/codemirror-ts';
73
68
  import { getFileExtension } from '../utils/fileExtension';
74
69
  import { SparklesSVG } from '../Icons/SparklesSVG';
75
- import { VZCodeContext } from '../VZCodeContext';
76
- import { useContext, useMemo } from 'react';
77
- import { handleAIChatMessage } from '../../server/aiChatHandler';
78
70
 
79
71
  const DEBUG = false;
80
72
 
@@ -83,7 +75,7 @@ const DEBUG = false;
83
75
  export const fileNameStateField = StateField.define<string>(
84
76
  {
85
77
  create: () => '', // Default initial value
86
- update: (value, tr) => value, // Typically set once at creation for a given editor instance
78
+ update: (value, _tr) => value, // Typically set once at creation for a given editor instance
87
79
  },
88
80
  );
89
81
 
@@ -194,7 +186,6 @@ export const getOrCreateEditor = async ({
194
186
  esLintSource,
195
187
  rainbowBracketsEnabled = true,
196
188
  setIsAIChatOpen,
197
- setAIChatMessage,
198
189
  handleSendMessage,
199
190
  }: {
200
191
  // TODO pass this in from the outside
@@ -232,7 +223,6 @@ export const getOrCreateEditor = async ({
232
223
  ) => Promise<readonly Diagnostic[]>;
233
224
  rainbowBracketsEnabled?: boolean; // New parameter type
234
225
  setIsAIChatOpen: (isAIChatOpen: boolean) => void;
235
- setAIChatMessage: (message: string) => void;
236
226
  handleSendMessage: any; // TODO fix types
237
227
  }): Promise<ExtendedEditorCacheValue> => {
238
228
  // Cache hit
@@ -258,10 +248,10 @@ export const getOrCreateEditor = async ({
258
248
 
259
249
  // Create a compartment for the theme so that it can be changed dynamically.
260
250
  // Inspired by: https://github.com/craftzdog/cm6-themes/blob/main/example/index.ts
261
- let themeCompartment = new Compartment();
251
+ const themeCompartment = new Compartment();
262
252
 
263
253
  // Create a compartment for rainbow brackets so that it can be enabled/disabled dynamically.
264
- let rainbowBracketsCompartment = new Compartment();
254
+ const rainbowBracketsCompartment = new Compartment();
265
255
 
266
256
  // The CodeMirror extensions to use.
267
257
  // const extensions = [autocompletion(), html(htmlConfig)]
@@ -485,7 +475,7 @@ export const getOrCreateEditor = async ({
485
475
  super();
486
476
  }
487
477
 
488
- eq(other: ToDoWidget) {
478
+ eq(_other: ToDoWidget) {
489
479
  return false;
490
480
  }
491
481
 
@@ -44,7 +44,6 @@ export const CodeEditor = ({
44
44
  codeEditorRef,
45
45
  enableAutoFollow,
46
46
  setIsAIChatOpen,
47
- setAIChatMessage,
48
47
  handleSendMessage,
49
48
  } = useContext(VZCodeContext);
50
49
 
@@ -71,7 +70,10 @@ export const CodeEditor = ({
71
70
 
72
71
  // This logic deletes the `isInteracting` property from the document
73
72
  submitOperation(
74
- ({ isInteracting, ...newDocument }) => ({
73
+ ({
74
+ isInteracting: _isInteracting,
75
+ ...newDocument
76
+ }) => ({
75
77
  ...newDocument,
76
78
  }),
77
79
  );
@@ -116,7 +118,6 @@ export const CodeEditor = ({
116
118
  aiCopilotEndpoint,
117
119
  esLintSource,
118
120
  setIsAIChatOpen,
119
- setAIChatMessage,
120
121
  handleSendMessage,
121
122
  });
122
123
 
@@ -80,7 +80,6 @@ const rainbowBracketsPlugin = ViewPlugin.fromClass(
80
80
  return Decoration.set(decorations);
81
81
  }
82
82
 
83
- // eslint-disable-next-line class-methods-use-this
84
83
  getMatchingBracket(closingBracket) {
85
84
  switch (closingBracket) {
86
85
  case ')':
@@ -7,7 +7,7 @@ const enableErrorDismiss = true;
7
7
 
8
8
  export const CodeErrorOverlay = ({
9
9
  errorMessage,
10
- content,
10
+ content: _content,
11
11
  }: {
12
12
  errorMessage: string | null;
13
13
  content: VizContent;
@@ -29,7 +29,7 @@ export const RunCodeWidget = ({
29
29
  const [isRunning, setIsRunning] = useState(false);
30
30
 
31
31
  const handleClick = useCallback(
32
- (event?: React.MouseEvent) => {
32
+ (_event?: React.MouseEvent) => {
33
33
  setIsRunning(true); // Set the running state to true
34
34
 
35
35
  // Run Prettier
@@ -3,7 +3,6 @@ import {
3
3
  createContext,
4
4
  useReducer,
5
5
  useCallback,
6
- useEffect,
7
6
  } from 'react';
8
7
 
9
8
  export type Side = 'left' | 'right';
@@ -6,7 +6,6 @@ import {
6
6
  useRef,
7
7
  useState,
8
8
  } from 'react';
9
- import { VizContent } from '@vizhub/viz-types';
10
9
  import { defaultTheme, useDynamicTheme } from '../themes';
11
10
  import { useActions } from '../useActions';
12
11
  import { useEditorCache } from '../useEditorCache';
@@ -77,9 +76,10 @@ export const useVZCodeState = ({
77
76
  const sidebarRef = useRef(null);
78
77
 
79
78
  const codeEditorRef = useRef(null);
79
+ const internalIframeRef = useRef(null);
80
80
 
81
- // Use external iframeRef if provided, otherwise create our own
82
- const iframeRef = externalIframeRef || useRef(null);
81
+ // Use external iframeRef if provided, otherwise use internal one
82
+ const iframeRef = externalIframeRef || internalIframeRef;
83
83
 
84
84
  // The error message shows errors in order of priority:
85
85
  // * `runtimeError` - errors from runtime execution, highest priority
@@ -423,18 +423,31 @@ export const useVZCodeState = ({
423
423
  errorMessage ===
424
424
  'You do not have permission to use AI chat on this visualization. Only users with edit access can use this feature. Fork the viz to edit it.'
425
425
  ) {
426
- // Trigger auto-fork instead of showing error
427
- try {
428
- await autoForkAndRetryAI?.(
429
- currentPrompt,
430
- aiChatMode,
431
- );
432
- // If we reach here, the fork was successful and redirect should happen
433
- return;
434
- } catch (forkError) {
435
- console.error('Auto-fork failed:', forkError);
426
+ // For authenticated users, trigger auto-fork
427
+ if (autoForkAndRetryAI) {
428
+ try {
429
+ await autoForkAndRetryAI(
430
+ currentPrompt,
431
+ aiChatMode,
432
+ );
433
+ // If we reach here, the fork was successful and redirect should happen
434
+ return;
435
+ } catch (forkError) {
436
+ console.error(
437
+ 'Auto-fork failed:',
438
+ forkError,
439
+ );
440
+ setAIErrorMessage(
441
+ 'Failed to fork visualization. Please try forking manually.',
442
+ );
443
+ return;
444
+ }
445
+ } else {
446
+ // For unauthenticated users, store the message and trigger login flow
447
+ // This will be handled by the external error handler
436
448
  setAIErrorMessage(
437
- 'Failed to fork visualization. Please try forking manually.',
449
+ errorMessage,
450
+ messageContent.trim(),
438
451
  );
439
452
  return;
440
453
  }
@@ -492,7 +505,7 @@ export const useVZCodeState = ({
492
505
  let newConfigData;
493
506
  try {
494
507
  newConfigData = JSON.parse(files[configFileId].text);
495
- } catch (error) {
508
+ } catch {
496
509
  // If config is invalid JSON, we can't process changes
497
510
  return;
498
511
  }
@@ -543,10 +556,10 @@ export const useVZCodeState = ({
543
556
  iframeRef.current?.contentWindow?.postMessage(
544
557
  changedProperties,
545
558
  );
546
- } catch (error) {
559
+ } catch (_error_) {
547
560
  console.error(
548
561
  'Failed to send config changes to iframe:',
549
- error,
562
+ _error_,
550
563
  );
551
564
  }
552
565
  }
@@ -1,29 +1,14 @@
1
- import React, { useCallback, useContext } from 'react';
1
+ import React, { useContext } from 'react';
2
2
  import { Button, Modal, Form } from './bootstrap';
3
- import { ThemeLabel, themes } from './themes';
4
3
  import { VZCodeContext } from './VZCodeContext';
5
4
 
6
5
  export const VZKeyboardShortcutsDoc = ({
7
- enableUsernameField = true,
6
+ enableUsernameField: _enableUsernameField = true,
8
7
  }: {
9
8
  // Feature flag to enable/disable username field
10
9
  enableUsernameField?: boolean;
11
10
  }) => {
12
- const {
13
- isDocOpen,
14
- closeDoc,
15
-
16
- setTheme,
17
-
18
- setUsername,
19
- } = useContext(VZCodeContext);
20
-
21
- const handleThemeChange = useCallback(
22
- (event: React.ChangeEvent<HTMLSelectElement>) => {
23
- setTheme(event.target.value as ThemeLabel);
24
- },
25
- [],
26
- );
11
+ const { isDocOpen, closeDoc } = useContext(VZCodeContext);
27
12
 
28
13
  return isDocOpen ? (
29
14
  <Modal
@@ -11,8 +11,6 @@ import { RunCodeWidget } from './RunCodeWidget';
11
11
  import { InteractRule } from '@replit/codemirror-interact';
12
12
  import { EditorView } from '@codemirror/view';
13
13
  import { Diagnostic } from '@codemirror/lint';
14
- import { VizContent } from '@vizhub/viz-types';
15
- import { LeafPane } from '../types';
16
14
  import { isImageFile } from './utils/isImageFile';
17
15
 
18
16
  // TODO modify this to handle the SplitPane type
@@ -104,8 +102,6 @@ export const VZMiddle = ({
104
102
  aiAssistTooltipText,
105
103
  aiAssistClickOverride,
106
104
  aiCopilotEndpoint,
107
- aiChatEndpoint,
108
- aiChatOptions,
109
105
  customInteractRules,
110
106
  esLintSource,
111
107
  }: {
@@ -115,8 +111,6 @@ export const VZMiddle = ({
115
111
  aiAssistTooltipText?: string;
116
112
  aiAssistClickOverride?: () => void;
117
113
  aiCopilotEndpoint?: string;
118
- aiChatEndpoint?: string;
119
- aiChatOptions?: { [key: string]: any };
120
114
  customInteractRules?: Array<InteractRule>;
121
115
  esLintSource: (
122
116
  view: EditorView,
@@ -1,7 +1,6 @@
1
1
  import React, {
2
2
  useContext,
3
3
  useEffect,
4
- useMemo,
5
4
  useRef,
6
5
  } from 'react';
7
6
  import {
@@ -13,7 +12,7 @@ import * as Diff2Html from 'diff2html';
13
12
  import 'diff2html/bundles/css/diff2html.min.css';
14
13
  import './DiffView.scss';
15
14
  import { VZCodeContext } from '../../VZCodeContext';
16
- import { VizFileId, VizFiles } from '@vizhub/viz-types';
15
+ import { VizFiles } from '@vizhub/viz-types';
17
16
 
18
17
  interface DiffViewProps {
19
18
  diffData: UnifiedFilesDiff;
@@ -30,10 +29,6 @@ export const DiffView: React.FC<DiffViewProps> = ({
30
29
  (diff) => diff.length > 0,
31
30
  );
32
31
 
33
- if (unifiedDiffs.length === 0) {
34
- return null;
35
- }
36
-
37
32
  // Calculate statistics from all unified diffs
38
33
  let totalAdditions = 0;
39
34
  let totalDeletions = 0;
@@ -53,27 +48,6 @@ export const DiffView: React.FC<DiffViewProps> = ({
53
48
  outputFormat: 'line-by-line',
54
49
  });
55
50
 
56
- // Create a mapping from file name to file ID for click handling
57
- const fileNameToIdMap = useMemo(() => {
58
- const map = new Map<string, VizFileId>();
59
- Object.entries(diffData).forEach(([fileId, diff]) => {
60
- // Extract file name from the unified diff
61
- // The diff contains lines like "--- a/filename" and "+++ b/filename"
62
- const lines = diff.split('\n');
63
- for (const line of lines) {
64
- if (
65
- line.startsWith('--- a/') ||
66
- line.startsWith('+++ b/')
67
- ) {
68
- const fileName = line.substring(6); // Remove "--- a/" or "+++ b/"
69
- map.set(fileName, fileId as VizFileId);
70
- break;
71
- }
72
- }
73
- });
74
- return map;
75
- }, [diffData]);
76
-
77
51
  // Add click handlers to file names after HTML is rendered
78
52
  useEffect(() => {
79
53
  if (!diffContainerRef.current) return;
@@ -103,7 +77,7 @@ export const DiffView: React.FC<DiffViewProps> = ({
103
77
 
104
78
  // TODO get fileId from content.files
105
79
  const fileId = Object.entries(files).find(
106
- ([id, file]) => file.name === fileName,
80
+ ([_id, file]) => file.name === fileName,
107
81
  )?.[0];
108
82
  console.log('Mapped file ID:', fileId);
109
83
 
@@ -145,6 +119,10 @@ export const DiffView: React.FC<DiffViewProps> = ({
145
119
  };
146
120
  }, [diffHtml, content, openTab, setIsAIChatOpen]);
147
121
 
122
+ if (unifiedDiffs.length === 0) {
123
+ return null;
124
+ }
125
+
148
126
  return (
149
127
  <div className="diff-view">
150
128
  <div className="diff-summary">
@@ -1,12 +1,7 @@
1
1
  import { timestampToDate } from '@vizhub/viz-utils';
2
2
  import Markdown from 'react-markdown';
3
3
  import remarkGfm from 'remark-gfm';
4
- import React, {
5
- useMemo,
6
- memo,
7
- useState,
8
- useContext,
9
- } from 'react';
4
+ import React, { useMemo, memo, useContext } from 'react';
10
5
  import { DiffView } from './DiffView';
11
6
  import { UnifiedFilesDiff } from '../../../utils/fileDiff';
12
7
  import { enableDiffView } from '../../featureFlags';
@@ -15,13 +15,11 @@ const MessageListComponent = ({
15
15
  isLoading,
16
16
  chatId, // Add chatId prop
17
17
  aiScratchpad, // Add aiScratchpad prop
18
- aiStatus, // Add aiStatus prop
19
18
  }: {
20
19
  messages: VizChatMessage[];
21
20
  isLoading: boolean;
22
21
  chatId?: string; // Add chatId to the type
23
22
  aiScratchpad?: string; // Add aiScratchpad to the type
24
- aiStatus?: string; // Add aiStatus to the type
25
23
  }) => {
26
24
  const messagesEndRef = useRef<HTMLDivElement>(null);
27
25
  const messagesContainerRef = useRef<HTMLDivElement>(null);
@@ -160,7 +158,7 @@ const MessageListComponent = ({
160
158
  ref={messagesContainerRef}
161
159
  onScroll={handleScroll}
162
160
  >
163
- {messages.map((msg, index) => {
161
+ {messages.map((msg, _index) => {
164
162
  return (
165
163
  <Message
166
164
  key={msg.id}
@@ -20,8 +20,7 @@ export const useSpeechRecognition = (
20
20
  const [recognition, setRecognition] =
21
21
  // @ts-ignore
22
22
  useState<SpeechRecognition | null>(null);
23
- const [finalTranscript, setFinalTranscript] =
24
- useState<string>('');
23
+ const [, setFinalTranscript] = useState<string>('');
25
24
 
26
25
  // Speech recognition setup
27
26
  useEffect(() => {
@@ -23,7 +23,6 @@ export const DirectoryListing = ({
23
23
  deleteDirectory,
24
24
  isDirectoryOpen,
25
25
  toggleDirectory,
26
- sidebarPresenceIndicators,
27
26
  } = useContext(VZCodeContext);
28
27
 
29
28
  const handleClick = useCallback(() => {
@@ -2,7 +2,6 @@ import {
2
2
  useCallback,
3
3
  useContext,
4
4
  useState,
5
- useRef,
6
5
  useEffect,
7
6
  useMemo,
8
7
  } from 'react';
@@ -60,7 +59,8 @@ export const VisualEditor = () => {
60
59
  const configData = useMemo(() => {
61
60
  try {
62
61
  return JSON.parse(files[configFileId].text);
63
- } catch (error) {
62
+ } catch (_error) {
63
+ console.error('Error parsing config.json:', _error);
64
64
  return null;
65
65
  }
66
66
  }, [files?.[configFileId]?.text]);
@@ -301,7 +301,7 @@ export const VisualEditor = () => {
301
301
 
302
302
  return (
303
303
  <div className="visual-editor">
304
- {visualEditorWidgets.map((widgetConfig, index) => {
304
+ {visualEditorWidgets.map((widgetConfig, _index) => {
305
305
  if (widgetConfig.type === 'slider') {
306
306
  // Use local value if available, otherwise fall back to config value
307
307
  const currentValue =
@@ -13,7 +13,6 @@ export function VoiceChatModal() {
13
13
  const {
14
14
  liveKitRoomName,
15
15
  setLiveKitRoom,
16
- liveKitToken,
17
16
  setLiveKitToken,
18
17
  liveKitConnection,
19
18
  setLiveKitConnection,
@@ -12,7 +12,6 @@ import {
12
12
  vizFilesToFileCollection,
13
13
  } from '@vizhub/viz-utils';
14
14
  import JSZip from 'jszip';
15
- import { generate } from '@langchain/core/dist/utils/fast-json-patch';
16
15
 
17
16
  export const createAICopyPasteHandlers = (
18
17
  files: VizFiles,
@@ -113,7 +112,6 @@ export const createAICopyPasteHandlers = (
113
112
  runId: generateRunId(),
114
113
  }));
115
114
 
116
- const fileCount = Object.keys(parsed.files).length;
117
115
  setPasteButtonText('Pasted!');
118
116
  setTimeout(
119
117
  () => setPasteButtonText('Paste for AI'),
@@ -1,7 +1,10 @@
1
1
  export type { ThemeLabel, ThemeOption } from './themes';
2
2
  export type { EditorCache } from './useEditorCache';
3
3
 
4
- export { VZCodeProvider } from './VZCodeContext';
4
+ export {
5
+ VZCodeProvider,
6
+ VZCodeContext,
7
+ } from './VZCodeContext';
5
8
  export { VZSidebar } from './VZSidebar';
6
9
  export { VZSettings } from './VZSettings';
7
10
  export { VZKeyboardShortcutsDoc } from './VZKeyboardShortcutsDoc';