vzcode 2.6.0 → 2.8.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 (40) hide show
  1. package/dist/assets/{index-Bfp1zhR4.js → index-CCjGlbxJ.js} +175 -176
  2. package/dist/cli.js +0 -2
  3. package/dist/index.html +1 -1
  4. package/dist/server/aiChatHandler/chatOperations.js +1 -1
  5. package/dist/server/computeInitialDocument.js +1 -1
  6. package/dist/server/index.js +2 -2
  7. package/package.json +10 -3
  8. package/src/cli.ts +0 -3
  9. package/src/client/AIAssist/AIAssistCodeMirrorKeyMap.ts +4 -4
  10. package/src/client/AIAssist/startAIAssist.ts +1 -7
  11. package/src/client/App/useShareDB.ts +1 -1
  12. package/src/client/CodeEditor/InteractiveWidgets/rotateWidget.ts +1 -1
  13. package/src/client/CodeEditor/getOrCreateEditor.tsx +5 -15
  14. package/src/client/CodeEditor/index.tsx +4 -3
  15. package/src/client/CodeEditor/rainbowBrackets.ts +0 -1
  16. package/src/client/CodeErrorOverlay/index.tsx +1 -1
  17. package/src/client/RunCodeWidget/index.tsx +1 -1
  18. package/src/client/SplitPaneResizeContext.tsx +0 -1
  19. package/src/client/VZCodeContext/types.ts +8 -4
  20. package/src/client/VZCodeContext/useVZCodeState.ts +6 -6
  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 +2 -7
  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/useFileCRUD.ts +0 -1
  32. package/src/client/useKeyboardShortcuts.ts +6 -2
  33. package/src/client/vzReducer/closeTabsReducer.ts +1 -1
  34. package/src/client/vzReducer/createInitialState.test.ts +25 -0
  35. package/src/client/vzReducer/createInitialState.ts +1 -1
  36. package/src/client/vzReducer/searchReducer.test.ts +16 -16
  37. package/src/client/vzReducer/searchReducer.ts +2 -2
  38. package/src/server/aiChatHandler/chatOperations.ts +1 -4
  39. package/src/server/computeInitialDocument.ts +1 -1
  40. 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-Bfp1zhR4.js"></script>
23
+ <script type="module" crossorigin src="/assets/index-CCjGlbxJ.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.6.0",
3
+ "version": "2.8.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';
@@ -199,14 +199,14 @@ export type VZCodeContextValue = {
199
199
  } | null;
200
200
 
201
201
  // Additional widgets that can be rendered in AI chat messages
202
- additionalWidgets?: React.ComponentType<{
202
+ additionalWidgets?: (props: {
203
203
  messageId: string;
204
204
  chatId: string;
205
205
  handleSendMessage?: (
206
206
  messageToSend?: string,
207
207
  options?: Record<string, string>,
208
208
  ) => void;
209
- }>;
209
+ }) => React.ReactNode;
210
210
  };
211
211
 
212
212
  export interface VZCodeProviderProps {
@@ -239,10 +239,14 @@ export interface VZCodeProviderProps {
239
239
  prompt: string;
240
240
  modelName: string;
241
241
  } | null;
242
- additionalWidgets?: React.ComponentType<{
242
+ additionalWidgets?: (props: {
243
243
  messageId: string;
244
244
  chatId: string;
245
- }>;
245
+ handleSendMessage?: (
246
+ messageToSend?: string,
247
+ options?: Record<string, string>,
248
+ ) => void;
249
+ }) => React.ReactNode;
246
250
  iframeRef?: React.MutableRefObject<HTMLIFrameElement>;
247
251
  handleChatError?: (
248
252
  error: string,
@@ -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
@@ -492,7 +492,7 @@ export const useVZCodeState = ({
492
492
  let newConfigData;
493
493
  try {
494
494
  newConfigData = JSON.parse(files[configFileId].text);
495
- } catch (error) {
495
+ } catch {
496
496
  // If config is invalid JSON, we can't process changes
497
497
  return;
498
498
  }
@@ -543,10 +543,10 @@ export const useVZCodeState = ({
543
543
  iframeRef.current?.contentWindow?.postMessage(
544
544
  changedProperties,
545
545
  );
546
- } catch (error) {
546
+ } catch (_error_) {
547
547
  console.error(
548
548
  'Failed to send config changes to iframe:',
549
- error,
549
+ _error_,
550
550
  );
551
551
  }
552
552
  }
@@ -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';
@@ -63,7 +58,7 @@ const MessageComponent = ({
63
58
  )}
64
59
  {additionalWidgets &&
65
60
  chatId &&
66
- React.createElement(additionalWidgets, {
61
+ additionalWidgets({
67
62
  messageId: id,
68
63
  chatId: chatId,
69
64
  handleSendMessage,
@@ -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'),
@@ -5,7 +5,6 @@ import { randomId } from '../randomId';
5
5
  import { EditorCache } from './useEditorCache';
6
6
  import { getFileExtension } from './utils/fileExtension';
7
7
  import { getLanguageExtension } from './CodeEditor/getOrCreateEditor';
8
- import { editorCacheKey } from './useEditorCache';
9
8
 
10
9
  // CRUD operations for files and directories
11
10
  // CRUD = Create, Read, Update, Delete