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/assets/{index-BRU-VQpy.js → index-Cw7RI1uP.js} +168 -104
- package/dist/assets/{index-lvLw6dCW.css → index-DKLiE98a.css} +1 -1
- package/dist/index.html +2 -2
- package/package.json +3 -3
- package/src/client/VZSidebar/aiCopyPaste.ts +124 -0
- package/src/client/VZSidebar/index.tsx +38 -12
- package/src/client/VZSidebar/styles.scss +49 -0
- package/src/client/index.ts +1 -0
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-
|
|
24
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
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.
|
|
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.
|
|
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.
|
|
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;
|
package/src/client/index.ts
CHANGED