vzcode 1.16.0 → 1.18.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 (39) hide show
  1. package/dist/assets/index-CSSpCKM0.js +447 -0
  2. package/dist/assets/index-eifYAxsF.js +181 -0
  3. package/dist/assets/index-zzK6rRiK.css +1 -0
  4. package/dist/assets/worker-8af7bTHW.js +293 -0
  5. package/dist/index.html +2 -2
  6. package/package.json +40 -34
  7. package/src/client/App/index.tsx +52 -20
  8. package/src/client/App/usePending.ts +50 -0
  9. package/src/client/App/useShareDB.ts +40 -1
  10. package/src/client/CodeEditor/Copilot/index.ts +28 -0
  11. package/src/client/CodeEditor/InteractiveWidgets/colorPicker.ts +129 -33
  12. package/src/client/CodeEditor/InteractiveWidgets/colorsInTextPlugin.ts +36 -1
  13. package/src/client/CodeEditor/getOrCreateEditor.ts +43 -6
  14. package/src/client/CodeEditor/index.tsx +4 -1
  15. package/src/client/CodeEditor/rainbowBrackets.ts +14 -2
  16. package/src/client/CodeEditor/style.scss +106 -1
  17. package/src/client/Icons/MicSVG.tsx +25 -0
  18. package/src/client/RunCodeWidget/index.tsx +20 -3
  19. package/src/client/VZCodeContext.tsx +52 -14
  20. package/src/client/VZKeyboardShortcutsDoc.tsx +8 -8
  21. package/src/client/VZLeft.tsx +5 -2
  22. package/src/client/VZMiddle.tsx +5 -0
  23. package/src/client/VZSettings.tsx +54 -3
  24. package/src/client/VZSidebar/VoiceChatModal.tsx +121 -0
  25. package/src/client/VZSidebar/index.tsx +93 -14
  26. package/src/client/VZSidebar/styles.scss +6 -1
  27. package/src/client/featureFlags.ts +2 -0
  28. package/src/client/useTypeScript/worker/constants.ts +6 -0
  29. package/src/server/generateAIResponse.js +79 -13
  30. package/src/server/handleAICopilot.js +77 -0
  31. package/src/server/index.js +23 -8
  32. package/src/server/livekit.js +24 -0
  33. package/src/server/setupEnv.js +1 -1
  34. package/src/types.ts +1 -0
  35. package/src/vite-env.d.ts +10 -0
  36. package/dist/assets/index-B6yTvvah.css +0 -1
  37. package/dist/assets/index-BlwLvENZ.js +0 -159
  38. package/dist/assets/index-Bm65AzMP.js +0 -425
  39. package/dist/assets/worker-CJWrLBN2.js +0 -286
@@ -10,11 +10,13 @@ import { markdown } from '@codemirror/lang-markdown';
10
10
  import { html } from '@codemirror/lang-html';
11
11
  import { css } from '@codemirror/lang-css';
12
12
  import { json1Sync } from 'codemirror-ot';
13
+
13
14
  import { autocompletion } from '@codemirror/autocomplete';
14
15
  import { indentationMarkers } from '@replit/codemirror-indentation-markers';
15
16
  // import { showMinimap } from '@replit/codemirror-minimap';
16
17
  import { vscodeKeymap } from '@replit/codemirror-vscode-keymap';
17
18
  import { Diagnostic, linter } from '@codemirror/lint';
19
+
18
20
  import { json1Presence, textUnicode } from '../../ot';
19
21
  import {
20
22
  FileId,
@@ -45,11 +47,14 @@ import { InteractRule } from '@replit/codemirror-interact';
45
47
  import rainbowBrackets from '../CodeEditor/rainbowBrackets';
46
48
  import { cssLanguage } from '@codemirror/lang-css';
47
49
  import { javascriptLanguage } from '@codemirror/lang-javascript';
50
+ import { copilot } from './Copilot';
48
51
 
49
52
  // Feature flag to enable TypeScript completions & TypeScript Linter.
50
- const enableTypeScriptCompletions = true;
51
53
  const enableTypeScriptLinter = true;
52
54
 
55
+ // Feature flag to enable AI copilot
56
+ const enableCopilot = true;
57
+
53
58
  // Enables TypeScript +JSX support in CodeMirror.
54
59
  const tsx = () =>
55
60
  javascript({ jsx: true, typescript: true });
@@ -74,6 +79,7 @@ const htmlConfig = {
74
79
  ],
75
80
  nestedAttributes: [],
76
81
  };
82
+
77
83
  // Language extensions for CodeMirror.
78
84
  // Keys are file extensions.
79
85
  // Values are CodeMirror extensions.
@@ -101,6 +107,13 @@ const getAtPath = (obj, path) => {
101
107
  return current;
102
108
  };
103
109
 
110
+ // Extend the EditorCacheValue type to include the compartments and the updateRainbowBrackets method
111
+ interface ExtendedEditorCacheValue extends EditorCacheValue {
112
+ themeCompartment: Compartment;
113
+ rainbowBracketsCompartment: Compartment;
114
+ updateRainbowBrackets: (enabled: boolean) => void;
115
+ }
116
+
104
117
  // Gets or creates an `editorCache` entry for the given file id.
105
118
  // Looks in `editorCache` first, and if not found, creates a new editor.
106
119
  export const getOrCreateEditor = ({
@@ -120,6 +133,8 @@ export const getOrCreateEditor = ({
120
133
  allowGlobals,
121
134
  enableAutoFollowRef,
122
135
  openTab,
136
+ aiCopilotEndpoint,
137
+ rainbowBracketsEnabled = true, // New parameter to enable or disable Rainbow Brackets
123
138
  }: {
124
139
  // TODO pass this in from the outside
125
140
  paneId?: PaneId;
@@ -156,13 +171,15 @@ export const getOrCreateEditor = ({
156
171
  // enable auto-following the cursors of remote users.
157
172
  enableAutoFollowRef: React.MutableRefObject<boolean>;
158
173
  openTab: (tabState: TabState) => void;
159
- }): EditorCacheValue => {
174
+ aiCopilotEndpoint: string;
175
+ rainbowBracketsEnabled?: boolean; // New parameter type
176
+ }): ExtendedEditorCacheValue => {
160
177
  // Cache hit
161
178
 
162
179
  const cacheKey = editorCacheKey(fileId, paneId);
163
180
 
164
181
  if (editorCache.has(cacheKey)) {
165
- return editorCache.get(cacheKey);
182
+ return editorCache.get(cacheKey) as ExtendedEditorCacheValue;
166
183
  }
167
184
 
168
185
  // Cache miss
@@ -177,6 +194,9 @@ export const getOrCreateEditor = ({
177
194
  // Create a compartment for the theme so that it can be changed dynamically.
178
195
  // Inspired by: https://github.com/craftzdog/cm6-themes/blob/main/example/index.ts
179
196
  let themeCompartment = new Compartment();
197
+
198
+ // Create a compartment for rainbow brackets so that it can be enabled/disabled dynamically.
199
+ let rainbowBracketsCompartment = new Compartment();
180
200
 
181
201
  // The CodeMirror extensions to use.
182
202
  // const extensions = [autocompletion(), html(htmlConfig)]
@@ -237,6 +257,13 @@ export const getOrCreateEditor = ({
237
257
  themeCompartment.of(themeOptionsByLabel[theme].value),
238
258
  );
239
259
 
260
+ // Adds compartment for rainbow brackets with initial toggle state.
261
+ extensions.push(
262
+ rainbowBracketsCompartment.of(
263
+ rainbowBracketsEnabled ? rainbowBrackets() : []
264
+ ),
265
+ );
266
+
240
267
  // TODO handle dynamic changing of the file extension.
241
268
  // TODO handle dynamic file extensions by making
242
269
  // the CodeMirror language extension dynamic
@@ -380,8 +407,11 @@ export const getOrCreateEditor = ({
380
407
  }),
381
408
  ),
382
409
  );
383
- // adds rainbow brackets
384
- extensions.push(rainbowBrackets());
410
+
411
+ // adds copilot
412
+ if (enableCopilot) {
413
+ extensions.push(copilot({ aiCopilotEndpoint }));
414
+ }
385
415
 
386
416
  const editor = new EditorView({
387
417
  state: EditorState.create({
@@ -390,10 +420,17 @@ export const getOrCreateEditor = ({
390
420
  }),
391
421
  });
392
422
 
393
- const editorCacheValue = { editor, themeCompartment };
423
+ const editorCacheValue: ExtendedEditorCacheValue = { editor, themeCompartment, rainbowBracketsCompartment, updateRainbowBrackets: (enabled) => {
424
+ editor.dispatch({
425
+ effects: rainbowBracketsCompartment.reconfigure(enabled ? rainbowBrackets() : []),
426
+ });
427
+ }};
394
428
 
395
429
  // Populate the cache.
396
430
  editorCache.set(cacheKey, editorCacheValue);
397
431
 
432
+ // Initialize rainbow brackets based on the toggle state
433
+ editorCacheValue.updateRainbowBrackets(rainbowBracketsEnabled);
434
+
398
435
  return editorCacheValue;
399
436
  };
@@ -19,9 +19,11 @@ const filesPath = ['files'];
19
19
  export const CodeEditor = ({
20
20
  customInteractRules,
21
21
  allowGlobals,
22
+ aiCopilotEndpoint,
22
23
  }: {
23
24
  customInteractRules?: Array<InteractRule>;
24
25
  allowGlobals: boolean;
26
+ aiCopilotEndpoint: string;
25
27
  }) => {
26
28
  const {
27
29
  activePane,
@@ -99,7 +101,7 @@ export const CodeEditor = ({
99
101
  allowGlobals,
100
102
  enableAutoFollowRef,
101
103
  openTab,
102
- // splitPaneView,
104
+ aiCopilotEndpoint,
103
105
  }),
104
106
  [
105
107
  activePane,
@@ -112,6 +114,7 @@ export const CodeEditor = ({
112
114
  editorCache,
113
115
  usernameRef,
114
116
  typeScriptWorker,
117
+ aiCopilotEndpoint,
115
118
  ],
116
119
  );
117
120
 
@@ -8,6 +8,12 @@ function generateColors() {
8
8
  return ['red', 'orange', 'yellow', 'green'];
9
9
  }
10
10
 
11
+ let isRainbowEnabled = true;
12
+
13
+ export const toggleRainbowBrackets = (enabled: boolean) => {
14
+ isRainbowEnabled = enabled;
15
+ };
16
+
11
17
  const rainbowBracketsPlugin = ViewPlugin.fromClass(
12
18
  class {
13
19
  decorations;
@@ -50,12 +56,16 @@ const rainbowBracketsPlugin = ViewPlugin.fromClass(
50
56
  ) {
51
57
  const color =
52
58
  colors[stack.length % colors.length];
59
+ const bracketClass = isRainbowEnabled
60
+ ? `rainbow-bracket-${color}`
61
+ : `default-bracket`;
62
+
53
63
  decorations.push(
54
64
  Decoration.mark({
55
- class: `rainbow-bracket-${color}`,
65
+ class: bracketClass,
56
66
  }).range(open.from, open.from + 1),
57
67
  Decoration.mark({
58
- class: `rainbow-bracket-${color}`,
68
+ class: bracketClass,
59
69
  }).range(pos, pos + 1),
60
70
  );
61
71
  }
@@ -105,6 +115,8 @@ export default function rainbowBrackets() {
105
115
  },
106
116
  '.rainbow-bracket-green': { color: '#B2FFB2' },
107
117
  '.rainbow-bracket-green > span': { color: '#B2FFB2' },
118
+ '.default-bracket': { color: 'currentColor' },
119
+ '.default-bracket > span': { color: 'currentColor' },
108
120
  }),
109
121
  ];
110
122
  }
@@ -48,4 +48,109 @@
48
48
  .cm-line {
49
49
  font-family: var(--vzcode-font-family);
50
50
  }
51
- }
51
+
52
+ .tooltip_hover_circle {
53
+ color: white;
54
+ text-align: center;
55
+ position: fixed;
56
+ background-color: black;
57
+ padding: 5px;
58
+ border-radius: 5px;
59
+ white-space: nowrap;
60
+ opacity: 0;
61
+ transition: opacity 0.3s ease;
62
+ z-index: 1000;
63
+ pointer-events: none;
64
+ }
65
+
66
+ .tooltip_hover_circle strong {
67
+ font-size: 14px;
68
+ }
69
+
70
+ .tooltip_hover_circle div {
71
+ font-size: 12px;
72
+ }
73
+
74
+ .cm-panel.cm-search {
75
+ padding: 5px;
76
+ position: relative;
77
+ background-color: var(--vh-color-neutral-01);
78
+ border-radius: 6px;
79
+ color: var(--vh-color-neutral-04);
80
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
81
+ }
82
+
83
+ .cm-panels {
84
+ background-color: #333338;
85
+ color: var(--vh-color-neutral-04);
86
+ border: 2px solid var(--vh-color-neutral-02);
87
+ border-radius: 6px;
88
+ }
89
+
90
+ .cm-textfield {
91
+ background-color: var(--vh-color-neutral-01);
92
+ color: #efe7dc;
93
+ border: 1px solid var(--vh-color-neutral-04);
94
+ padding: 8px;
95
+ border-radius: 6px;
96
+ font-size: 14px;
97
+ }
98
+
99
+ .cm-button {
100
+ background-color: var(--vh-color-neutral-01);
101
+ border: 1px solid #193350;
102
+ color: var(--vh-color-neutral-04);
103
+ border: 1px solid var(--vh-color-neutral-04);
104
+ border-radius: 5px;
105
+ padding: 6px 12px;
106
+ font-weight: bold;
107
+ cursor: pointer;
108
+ transition: all 0.3s ease-in-out;
109
+ }
110
+
111
+ .cm-button:hover {
112
+ background-color: #50c878;
113
+ color: #ffffff;
114
+ transform: scale(1.1);
115
+ }
116
+
117
+ .cm-button:active {
118
+ background-color: #202e46;
119
+ transform: scale(0.95);
120
+ }
121
+
122
+ .cm-searchMatch {
123
+ background-color: rgba(255, 255, 0, 0.5);
124
+ border-radius: 2px;
125
+ }
126
+
127
+ .cm-searchMatch-selected {
128
+ background-color: rgba(255, 140, 0, 0.5);
129
+ border: 2px solid #ff8800;
130
+ border-radius: 2px;
131
+ }
132
+ .cm-panel.cm-search [name="close"] {
133
+ position: absolute;
134
+ top: 0;
135
+ right: 4px;
136
+ background-color: var(--vh-color-neutral-01);
137
+ color: var(--vh-color-neutral-04);
138
+ border: none;
139
+ font: inherit;
140
+ padding: 4px 8px;
141
+ margin: 4px;
142
+ border-radius: 4px;
143
+ cursor: pointer;
144
+ transition: all 0.3s ease-in-out;
145
+ }
146
+
147
+ .cm-panel.cm-search [name="close"]:hover {
148
+ background-color: var(--vh-color-caution-01);
149
+ color: #ffffff;
150
+ }
151
+
152
+ .cm-panel.cm-search [name="close"]:active {
153
+ background-color: var(--vh-color-caution-02);
154
+ transform: scale(0.95);
155
+ }
156
+ }
@@ -0,0 +1,25 @@
1
+ export const MicSVG = () => (
2
+ <svg
3
+ fill="#000000"
4
+ height="24"
5
+ width="24"
6
+ stroke="currentColor"
7
+ version="1.1"
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ viewBox="0 0 512 512"
10
+ enable-background="new 0 0 512 512"
11
+ >
12
+ <g>
13
+ <g>
14
+ <path
15
+ fill="currentColor"
16
+ d="m439.5,236c0-11.3-9.1-20.4-20.4-20.4s-20.4,9.1-20.4,20.4c0,70-64,126.9-142.7,126.9-78.7,0-142.7-56.9-142.7-126.9 0-11.3-9.1-20.4-20.4-20.4s-20.4,9.1-20.4,20.4c0,86.2 71.5,157.4 163.1,166.7v57.5h-23.6c-11.3,0-20.4,9.1-20.4,20.4 0,11.3 9.1,20.4 20.4,20.4h88c11.3,0 20.4-9.1 20.4-20.4 0-11.3-9.1-20.4-20.4-20.4h-23.6v-57.5c91.6-9.3 163.1-80.5 163.1-166.7z"
17
+ />
18
+ <path
19
+ fill="currentColor"
20
+ d="m256,323.5c51,0 92.3-41.3 92.3-92.3v-127.9c0-51-41.3-92.3-92.3-92.3s-92.3,41.3-92.3,92.3v127.9c0,51 41.3,92.3 92.3,92.3zm-52.3-220.2c0-28.8 23.5-52.3 52.3-52.3s52.3,23.5 52.3,52.3v127.9c0,28.8-23.5,52.3-52.3,52.3s-52.3-23.5-52.3-52.3v-127.9z"
21
+ />
22
+ </g>
23
+ </g>
24
+ </svg>
25
+ );
@@ -1,4 +1,4 @@
1
- import { useCallback, useContext, useState } from 'react';
1
+ import { useCallback, useContext, useEffect, useState } from 'react';
2
2
  import { PlaySVG } from '../Icons';
3
3
  import { SplitEditorSVG } from '../Icons/SplitEditorSVG';
4
4
  import { VZCodeContext } from '../VZCodeContext';
@@ -17,7 +17,7 @@ export const RunCodeWidget = ({
17
17
  </>
18
18
  ),
19
19
  }: {
20
- runCodeWidgetTooltipText?: JSX.Element;
20
+ runCodeWidgetTooltipText?: JSX.Element;
21
21
  }) => {
22
22
  const { runCodeRef, runPrettierRef, splitCurrentPane } =
23
23
  useContext(VZCodeContext);
@@ -40,7 +40,7 @@ export const RunCodeWidget = ({
40
40
 
41
41
  // Optional: reset the icon state after animation completes (e.g., 1 second)
42
42
  setTimeout(() => setIsRunning(false), 1000);
43
- }, []);
43
+ }, [runCodeRef, runPrettierRef]);
44
44
 
45
45
  const handleSplitEditor = useCallback(() => {
46
46
  console.log('Split Editor');
@@ -48,6 +48,23 @@ export const RunCodeWidget = ({
48
48
  splitCurrentPane();
49
49
  }, [splitCurrentPane]);
50
50
 
51
+ // Add the keyboard event listener for Ctrl+S and Shift+Enter
52
+ useEffect(() => {
53
+ const handleKeyDown = (event: KeyboardEvent) => {
54
+ if ((event.ctrlKey && event.key === 's') || (event.shiftKey && event.key === 'Enter')) {
55
+ event.preventDefault();
56
+ handleClick();
57
+ }
58
+ };
59
+
60
+ window.addEventListener('keydown', handleKeyDown);
61
+
62
+ // Cleanup the event listener on component unmount
63
+ return () => {
64
+ window.removeEventListener('keydown', handleKeyDown);
65
+ };
66
+ }, [handleClick]);
67
+
51
68
  return (
52
69
  <div>
53
70
  <div className="vz-code-split-view-widget">
@@ -2,42 +2,42 @@ import {
2
2
  createContext,
3
3
  useCallback,
4
4
  useReducer,
5
- useState,
6
5
  useRef,
6
+ useState,
7
7
  } from 'react';
8
8
  import {
9
9
  Files,
10
10
  ItemId,
11
+ LeafPane,
12
+ Pane,
13
+ PaneId,
14
+ PresenceIndicator,
15
+ SearchFileVisibility,
16
+ SearchResults,
11
17
  ShareDBDoc,
12
18
  SubmitOperation,
19
+ TabState,
13
20
  Username,
14
21
  VZCodeContent,
15
- SearchResults,
16
- SearchFileVisibility,
17
- TabState,
18
- PresenceIndicator,
19
- Pane,
20
- PaneId,
21
- LeafPane,
22
22
  } from '../types';
23
- import { usePrettier } from './usePrettier';
24
- import { useTypeScript } from './useTypeScript';
25
- import { createInitialState, vzReducer } from './vzReducer';
26
23
  import {
27
24
  ThemeLabel,
28
25
  defaultTheme,
29
26
  useDynamicTheme,
30
27
  } from './themes';
31
28
  import { useActions } from './useActions';
32
- import { useOpenDirectories } from './useOpenDirectories';
33
- import { useFileCRUD } from './useFileCRUD';
34
29
  import {
35
30
  EditorCache,
36
31
  useEditorCache,
37
32
  } from './useEditorCache';
38
- import { useURLSync } from './useURLSync';
33
+ import { useFileCRUD } from './useFileCRUD';
39
34
  import { useKeyboardShortcuts } from './useKeyboardShortcuts';
35
+ import { useOpenDirectories } from './useOpenDirectories';
36
+ import { usePrettier } from './usePrettier';
40
37
  import { useRunCode } from './useRunCode';
38
+ import { useTypeScript } from './useTypeScript';
39
+ import { useURLSync } from './useURLSync';
40
+ import { createInitialState, vzReducer } from './vzReducer';
41
41
  import { findPane } from './vzReducer/findPane';
42
42
 
43
43
  // This context centralizes all the "smart" logic
@@ -156,6 +156,7 @@ export type VZCodeContextValue = {
156
156
  codeEditorRef: React.RefObject<HTMLDivElement>;
157
157
 
158
158
  connected: boolean;
159
+ pending: boolean;
159
160
 
160
161
  hoveredItemId: ItemId | null;
161
162
  setHoveredItemId: (itemId: ItemId | null) => void;
@@ -169,6 +170,15 @@ export type VZCodeContextValue = {
169
170
 
170
171
  sidebarPresenceIndicators: Array<PresenceIndicator>;
171
172
  splitCurrentPane: () => void;
173
+
174
+ liveKitToken: string;
175
+ setLiveKitToken: (state: string) => void;
176
+ liveKitRoomName: string;
177
+ setLiveKitRoom: (state: string) => void;
178
+ liveKitConnection: boolean;
179
+ setLiveKitConnection: (state: boolean) => void;
180
+ voiceChatModalOpen: boolean;
181
+ setVoiceChatModalOpen: (state: boolean) => void;
172
182
  };
173
183
 
174
184
  export const VZCodeProvider = ({
@@ -183,6 +193,13 @@ export const VZCodeProvider = ({
183
193
  children,
184
194
  codeError = null,
185
195
  connected,
196
+ pending,
197
+ liveKitToken,
198
+ setLiveKitToken,
199
+ liveKitRoomName,
200
+ setLiveKitRoom,
201
+ liveKitConnection,
202
+ setLiveKitConnection,
186
203
  }: {
187
204
  content: VZCodeContent;
188
205
  shareDBDoc: ShareDBDoc<VZCodeContent>;
@@ -195,6 +212,13 @@ export const VZCodeProvider = ({
195
212
  children: React.ReactNode;
196
213
  codeError?: string | null;
197
214
  connected: boolean;
215
+ pending: boolean;
216
+ liveKitToken: string | undefined;
217
+ setLiveKitToken: (state: string) => void;
218
+ liveKitRoomName: string | undefined;
219
+ setLiveKitRoom: (state: string) => void;
220
+ liveKitConnection: boolean;
221
+ setLiveKitConnection: (state: boolean) => void;
198
222
  }) => {
199
223
  // Auto-run Pretter after local changes.
200
224
  const {
@@ -393,6 +417,11 @@ export const VZCodeProvider = ({
393
417
  const [hoveredItemId, setHoveredItemId] =
394
418
  useState<ItemId | null>(null);
395
419
 
420
+ // Livekit Voice Chat Modal
421
+
422
+ const [voiceChatModalOpen, setVoiceChatModalOpen] =
423
+ useState(false);
424
+
396
425
  // The value provided by this context.
397
426
  const value: VZCodeContextValue = {
398
427
  content,
@@ -471,6 +500,7 @@ export const VZCodeProvider = ({
471
500
  codeEditorRef,
472
501
 
473
502
  connected,
503
+ pending,
474
504
 
475
505
  hoveredItemId,
476
506
  setHoveredItemId,
@@ -480,6 +510,14 @@ export const VZCodeProvider = ({
480
510
  updatePresenceIndicator,
481
511
  sidebarPresenceIndicators,
482
512
  splitCurrentPane,
513
+ liveKitRoomName,
514
+ setLiveKitRoom,
515
+ liveKitToken,
516
+ setLiveKitToken,
517
+ liveKitConnection,
518
+ setLiveKitConnection,
519
+ voiceChatModalOpen,
520
+ setVoiceChatModalOpen,
483
521
  };
484
522
 
485
523
  return (
@@ -46,41 +46,41 @@ export const VZKeyboardShortcutsDoc = ({
46
46
  {/* <Form.Label>WINDOWS</Form.Label> */}
47
47
  <ul>
48
48
  <li>
49
- <strong>Ctrl + s</strong> or{' '}
50
- <strong>Shift + Enter</strong> <br />
49
+ <strong><kbd>Ctrl</kbd> + <kbd>S</kbd></strong> or{' '}
50
+ <strong><kbd>Shift↑</kbd> + <kbd>Enter←</kbd></strong> <br />
51
51
  <span>Run and format code</span>
52
52
  </li>
53
53
  <li>
54
- <strong>Alt + drag on a number</strong>
54
+ <strong><kbd>Alt</kbd> + Drag on a number</strong>
55
55
  <br />
56
56
  <span>
57
57
  Modify the number by dragging left or right
58
58
  </span>
59
59
  </li>
60
60
  <li>
61
- <strong>Alt + click on a hex color</strong>
61
+ <strong><kbd>Alt</kbd> + Click on a hex color</strong>
62
62
  <br />
63
63
  <span>
64
64
  Open a color picker to modify the color
65
65
  </span>
66
66
  </li>
67
67
  <li>
68
- <strong>Alt + w</strong> <br />
68
+ <strong><kbd>Alt</kbd> + <kbd>W</kbd></strong> <br />
69
69
  <span>Close the current tab</span>
70
70
  </li>
71
71
  <li>
72
- <strong>Alt + n or Ctrl + Shift + n</strong>{' '}
72
+ <strong><kbd>Alt</kbd> + <kbd>N</kbd></strong> or{' '} <strong><kbd>Ctrl</kbd> + <kbd>Shift↑</kbd> + <kbd>N</kbd></strong>{' '}
73
73
  <br />
74
74
  <span>Open the create file modal</span>
75
75
  </li>
76
76
  <li>
77
- <strong>Alt + Page Up</strong> <br />
77
+ <strong><kbd>Alt</kbd> + <kbd>PgUp↑</kbd></strong> <br />
78
78
  <span>
79
79
  Change the active tab to the previous one
80
80
  </span>
81
81
  </li>
82
82
  <li>
83
- <strong>Alt + Page Down</strong> <br />
83
+ <strong><kbd>Alt</kbd> + <kbd>PgDn↓</kbd></strong> <br />
84
84
  <span>
85
85
  Change the active tab to the next one
86
86
  </span>
@@ -1,8 +1,10 @@
1
- import { VZSettings } from './VZSettings';
1
+ import { enableLiveKit } from './featureFlags';
2
2
  import { VZKeyboardShortcutsDoc } from './VZKeyboardShortcutsDoc';
3
+ import { VZSettings } from './VZSettings';
3
4
  import { VZSidebar } from './VZSidebar';
4
- import { CreateFileModal } from './VZSidebar/CreateFileModal';
5
5
  import { CreateDirModal } from './VZSidebar/CreateDirModal';
6
+ import { CreateFileModal } from './VZSidebar/CreateFileModal';
7
+ import { VoiceChatModal } from './VZSidebar/VoiceChatModal';
6
8
 
7
9
  // The middle portion of the VZCode environment, containing:
8
10
  // * The sidebar
@@ -20,6 +22,7 @@ export const VZLeft = ({ enableUsernameField = true }) => {
20
22
  />
21
23
  <CreateFileModal />
22
24
  <CreateDirModal />
25
+ {enableLiveKit && <VoiceChatModal />}
23
26
  </div>
24
27
  );
25
28
  };
@@ -23,6 +23,7 @@ const PaneView = ({
23
23
  aiAssistOptions,
24
24
  aiAssistTooltipText,
25
25
  aiAssistClickOverride,
26
+ aiCopilotEndpoint,
26
27
  }) => {
27
28
  // This prevents the CodeEditor from rendering
28
29
  // during SSR.
@@ -49,6 +50,7 @@ const PaneView = ({
49
50
  <CodeEditor
50
51
  customInteractRules={customInteractRules}
51
52
  allowGlobals={allowGlobals}
53
+ aiCopilotEndpoint={aiCopilotEndpoint}
52
54
  />
53
55
  )}
54
56
  {isClient &&
@@ -82,6 +84,7 @@ export const VZMiddle = ({
82
84
  aiAssistOptions,
83
85
  aiAssistTooltipText,
84
86
  aiAssistClickOverride,
87
+ aiCopilotEndpoint,
85
88
  customInteractRules,
86
89
  allowGlobals = false,
87
90
  }: {
@@ -90,6 +93,7 @@ export const VZMiddle = ({
90
93
  aiAssistOptions?: { [key: string]: string };
91
94
  aiAssistTooltipText?: string;
92
95
  aiAssistClickOverride?: () => void;
96
+ aiCopilotEndpoint?: string;
93
97
  customInteractRules?: Array<InteractRule>;
94
98
  allowGlobals?: boolean;
95
99
  }) => {
@@ -128,6 +132,7 @@ export const VZMiddle = ({
128
132
  aiAssistOptions={aiAssistOptions}
129
133
  aiAssistTooltipText={aiAssistTooltipText}
130
134
  aiAssistClickOverride={aiAssistClickOverride}
135
+ aiCopilotEndpoint={aiCopilotEndpoint}
131
136
  />
132
137
  <CodeErrorOverlay
133
138
  errorMessage={errorMessage}