vzcode 1.37.0 → 1.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.html CHANGED
@@ -20,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-BRU-VQpy.js"></script>
24
- <link rel="stylesheet" crossorigin href="/assets/index-lvLw6dCW.css">
23
+ <script type="module" crossorigin src="/assets/index-Cw7RI1uP.js"></script>
24
+ <link rel="stylesheet" crossorigin href="/assets/index-DKLiE98a.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.37.0",
3
+ "version": "1.38.0",
4
4
  "description": "Multiplayer code editor system",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -114,7 +114,7 @@
114
114
  "@codemirror/state": "^6.5.2",
115
115
  "@codemirror/theme-one-dark": "^6.1.3",
116
116
  "@codemirror/view": "^6.38.1",
117
- "@langchain/core": "^0.3.65",
117
+ "@langchain/core": "^0.3.66",
118
118
  "@langchain/openai": "^0.6.2",
119
119
  "@lezer/highlight": "^1.2.1",
120
120
  "@livekit/components-react": "^2.9.14",
@@ -145,7 +145,7 @@
145
145
  "d3-array": "^3.2.4",
146
146
  "diff-match-patch": "^1.0.5",
147
147
  "dotenv": "^17.2.0",
148
- "editcodewithai": "^2.0.0",
148
+ "editcodewithai": "^2.2.0",
149
149
  "eslint": "^9.31.0",
150
150
  "eslint-linter-browserify": "^9.31.0",
151
151
  "express": "^5.1.0",
@@ -0,0 +1,124 @@
1
+ import {
2
+ formatMarkdownFiles,
3
+ parseMarkdownFiles,
4
+ } from 'llm-code-format';
5
+ import {
6
+ FORMAT_INSTRUCTIONS,
7
+ mergeFileChanges,
8
+ } from 'editcodewithai';
9
+ import { VizFiles } from '@vizhub/viz-types';
10
+ import { vizFilesToFileCollection } from '@vizhub/viz-utils';
11
+
12
+ export const createAICopyPasteHandlers = (
13
+ files: VizFiles,
14
+ submitOperation: any,
15
+ setCopyButtonText: (text: string) => void,
16
+ setPasteButtonText: (text: string) => void,
17
+ ) => {
18
+ // Copy for AI - formats all files and copies to clipboard
19
+ const handleCopyForAI = async () => {
20
+ if (!files) return;
21
+
22
+ try {
23
+ const fileCollection =
24
+ vizFilesToFileCollection(files);
25
+
26
+ // Format files for AI consumption
27
+ const formattedFiles =
28
+ formatMarkdownFiles(fileCollection) +
29
+ '\n\n' +
30
+ FORMAT_INSTRUCTIONS.whole;
31
+
32
+ // Copy to clipboard
33
+ await navigator.clipboard.writeText(formattedFiles);
34
+
35
+ // Show success feedback
36
+ setCopyButtonText('Copied!');
37
+ setTimeout(
38
+ () => setCopyButtonText('Copy for AI'),
39
+ 2000,
40
+ );
41
+ } catch (error) {
42
+ console.error('Failed to copy files for AI:', error);
43
+ setCopyButtonText('Error');
44
+ setTimeout(
45
+ () => setCopyButtonText('Copy for AI'),
46
+ 2000,
47
+ );
48
+ }
49
+ };
50
+
51
+ // Paste for AI - parses clipboard content and updates files
52
+ const handlePasteForAI = async () => {
53
+ if (!submitOperation) return;
54
+
55
+ try {
56
+ // Read from clipboard
57
+ const clipboardText =
58
+ await navigator.clipboard.readText();
59
+
60
+ // Handle various line endings
61
+ const normalized = clipboardText.replace(
62
+ /\r\n?/g,
63
+ '\n',
64
+ );
65
+
66
+ if (!normalized.trim()) {
67
+ setPasteButtonText('Empty clipboard');
68
+ setTimeout(
69
+ () => setPasteButtonText('Paste for AI'),
70
+ 2000,
71
+ );
72
+ return;
73
+ }
74
+
75
+ // Parse the markdown files format
76
+ const parsed = parseMarkdownFiles(normalized, 'bold');
77
+
78
+ if (
79
+ parsed.files &&
80
+ Object.keys(parsed.files).length > 0
81
+ ) {
82
+ // Use mergeFileChanges utility from editcodewithai
83
+ const mergedFiles = mergeFileChanges(
84
+ files,
85
+ parsed.files,
86
+ );
87
+
88
+ // Update files using the submit operation
89
+ submitOperation((document) => ({
90
+ ...document,
91
+ files: mergedFiles,
92
+ }));
93
+
94
+ const fileCount = Object.keys(parsed.files).length;
95
+ setPasteButtonText('Pasted!');
96
+ setTimeout(
97
+ () => setPasteButtonText('Paste for AI'),
98
+ 2000,
99
+ );
100
+ } else {
101
+ setPasteButtonText('No files found');
102
+ setTimeout(
103
+ () => setPasteButtonText('Paste for AI'),
104
+ 2000,
105
+ );
106
+ }
107
+ } catch (error) {
108
+ console.error(
109
+ 'Failed to paste files from AI:',
110
+ error,
111
+ );
112
+ setPasteButtonText('Error');
113
+ setTimeout(
114
+ () => setPasteButtonText('Paste for AI'),
115
+ 2000,
116
+ );
117
+ }
118
+ };
119
+
120
+ return {
121
+ handleCopyForAI,
122
+ handlePasteForAI,
123
+ };
124
+ };
@@ -35,15 +35,13 @@ import { AIChat } from './AIChat';
35
35
  import { Listing } from './Listing';
36
36
  import { Search } from './Search';
37
37
  import { useDragAndDrop } from './useDragAndDrop';
38
+ import { createAICopyPasteHandlers } from './aiCopyPaste';
38
39
  import {
39
40
  enableLiveKit,
40
41
  enableAIChat,
41
42
  } from '../featureFlags';
42
43
  import './styles.scss';
43
44
 
44
- // TODO turn this UI back on when we are actually detecting
45
- // the connection status.
46
- // See https://github.com/vizhub-core/vzcode/issues/456
47
45
  const enableConnectionStatus = true;
48
46
 
49
47
  export const VZSidebar = ({
@@ -146,10 +144,8 @@ export const VZSidebar = ({
146
144
  toggleAutoFollow,
147
145
  docPresence,
148
146
  updatePresenceIndicator,
149
- sidebarPresenceIndicators,
150
- liveKitConnection,
151
- setLiveKitConnection,
152
147
  setVoiceChatModalOpen,
148
+ submitOperation,
153
149
  } = useContext(VZCodeContext);
154
150
 
155
151
  const fileTree = useMemo(
@@ -163,6 +159,24 @@ export const VZSidebar = ({
163
159
  setIsSettingsOpen(true);
164
160
  }, []);
165
161
 
162
+ // State for AI operation feedback
163
+ const [copyButtonText, setCopyButtonText] =
164
+ useState('Copy for AI');
165
+ const [pasteButtonText, setPasteButtonText] =
166
+ useState('Paste for AI');
167
+
168
+ // Create AI copy/paste handlers
169
+ const { handleCopyForAI, handlePasteForAI } = useMemo(
170
+ () =>
171
+ createAICopyPasteHandlers(
172
+ files,
173
+ submitOperation,
174
+ setCopyButtonText,
175
+ setPasteButtonText,
176
+ ),
177
+ [files, submitOperation],
178
+ );
179
+
166
180
  const { sidebarWidth } = useContext(
167
181
  SplitPaneResizeContext,
168
182
  );
@@ -215,12 +229,6 @@ export const VZSidebar = ({
215
229
  fileId: update.start[1] as VizFileId,
216
230
  };
217
231
 
218
- // console.log('Got presence!');
219
- // // console.log({presenceId,update})
220
- // console.log(
221
- // JSON.stringify(presenceIndicator, null, 2),
222
- // );
223
-
224
232
  updatePresenceIndicator(presenceIndicator);
225
233
  };
226
234
 
@@ -532,6 +540,24 @@ export const VZSidebar = ({
532
540
  )}
533
541
  </div>
534
542
  </div>
543
+ {!isAIChatOpen && !isSearchOpen && filesExist && (
544
+ <div className="ai-buttons">
545
+ <button
546
+ className="ai-button copy-button"
547
+ onClick={handleCopyForAI}
548
+ title="Copy files formatted for AI"
549
+ >
550
+ {copyButtonText}
551
+ </button>
552
+ <button
553
+ className="ai-button paste-button"
554
+ onClick={handlePasteForAI}
555
+ title="Paste files from AI"
556
+ >
557
+ {pasteButtonText}
558
+ </button>
559
+ </div>
560
+ )}
535
561
  {enableConnectionStatus && (
536
562
  <div className="connection-status">
537
563
  {isConnecting
@@ -297,6 +297,55 @@
297
297
  }
298
298
  }
299
299
  }
300
+
301
+ .ai-buttons {
302
+ display: flex;
303
+ flex-direction: column;
304
+ gap: 8px;
305
+ padding: 10px 10px 0 10px;
306
+ border-top: 1px solid var(--vh-color-neutral-02);
307
+
308
+ .ai-button {
309
+ padding: 8px 12px;
310
+ border: 1px solid var(--vh-color-neutral-03);
311
+ border-radius: 6px;
312
+ background: var(--vh-color-neutral-01);
313
+ color: var(--vh-color-neutral-04);
314
+ font-size: 12px;
315
+ font-weight: 500;
316
+ font-family: var(--vzcode-font-family);
317
+ cursor: pointer;
318
+ transition: all 0.2s ease;
319
+
320
+ &:hover {
321
+ background: var(--vh-color-hover-dark);
322
+ border-color: var(--vh-color-neutral-04);
323
+ }
324
+
325
+ &:active {
326
+ background: var(--vh-color-neutral-03);
327
+ }
328
+
329
+ &.copy-button {
330
+ border-color: var(--vh-color-primary-03);
331
+
332
+ &:hover {
333
+ background: var(--vh-color-hover-dark);
334
+ border-color: var(--vh-color-primary-04);
335
+ }
336
+ }
337
+
338
+ &.paste-button {
339
+ border-color: var(--vh-color-success-03);
340
+
341
+ &:hover {
342
+ background: var(--vh-color-hover-dark);
343
+ border-color: var(--vh-color-success-04);
344
+ }
345
+ }
346
+ }
347
+ }
348
+
300
349
  .name {
301
350
  display: flex;
302
351
  align-items: center;
@@ -14,5 +14,6 @@ export {
14
14
  } from './SplitPaneResizeContext';
15
15
  export { useSubmitOperation } from './useSubmitOperation';
16
16
  export { shouldTriggerRun } from './shouldTriggerRun';
17
+ export { mergeFileChanges } from 'editcodewithai';
17
18
 
18
19
  export * from './Icons';