vzcode 1.44.0 → 1.46.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 (42) hide show
  1. package/dist/assets/{buildWorker-CRLuRnCr.js → buildWorker-C_tGhWXG.js} +135 -74
  2. package/dist/assets/index-CC0CUUDi.js +457 -0
  3. package/dist/assets/{index-Beqaj63x.css → index-CQyHWTWE.css} +1 -1
  4. package/dist/assets/worker-CekYspLa.js +453 -0
  5. package/dist/index.html +2 -2
  6. package/package.json +13 -7
  7. package/src/client/CodeEditor/{getOrCreateEditor.ts → getOrCreateEditor.tsx} +129 -1
  8. package/src/client/CodeEditor/index.tsx +11 -4
  9. package/src/client/Icons/SparklesSVG.tsx +9 -3
  10. package/src/client/RunCodeWidget/index.tsx +18 -15
  11. package/src/client/SplitPaneResizeContext.tsx +26 -108
  12. package/src/client/VZCodeContext.tsx +15 -1
  13. package/src/client/VZRight.tsx +32 -4
  14. package/src/client/VZSidebar/AIChat/ChatInput.tsx +80 -10
  15. package/src/client/VZSidebar/AIChat/DiffView.scss +154 -0
  16. package/src/client/VZSidebar/AIChat/DiffView.tsx +133 -0
  17. package/src/client/VZSidebar/AIChat/Message.tsx +24 -0
  18. package/src/client/VZSidebar/AIChat/MessageList.tsx +134 -12
  19. package/src/client/VZSidebar/AIChat/ThinkingScratchpad.tsx +37 -0
  20. package/src/client/VZSidebar/AIChat/index.tsx +155 -17
  21. package/src/client/VZSidebar/AIChat/styles.scss +223 -1
  22. package/src/client/VZSidebar/aiCopyPaste.ts +15 -2
  23. package/src/client/VZSidebar/index.tsx +10 -2
  24. package/src/client/bootstrap.ts +11 -1
  25. package/src/client/featureFlags.ts +2 -0
  26. package/src/client/useActions.ts +12 -0
  27. package/src/client/usePrettier/index.ts +1 -3
  28. package/src/client/vzReducer/aiChatReducer.ts +13 -0
  29. package/src/client/vzReducer/createInitialState.ts +1 -0
  30. package/src/client/vzReducer/index.ts +9 -0
  31. package/src/client/vzReducer/searchReducer.test.ts +44 -2
  32. package/src/runCode.ts +5 -17
  33. package/src/server/aiChatHandler/aiEditing.ts +56 -0
  34. package/src/server/aiChatHandler/chatOperations.ts +78 -1
  35. package/src/server/aiChatHandler/index.ts +33 -9
  36. package/src/server/aiChatHandler/llmStreaming.ts +101 -19
  37. package/src/server/computeInitialDocument.ts +25 -6
  38. package/src/server/generateAIResponse.ts +4 -0
  39. package/src/server/index.ts +83 -2
  40. package/src/utils/fileDiff.ts +114 -0
  41. package/dist/assets/index-C46Hp5ym.js +0 -340
  42. package/dist/assets/worker-DkYJN5WQ.js +0 -453
package/dist/index.html CHANGED
@@ -20,8 +20,8 @@
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-C46Hp5ym.js"></script>
24
- <link rel="stylesheet" crossorigin href="/assets/index-Beqaj63x.css">
23
+ <script type="module" crossorigin src="/assets/index-CC0CUUDi.js"></script>
24
+ <link rel="stylesheet" crossorigin href="/assets/index-CQyHWTWE.css">
25
25
  </head>
26
26
  <body>
27
27
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vzcode",
3
- "version": "1.44.0",
3
+ "version": "1.46.0",
4
4
  "description": "Multiplayer code editor system",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -18,6 +18,9 @@
18
18
  "build": "vite build",
19
19
  "build-release": "vite build --mode release",
20
20
  "preview": "concurrently \"npm run test-interactive\" \"vite preview\"",
21
+ "tauri": "tauri",
22
+ "tauri:dev": "tauri dev",
23
+ "tauri:build": "tauri build",
21
24
  "prepublishOnly": "npm run build-release",
22
25
  "upgrade": "ncu -x react,react-dom,@types/react,@types/react-dom -u"
23
26
  },
@@ -109,7 +112,7 @@
109
112
  "@codemirror/lang-html": "^6.4.9",
110
113
  "@codemirror/lang-javascript": "^6.2.4",
111
114
  "@codemirror/lang-json": "^6.0.2",
112
- "@codemirror/lang-markdown": "^6.3.3",
115
+ "@codemirror/lang-markdown": "^6.3.4",
113
116
  "@codemirror/lint": "^6.8.5",
114
117
  "@codemirror/state": "^6.5.2",
115
118
  "@codemirror/theme-one-dark": "^6.1.3",
@@ -134,9 +137,9 @@
134
137
  "@uiw/codemirror-theme-xcode": "^4.24.2",
135
138
  "@uiw/codemirror-themes": "^4.24.2",
136
139
  "@valtown/codemirror-ts": "^2.3.1",
137
- "@vizhub/runtime": "^4.2.0",
138
- "@vizhub/viz-types": "^0.3.0",
139
- "@vizhub/viz-utils": "^1.3.0",
140
+ "@vizhub/runtime": "^4.3.0",
141
+ "@vizhub/viz-types": "^0.4.0",
142
+ "@vizhub/viz-utils": "^1.4.0",
140
143
  "body-parser": "^2.2.0",
141
144
  "codemirror": "^6.0.2",
142
145
  "codemirror-copilot": "^0.0.7",
@@ -144,7 +147,9 @@
144
147
  "color-hash": "^2.0.2",
145
148
  "comlink": "^4.4.2",
146
149
  "d3-array": "^3.2.4",
150
+ "diff": "^8.0.2",
147
151
  "diff-match-patch": "^1.0.5",
152
+ "diff2html": "^3.4.52",
148
153
  "dotenv": "^17.2.1",
149
154
  "editcodewithai": "^2.3.0",
150
155
  "eslint-linter-browserify": "^9.32.0",
@@ -154,7 +159,7 @@
154
159
  "jszip": "^3.10.1",
155
160
  "livekit-server-sdk": "^2.13.1",
156
161
  "llm-code-format": "^3.0.0",
157
- "npm": "^11.5.1",
162
+ "npm": "^11.5.2",
158
163
  "open": "^10.2.0",
159
164
  "prettier-plugin-svelte": "^3.4.0",
160
165
  "react": "^18",
@@ -171,6 +176,7 @@
171
176
  },
172
177
  "devDependencies": {
173
178
  "@eslint/js": "^9.32.0",
179
+ "@tauri-apps/cli": "^2.7.1",
174
180
  "@types/react": "^18",
175
181
  "@types/react-dom": "^18",
176
182
  "@vitejs/plugin-react": "^4.7.0",
@@ -182,7 +188,7 @@
182
188
  "prettier": "^3.6.2",
183
189
  "sass": "^1.89.2",
184
190
  "ts-node": "^10.9.2",
185
- "typescript": "^5.8.3",
191
+ "typescript": "^5.9.2",
186
192
  "vite": "^7.0.6",
187
193
  "vitest": "^3.2.4"
188
194
  },
@@ -1,3 +1,4 @@
1
+ import { createRoot } from 'react-dom/client';
1
2
  import { EditorView } from 'codemirror';
2
3
  import {
3
4
  Compartment,
@@ -43,7 +44,17 @@ import {
43
44
  EditorCacheValue,
44
45
  } from '../useEditorCache';
45
46
  import { ThemeLabel, themeOptionsByLabel } from '../themes';
46
- import { keymap } from '@codemirror/view';
47
+ import {
48
+ keymap,
49
+ Decoration,
50
+ WidgetType,
51
+ ViewUpdate,
52
+ ViewPlugin,
53
+ DecorationSet,
54
+ } from '@codemirror/view';
55
+ import { Range } from '@codemirror/state';
56
+ import { syntaxTree } from '@codemirror/language';
57
+ import { RegExpCursor } from '@codemirror/search';
47
58
  import { basicSetup } from './basicSetup';
48
59
  import { InteractRule } from '@replit/codemirror-interact';
49
60
  import rainbowBrackets from './rainbowBrackets';
@@ -60,6 +71,9 @@ import {
60
71
  tsSyncWorker,
61
72
  } from '@valtown/codemirror-ts';
62
73
  import { getFileExtension } from '../utils/fileExtension';
74
+ import { SparklesSVG } from '../Icons/SparklesSVG';
75
+ import { VZCodeContext } from '../VZCodeContext';
76
+ import { useContext, useMemo } from 'react';
63
77
 
64
78
  const DEBUG = false;
65
79
 
@@ -178,6 +192,8 @@ export const getOrCreateEditor = async ({
178
192
  aiCopilotEndpoint,
179
193
  esLintSource,
180
194
  rainbowBracketsEnabled = true,
195
+ setIsAIChatOpen,
196
+ setAIChatMessage,
181
197
  }: {
182
198
  // TODO pass this in from the outside
183
199
  paneId?: PaneId;
@@ -213,6 +229,8 @@ export const getOrCreateEditor = async ({
213
229
  view: EditorView,
214
230
  ) => Promise<readonly Diagnostic[]>;
215
231
  rainbowBracketsEnabled?: boolean; // New parameter type
232
+ setIsAIChatOpen: any; // TODO fix types
233
+ setAIChatMessage: any; // TODO fix types
216
234
  }): Promise<ExtendedEditorCacheValue> => {
217
235
  // Cache hit
218
236
 
@@ -454,6 +472,116 @@ export const getOrCreateEditor = async ({
454
472
  extensions.push(copilot({ aiCopilotEndpoint }));
455
473
  }
456
474
 
475
+ // const { setIsAIChatOpen } = useContext(VZCodeContext);
476
+
477
+ // Widget appears after instances of "todo" in code editor, allowing AI to implement todo tasks when clicked
478
+ function createToDoPlugin() {
479
+ // setIsAIChatOpen: (open: boolean) => void,
480
+ class ToDoWidget extends WidgetType {
481
+ constructor() {
482
+ super();
483
+ }
484
+
485
+ eq(other: ToDoWidget) {
486
+ return false;
487
+ }
488
+
489
+ toDOM() {
490
+ const wrap = document.createElement('i');
491
+ wrap.style.display = 'inline-flex'; // prevent block expansion
492
+ wrap.style.alignItems = 'center';
493
+ wrap.style.justifyContent = 'center';
494
+ wrap.className = 'icon-button icon-button-dark';
495
+ const reactContainer =
496
+ document.createElement('div');
497
+ wrap.appendChild(reactContainer);
498
+
499
+ const root = createRoot(reactContainer);
500
+ root.render(
501
+ <div
502
+ onClick={() => {
503
+ console.log(
504
+ 'TODO set the chat prompt to "Implement the TODO"',
505
+ );
506
+ setIsAIChatOpen(true);
507
+ setAIChatMessage('Implement the TODO');
508
+ // submitAIChatMessage()
509
+ }}
510
+ >
511
+ <SparklesSVG width={14} height={14} />
512
+ </div>,
513
+ );
514
+ return wrap;
515
+ }
516
+
517
+ ignoreEvent() {
518
+ return false;
519
+ }
520
+ }
521
+
522
+ function toDoWidgets(editor: EditorView) {
523
+ const { state } = editor;
524
+ const tree = syntaxTree(state);
525
+ const findToDo = new RegExpCursor(state.doc, 'todo', {
526
+ ignoreCase: true,
527
+ });
528
+ const widgets: Range<Decoration>[] = [];
529
+
530
+ while (!findToDo.next().done) {
531
+ const { from, to } = findToDo.value;
532
+ const node = tree.resolve(from);
533
+ let inComment = false;
534
+
535
+ // Walk up the parents until we hit the root, looking for a comment node
536
+ for (let cur: any = node; cur; cur = cur.parent) {
537
+ if (
538
+ cur.type.is('Comment') || // grammars that group comments
539
+ cur.type.is('comment') || // generic lowercase group
540
+ /Comment$/.test(cur.type.name) // fallback for e.g. LineComment
541
+ ) {
542
+ inComment = true;
543
+ break;
544
+ }
545
+ }
546
+ if (!inComment) continue; // skip non-comment TODOs
547
+
548
+ const deco = Decoration.widget({
549
+ widget: new ToDoWidget(),
550
+ side: 1,
551
+ }).range(to);
552
+ widgets.push(deco);
553
+ }
554
+ return Decoration.set(widgets);
555
+ }
556
+
557
+ const todoPlugin = ViewPlugin.fromClass(
558
+ class {
559
+ decorations: DecorationSet;
560
+
561
+ constructor(view: EditorView) {
562
+ this.decorations = toDoWidgets(view);
563
+ }
564
+
565
+ update(update: ViewUpdate) {
566
+ if (
567
+ update.docChanged ||
568
+ update.viewportChanged ||
569
+ syntaxTree(update.startState) !==
570
+ syntaxTree(update.state)
571
+ )
572
+ this.decorations = toDoWidgets(update.view);
573
+ }
574
+ },
575
+ {
576
+ decorations: (v) => v.decorations,
577
+ },
578
+ );
579
+
580
+ return todoPlugin;
581
+ }
582
+
583
+ extensions.push(createToDoPlugin());
584
+
457
585
  const editor = new EditorView({
458
586
  state: EditorState.create({
459
587
  doc: text,
@@ -43,7 +43,8 @@ export const CodeEditor = ({
43
43
  theme,
44
44
  codeEditorRef,
45
45
  enableAutoFollow,
46
- openTab,
46
+ setIsAIChatOpen,
47
+ setAIChatMessage,
47
48
  } = useContext(VZCodeContext);
48
49
 
49
50
  // Set `doc.data.isInteracting` to `true` when the user is interacting
@@ -61,13 +62,17 @@ export const CodeEditor = ({
61
62
  clearTimeout(interactTimeoutRef.current);
62
63
  }
63
64
 
64
- // Set `isInteracting: undefined` after a delay.
65
+ // Set `isInteracting: undefined` after a delay,
66
+ // so that when the runId changes in the future,
67
+ // it will trigger a hard re-run, not a hot reload.
65
68
  interactTimeoutRef.current = setTimeout(() => {
66
69
  interactTimeoutRef.current = null;
67
70
 
68
- // This logic deletes the `isInteracting` property from the document.
71
+ // This logic deletes the `isInteracting` property from the document
69
72
  submitOperation(
70
- ({ isInteracting, ...newDocument }) => newDocument,
73
+ ({ isInteracting, ...newDocument }) => ({
74
+ ...newDocument,
75
+ }),
71
76
  );
72
77
  }, 800);
73
78
  }, [submitOperation]);
@@ -109,6 +114,8 @@ export const CodeEditor = ({
109
114
  enableAutoFollowRef,
110
115
  aiCopilotEndpoint,
111
116
  esLintSource,
117
+ setIsAIChatOpen,
118
+ setAIChatMessage,
112
119
  });
113
120
 
114
121
  if (isMounted) {
@@ -1,8 +1,14 @@
1
- export const SparklesSVG = () => (
1
+ export const SparklesSVG = ({
2
+ width = '32',
3
+ height = '32',
4
+ }: {
5
+ width?: string | number;
6
+ height?: string | number;
7
+ }) => (
2
8
  <svg
3
9
  xmlns="http://www.w3.org/2000/svg"
4
- width="32"
5
- height="32"
10
+ width={width}
11
+ height={height}
6
12
  viewBox="0 0 24 24"
7
13
  fill="currentColor"
8
14
  stroke="currentColor"
@@ -28,24 +28,27 @@ export const RunCodeWidget = ({
28
28
  useContext(VZCodeContext);
29
29
  const [isRunning, setIsRunning] = useState(false);
30
30
 
31
- const handleClick = useCallback(() => {
32
- setIsRunning(true); // Set the running state to true
31
+ const handleClick = useCallback(
32
+ (event?: React.MouseEvent) => {
33
+ setIsRunning(true); // Set the running state to true
33
34
 
34
- // Run Prettier
35
- const runPrettier = runPrettierRef.current;
36
- if (runPrettier !== null) {
37
- runPrettier();
38
- }
35
+ // Run Prettier
36
+ const runPrettier = runPrettierRef.current;
37
+ if (runPrettier !== null) {
38
+ runPrettier();
39
+ }
39
40
 
40
- // Run the code
41
- const runCode = runCodeRef.current;
42
- if (runCode !== null) {
43
- runCode();
44
- }
41
+ // Run the code
42
+ const runCode = runCodeRef.current;
43
+ if (runCode !== null) {
44
+ runCode();
45
+ }
45
46
 
46
- // Optional: reset the icon state after animation completes (e.g., 1 second)
47
- setTimeout(() => setIsRunning(false), 1000);
48
- }, [runCodeRef, runPrettierRef]);
47
+ // Optional: reset the icon state after animation completes (e.g., 1 second)
48
+ setTimeout(() => setIsRunning(false), 1000);
49
+ },
50
+ [runCodeRef, runPrettierRef],
51
+ );
49
52
 
50
53
  const handleSplitEditor = useCallback(() => {
51
54
  splitCurrentPane();
@@ -2,9 +2,8 @@
2
2
  import {
3
3
  createContext,
4
4
  useReducer,
5
- useEffect,
6
5
  useCallback,
7
- useLayoutEffect,
6
+ useEffect,
8
7
  } from 'react';
9
8
 
10
9
  export type Side = 'left' | 'right';
@@ -16,63 +15,22 @@ export type SplitPaneResizeContextValue = {
16
15
  isDraggingRight: boolean;
17
16
  isDraggingLeft: boolean;
18
17
  setIsDragging: (a: boolean, side: Side) => void;
18
+ setSidebarView: (isAIChatOpen: boolean) => void;
19
19
  };
20
20
 
21
- // Feature flag for developers to use when testing.
22
- const enableLocalStorage = true;
23
-
24
- // The amount of time to wait idle before writing to localStorage.
25
- // This is to avoid writing to localStorage on every resize event.
26
- // MS = milliseconds
27
- const localStorageWriteDebounceMS = 800;
28
-
29
- // Properties in LocalStorage
30
- const sidebarWidthProperty = 'vzCodeSidebarWidth';
31
- const codeEditorWidthProperty = 'vzCodeCodeEditorWidth';
32
-
33
- const initialSidebarWidthDefault = 250;
34
- let initialSidebarWidth: number =
35
- initialSidebarWidthDefault;
36
-
21
+ // Default widths for different sidebar views
22
+ const filesViewWidth = 300;
23
+ const aiChatViewWidth = 600;
37
24
  const initialCodeEditorWidthDefault = 800;
38
- let initialCodeEditorWidth: number =
39
- initialCodeEditorWidthDefault;
40
-
41
- // If no value is found in localStorage, we'll use the default.
42
- let needsInitialization = false;
43
-
44
- // If we're in the browser,
45
- if (typeof window !== 'undefined' && enableLocalStorage) {
46
- //check localStorage for a previously stored width.
47
- const sidebarWidthLocal: string | null =
48
- window.localStorage.getItem(sidebarWidthProperty);
49
-
50
- const codeEditorWidthLocal: string | null =
51
- window.localStorage.getItem(codeEditorWidthProperty);
52
-
53
- // If there is a previously stored width,
54
- if (sidebarWidthLocal !== null) {
55
- // use it as the initial width.
56
- initialSidebarWidth = +sidebarWidthLocal;
57
- needsInitialization = true;
58
- }
59
-
60
- if (codeEditorWidthLocal !== null) {
61
- // use it as the initial width.
62
- initialCodeEditorWidth = +codeEditorWidthLocal;
63
- needsInitialization = true;
64
- }
65
- } else {
66
- // If we're not in the browser, use the default initial width.
67
- }
68
25
 
69
26
  const initialValue: SplitPaneResizeContextValue = {
70
- codeEditorWidth: initialCodeEditorWidth,
71
- sidebarWidth: initialSidebarWidth,
27
+ codeEditorWidth: initialCodeEditorWidthDefault,
28
+ sidebarWidth: filesViewWidth, // Default to files view
72
29
  moveSplitPane: () => {},
73
30
  isDraggingRight: false,
74
31
  isDraggingLeft: false,
75
32
  setIsDragging: () => {},
33
+ setSidebarView: () => {},
76
34
  };
77
35
 
78
36
  export const SplitPaneResizeContext =
@@ -84,30 +42,13 @@ type SplitPaneState = {
84
42
  codeEditorWidth: number;
85
43
  isDraggingLeft: boolean;
86
44
  isDraggingRight: boolean;
87
-
88
- // False on first render
89
- isInitialized: boolean;
90
45
  };
91
46
 
92
47
  const initialState: SplitPaneState = {
93
- // sidebarWidth: initialSidebarWidth,
94
- // codeEditorWidth: initialCodeEditorWidth,
95
-
96
- // These need to match between SSR and the first
97
- // client-side render (hydration), to avoid
98
- // React hydration errors like this one:
99
- // * Warning: Prop `style` did not match.
100
- // * Server: "left:210px;width:20px"
101
- // * Client: "left:218px;width:20px"
102
-
103
- sidebarWidth: initialSidebarWidthDefault,
48
+ sidebarWidth: filesViewWidth,
104
49
  codeEditorWidth: initialCodeEditorWidthDefault,
105
50
  isDraggingLeft: false,
106
51
  isDraggingRight: false,
107
-
108
- // Solution for hydration errors: we set the value from localStorage
109
- // in a layoutEffect that happens after first render.
110
- isInitialized: false,
111
52
  };
112
53
 
113
54
  type SplitPaneAction =
@@ -122,7 +63,8 @@ type SplitPaneAction =
122
63
  isDragging: boolean;
123
64
  }
124
65
  | {
125
- type: 'initialize';
66
+ type: 'setSidebarView';
67
+ isAIChatOpen: boolean;
126
68
  };
127
69
 
128
70
  const splitPaneReducer = (
@@ -130,13 +72,6 @@ const splitPaneReducer = (
130
72
  action: SplitPaneAction,
131
73
  ) => {
132
74
  switch (action.type) {
133
- case 'initialize':
134
- return {
135
- ...state,
136
- sidebarWidth: initialSidebarWidth,
137
- codeEditorWidth: initialCodeEditorWidth,
138
- isInitialized: true,
139
- };
140
75
  case 'move':
141
76
  return action.side === 'left'
142
77
  ? {
@@ -160,6 +95,13 @@ const splitPaneReducer = (
160
95
  ...state,
161
96
  isDraggingRight: action.isDragging,
162
97
  };
98
+ case 'setSidebarView':
99
+ return {
100
+ ...state,
101
+ sidebarWidth: action.isAIChatOpen
102
+ ? aiChatViewWidth
103
+ : filesViewWidth,
104
+ };
163
105
  default:
164
106
  return state;
165
107
  }
@@ -185,45 +127,20 @@ export const SplitPaneResizeProvider = ({ children }) => {
185
127
  [dispatch],
186
128
  );
187
129
 
130
+ const setSidebarView = useCallback(
131
+ (isAIChatOpen: boolean) => {
132
+ dispatch({ type: 'setSidebarView', isAIChatOpen });
133
+ },
134
+ [dispatch],
135
+ );
136
+
188
137
  const {
189
138
  sidebarWidth,
190
139
  codeEditorWidth,
191
140
  isDraggingLeft,
192
141
  isDraggingRight,
193
- isInitialized,
194
142
  } = state;
195
143
 
196
- // Logic around initializing from localStorage.
197
- // Only run this on the client.
198
- if (typeof window !== 'undefined') {
199
- useLayoutEffect(() => {
200
- if (needsInitialization && !isInitialized) {
201
- dispatch({ type: 'initialize' });
202
- }
203
- }, [isInitialized]);
204
- }
205
-
206
- // Logic around storing the values in localStorage.
207
- useEffect(() => {
208
- if (sidebarWidth !== initialSidebarWidth) {
209
- setTimeout(() => {
210
- window.localStorage.setItem(
211
- sidebarWidthProperty,
212
- '' + sidebarWidth,
213
- );
214
- }, localStorageWriteDebounceMS);
215
- }
216
-
217
- if (codeEditorWidth !== initialCodeEditorWidth) {
218
- setTimeout(() => {
219
- window.localStorage.setItem(
220
- codeEditorWidthProperty,
221
- '' + codeEditorWidth,
222
- );
223
- }, localStorageWriteDebounceMS);
224
- }
225
- }, [codeEditorWidth, sidebarWidth]);
226
-
227
144
  const value: SplitPaneResizeContextValue = {
228
145
  codeEditorWidth,
229
146
  sidebarWidth,
@@ -231,6 +148,7 @@ export const SplitPaneResizeProvider = ({ children }) => {
231
148
  isDraggingLeft,
232
149
  isDraggingRight,
233
150
  setIsDragging,
151
+ setSidebarView,
234
152
  };
235
153
 
236
154
  return (
@@ -126,6 +126,8 @@ export type VZCodeContextValue = {
126
126
  setIsAIChatOpen: (isAIChatOpen: boolean) => void;
127
127
  aiChatFocused: boolean;
128
128
  toggleAIChatFocused: () => void;
129
+ aiChatMode: 'ask' | 'edit';
130
+ setAIChatMode: (mode: 'ask' | 'edit') => void;
129
131
  aiChatEndpoint?: string;
130
132
  aiChatOptions?: { [key: string]: any };
131
133
  setSearchResults: (files: ShareDBDoc<VizContent>) => void;
@@ -158,7 +160,9 @@ export type VZCodeContextValue = {
158
160
  runPrettierRef: React.MutableRefObject<
159
161
  null | (() => void)
160
162
  >;
161
- runCodeRef: React.MutableRefObject<null | (() => void)>;
163
+ runCodeRef: React.MutableRefObject<
164
+ null | ((hardRerun?: boolean) => void)
165
+ >;
162
166
 
163
167
  sidebarRef: React.RefObject<HTMLDivElement>;
164
168
 
@@ -188,6 +192,8 @@ export type VZCodeContextValue = {
188
192
  setLiveKitConnection: (state: boolean) => void;
189
193
  voiceChatModalOpen: boolean;
190
194
  setVoiceChatModalOpen: (state: boolean) => void;
195
+ aiChatMessage: string;
196
+ setAIChatMessage: (message: string) => void;
191
197
  };
192
198
 
193
199
  export const VZCodeProvider = ({
@@ -315,6 +321,7 @@ export const VZCodeProvider = ({
315
321
  toggleSearchFocused,
316
322
  setIsAIChatOpen,
317
323
  toggleAIChatFocused,
324
+ setAIChatMode,
318
325
  setIsSettingsOpen,
319
326
  setIsDocOpen,
320
327
  closeSettings,
@@ -442,6 +449,8 @@ export const VZCodeProvider = ({
442
449
  const [voiceChatModalOpen, setVoiceChatModalOpen] =
443
450
  useState(false);
444
451
 
452
+ const [aiChatMessage, setAIChatMessage] = useState('');
453
+
445
454
  // The value provided by this context.
446
455
  const value: VZCodeContextValue = {
447
456
  content,
@@ -485,6 +494,8 @@ export const VZCodeProvider = ({
485
494
  setIsAIChatOpen,
486
495
  aiChatFocused,
487
496
  toggleAIChatFocused,
497
+ aiChatMode: state.aiChatMode,
498
+ setAIChatMode,
488
499
  aiChatEndpoint,
489
500
  aiChatOptions,
490
501
 
@@ -546,6 +557,9 @@ export const VZCodeProvider = ({
546
557
  setLiveKitConnection,
547
558
  voiceChatModalOpen,
548
559
  setVoiceChatModalOpen,
560
+
561
+ aiChatMessage,
562
+ setAIChatMessage,
549
563
  };
550
564
 
551
565
  return (