vzcode 2.17.0 → 2.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.
- package/dist/assets/{bindings_wasm_bg-D9vNLG9F.wasm → bindings_wasm_bg-9w8E-TmY.wasm} +0 -0
- package/dist/assets/buildWorker-Bi6wsfQk.js +695 -0
- package/dist/assets/index-DuDXdJWC.js +477 -0
- package/dist/assets/worker-BSzbM0Uo.js +330 -0
- package/dist/assets/{worker-CmHJK_do.js → worker-ClF0pBYr.js} +74 -74
- package/dist/index.html +1 -1
- package/dist/server/aiChatHandler/aiEditing.js +3 -34
- package/dist/server/aiChatHandler/chatOperations.js +2 -0
- package/dist/server/aiChatHandler/llmStreaming.js +13 -31
- package/dist/server/prettier.js +15 -6
- package/package.json +17 -17
- package/src/client/CodeEditor/index.tsx +1 -4
- package/src/server/aiChatHandler/aiEditing.ts +3 -52
- package/src/server/aiChatHandler/chatOperations.ts +2 -0
- package/src/server/aiChatHandler/llmStreaming.ts +25 -44
- package/src/server/prettier.ts +25 -9
- package/dist/assets/buildWorker-DL4wXpRr.js +0 -695
- package/dist/assets/index-BiPmUreW.js +0 -474
- package/dist/assets/worker-RJ-cjbld.js +0 -327
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-
|
|
23
|
+
<script type="module" crossorigin src="/assets/index-DuDXdJWC.js"></script>
|
|
24
24
|
<link rel="stylesheet" crossorigin href="/assets/index-BvGPtSrr.css">
|
|
25
25
|
</head>
|
|
26
26
|
<body>
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { assembleFullPrompt, prepareFilesForPrompt, } from 'editcodewithai';
|
|
2
2
|
import { formatMarkdownFiles } from 'llm-code-format';
|
|
3
3
|
import { createFilesSnapshot, generateFilesUnifiedDiff, } from '../../utils/fileDiff.js';
|
|
4
|
-
import { formatFiles } from '../prettier.js';
|
|
5
|
-
import { createSubmitOperation } from '../../submitOperation.js';
|
|
6
4
|
// Dev flag for waiting 1 second before starting the LLM function.
|
|
7
5
|
// Useful for debugging and testing purposes, e.g. checking the typing indicator.
|
|
8
6
|
const delayStart = false;
|
|
@@ -33,11 +31,11 @@ export const performAIChat = async ({ prompt, shareDBDoc, llmFunction, }) => {
|
|
|
33
31
|
* Performs AI editing operations using streaming with incremental OT operations
|
|
34
32
|
*/
|
|
35
33
|
export const performAIEditing = async ({ prompt, shareDBDoc, llmFunction, runCode, }) => {
|
|
36
|
-
//
|
|
34
|
+
// Capture the current state of files before editing
|
|
37
35
|
const beforeFiles = createFilesSnapshot(shareDBDoc.data.files);
|
|
38
36
|
const { files } = prepareFilesForPrompt(shareDBDoc.data.files);
|
|
39
37
|
const filesContext = formatMarkdownFiles(files);
|
|
40
|
-
//
|
|
38
|
+
// Assemble the final prompt
|
|
41
39
|
const fullPrompt = assembleFullPrompt({
|
|
42
40
|
filesContext,
|
|
43
41
|
prompt,
|
|
@@ -46,37 +44,8 @@ export const performAIEditing = async ({ prompt, shareDBDoc, llmFunction, runCod
|
|
|
46
44
|
if (delayStart) {
|
|
47
45
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
48
46
|
}
|
|
49
|
-
// Call the LLM function which will handle streaming
|
|
47
|
+
// Call the LLM function which will handle streaming, incremental file updates, and Prettier formatting
|
|
50
48
|
const result = await llmFunction(fullPrompt);
|
|
51
|
-
// 3. Run Prettier on changed files before running code
|
|
52
|
-
const afterLLMFiles = createFilesSnapshot(shareDBDoc.data.files);
|
|
53
|
-
// Find files that were changed by the AI
|
|
54
|
-
const changedFileIds = Object.keys(afterLLMFiles).filter((fileId) => beforeFiles[fileId]?.text !==
|
|
55
|
-
afterLLMFiles[fileId]?.text);
|
|
56
|
-
if (changedFileIds.length > 0) {
|
|
57
|
-
// Format the changed files
|
|
58
|
-
const formattedFiles = await formatFiles(shareDBDoc.data.files, changedFileIds);
|
|
59
|
-
// Apply formatted versions to shareDBDoc if formatting succeeded
|
|
60
|
-
if (Object.keys(formattedFiles).length > 0) {
|
|
61
|
-
const submitOperation = createSubmitOperation(shareDBDoc);
|
|
62
|
-
submitOperation((document) => {
|
|
63
|
-
const updatedFiles = { ...document.files };
|
|
64
|
-
// Apply each formatted file
|
|
65
|
-
Object.entries(formattedFiles).forEach(([fileId, formattedText]) => {
|
|
66
|
-
if (updatedFiles[fileId]) {
|
|
67
|
-
updatedFiles[fileId] = {
|
|
68
|
-
...updatedFiles[fileId],
|
|
69
|
-
text: formattedText,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
return {
|
|
74
|
-
...document,
|
|
75
|
-
files: updatedFiles,
|
|
76
|
-
};
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
49
|
runCode();
|
|
81
50
|
// 4. Capture the state of files after editing and formatting, then generate diff
|
|
82
51
|
const afterFiles = createFilesSnapshot(shareDBDoc.data.files);
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import OpenAI from 'openai';
|
|
2
2
|
import { parseMarkdownFiles, StreamingMarkdownParser, } from 'llm-code-format';
|
|
3
3
|
import { mergeFileChanges } from 'editcodewithai';
|
|
4
|
-
import { generateRunId } from '@vizhub/viz-utils';
|
|
5
4
|
import { updateFiles, updateAIScratchpad, createStreamingAIMessage, addStreamingEvent, updateStreamingStatus, finalizeStreamingMessage, } from './chatOperations.js';
|
|
6
|
-
import {
|
|
5
|
+
import { formatFiles } from '../prettier.js';
|
|
7
6
|
const DEBUG = false;
|
|
8
7
|
// Useful for testing/debugging the streaming behavior
|
|
9
8
|
const slowMode = false;
|
|
@@ -191,37 +190,20 @@ enableReasoningTokens = false, model, aiRequestOptions, }) => {
|
|
|
191
190
|
if (currentEditingFileName) {
|
|
192
191
|
await completeFileEditing(currentEditingFileName);
|
|
193
192
|
}
|
|
193
|
+
// // Capture the current state of files before applying changes
|
|
194
|
+
// const beforeFiles = createFilesSnapshot(
|
|
195
|
+
// shareDBDoc.data.files,
|
|
196
|
+
// );
|
|
197
|
+
// Parse the full content to extract file changes
|
|
198
|
+
// export type FileCollection = Record<string, string>;
|
|
199
|
+
const newFilesUnformatted = parseMarkdownFiles(fullContent, 'bold').files;
|
|
200
|
+
// Run Prettier on `newFiles` before applying them
|
|
201
|
+
const newFilesFormatted = await formatFiles(newFilesUnformatted);
|
|
194
202
|
// Apply all the edits at once
|
|
195
|
-
|
|
203
|
+
const mergedChanges = mergeFileChanges(shareDBDoc.data.files, newFilesFormatted);
|
|
204
|
+
updateFiles(shareDBDoc, mergedChanges);
|
|
196
205
|
// Finalize streaming message
|
|
197
|
-
|
|
198
|
-
// Generate a new runId to trigger a run when AI finishes editing
|
|
199
|
-
// This will trigger a re-run without hot reloading
|
|
200
|
-
const newRunId = generateRunId();
|
|
201
|
-
const runIdOp = diff(shareDBDoc.data, {
|
|
202
|
-
...shareDBDoc.data,
|
|
203
|
-
runId: newRunId,
|
|
204
|
-
});
|
|
205
|
-
shareDBDoc.submitOp(runIdOp, (error) => {
|
|
206
|
-
if (error) {
|
|
207
|
-
console.warn('Error setting runId after AI editing:', error);
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
DEBUG &&
|
|
211
|
-
console.log('Set new runId after AI editing:', newRunId);
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
// Write chunks file for debugging
|
|
215
|
-
// if (DEBUG) {
|
|
216
|
-
// const chunksFileJSONpath = `./ai-chunks-${chatId}.json`;
|
|
217
|
-
// fs.writeFileSync(
|
|
218
|
-
// chunksFileJSONpath,
|
|
219
|
-
// JSON.stringify(chunks, null, 2),
|
|
220
|
-
// );
|
|
221
|
-
// console.log(
|
|
222
|
-
// `AI chunks written to ${chunksFileJSONpath}`,
|
|
223
|
-
// );
|
|
224
|
-
// }
|
|
206
|
+
finalizeStreamingMessage(shareDBDoc, chatId);
|
|
225
207
|
return {
|
|
226
208
|
content: fullContent,
|
|
227
209
|
generationId: generationId,
|
package/dist/server/prettier.js
CHANGED
|
@@ -72,16 +72,25 @@ export const formatFile = async (fileText, fileName) => {
|
|
|
72
72
|
* Only formats files that have supported extensions
|
|
73
73
|
* Returns a map of fileId -> formatted text for successfully formatted files
|
|
74
74
|
*/
|
|
75
|
-
export const formatFiles = async (
|
|
75
|
+
export const formatFiles = async (fileCollection) => {
|
|
76
76
|
const results = {};
|
|
77
|
-
const targetFileIds =
|
|
77
|
+
const targetFileIds = Object.keys(fileCollection);
|
|
78
78
|
// Process files in parallel for better performance
|
|
79
79
|
const formatPromises = targetFileIds.map(async (fileId) => {
|
|
80
|
-
const
|
|
81
|
-
if (!
|
|
80
|
+
const fileData = fileCollection[fileId];
|
|
81
|
+
if (!fileData)
|
|
82
82
|
return;
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
// Handle both FileCollection format and test format
|
|
84
|
+
const fileName = typeof fileData === 'string'
|
|
85
|
+
? fileId
|
|
86
|
+
: fileData.name;
|
|
87
|
+
const fileText = typeof fileData === 'string'
|
|
88
|
+
? fileData
|
|
89
|
+
: fileData.text;
|
|
90
|
+
if (!fileText)
|
|
91
|
+
return;
|
|
92
|
+
const formatted = await formatFile(fileText, fileName);
|
|
93
|
+
if (formatted !== null && formatted !== fileText) {
|
|
85
94
|
results[fileId] = formatted;
|
|
86
95
|
}
|
|
87
96
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vzcode",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.0",
|
|
4
4
|
"description": "Multiplayer code editor system",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -130,15 +130,15 @@
|
|
|
130
130
|
"@replit/codemirror-vscode-keymap": "^6.0.2",
|
|
131
131
|
"@teamwork/websocket-json-stream": "^2.0.0",
|
|
132
132
|
"@typescript/vfs": "^1.6.1",
|
|
133
|
-
"@uiw/codemirror-theme-abcdef": "^4.25.
|
|
134
|
-
"@uiw/codemirror-theme-dracula": "^4.25.
|
|
135
|
-
"@uiw/codemirror-theme-eclipse": "^4.25.
|
|
136
|
-
"@uiw/codemirror-theme-github": "^4.25.
|
|
137
|
-
"@uiw/codemirror-theme-material": "^4.25.
|
|
138
|
-
"@uiw/codemirror-theme-nord": "^4.25.
|
|
139
|
-
"@uiw/codemirror-theme-okaidia": "^4.25.
|
|
140
|
-
"@uiw/codemirror-theme-xcode": "^4.25.
|
|
141
|
-
"@uiw/codemirror-themes": "^4.25.
|
|
133
|
+
"@uiw/codemirror-theme-abcdef": "^4.25.2",
|
|
134
|
+
"@uiw/codemirror-theme-dracula": "^4.25.2",
|
|
135
|
+
"@uiw/codemirror-theme-eclipse": "^4.25.2",
|
|
136
|
+
"@uiw/codemirror-theme-github": "^4.25.2",
|
|
137
|
+
"@uiw/codemirror-theme-material": "^4.25.2",
|
|
138
|
+
"@uiw/codemirror-theme-nord": "^4.25.2",
|
|
139
|
+
"@uiw/codemirror-theme-okaidia": "^4.25.2",
|
|
140
|
+
"@uiw/codemirror-theme-xcode": "^4.25.2",
|
|
141
|
+
"@uiw/codemirror-themes": "^4.25.2",
|
|
142
142
|
"@valtown/codemirror-ts": "^2.3.1",
|
|
143
143
|
"@vizhub/runtime": "^4.5.0",
|
|
144
144
|
"@vizhub/viz-types": "^0.5.0",
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
"bootstrap-icons": "^1.13.1",
|
|
148
148
|
"codemirror": "^6.0.2",
|
|
149
149
|
"codemirror-copilot": "^0.0.7",
|
|
150
|
-
"codemirror-ot": "^5.
|
|
150
|
+
"codemirror-ot": "^5.6.0",
|
|
151
151
|
"color-hash": "^2.0.2",
|
|
152
152
|
"comlink": "^4.4.2",
|
|
153
153
|
"d3-array": "^3.2.4",
|
|
@@ -157,7 +157,7 @@
|
|
|
157
157
|
"diff2html": "^3.4.52",
|
|
158
158
|
"dotenv": "^17.2.2",
|
|
159
159
|
"editcodewithai": "^2.4.0",
|
|
160
|
-
"eslint-linter-browserify": "^9.
|
|
160
|
+
"eslint-linter-browserify": "^9.36.0",
|
|
161
161
|
"express": "^5.1.0",
|
|
162
162
|
"ignore": "^7.0.5",
|
|
163
163
|
"json0-ot-diff": "^1.1.2",
|
|
@@ -181,7 +181,7 @@
|
|
|
181
181
|
"ws": "^8.18.3"
|
|
182
182
|
},
|
|
183
183
|
"devDependencies": {
|
|
184
|
-
"@eslint/js": "^9.
|
|
184
|
+
"@eslint/js": "^9.36.0",
|
|
185
185
|
"@tauri-apps/cli": "^2.8.4",
|
|
186
186
|
"@types/d3-color": "^3.1.3",
|
|
187
187
|
"@types/react": "^18",
|
|
@@ -191,12 +191,12 @@
|
|
|
191
191
|
"@vitejs/plugin-react": "^5.0.3",
|
|
192
192
|
"concurrently": "^9.2.1",
|
|
193
193
|
"cross-env": "^10.0.0",
|
|
194
|
-
"eslint": "^9.
|
|
194
|
+
"eslint": "^9.36.0",
|
|
195
195
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
196
196
|
"eslint-plugin-react": "^7.37.5",
|
|
197
197
|
"eslint-plugin-react-hooks": "^5.2.0",
|
|
198
198
|
"globals": "^16.4.0",
|
|
199
|
-
"npm-check-updates": "^18.
|
|
199
|
+
"npm-check-updates": "^18.2.1",
|
|
200
200
|
"prettier": "^3.6.2",
|
|
201
201
|
"sass": "^1.92.1",
|
|
202
202
|
"ts-node": "^10.9.2",
|
|
@@ -205,7 +205,7 @@
|
|
|
205
205
|
"vitest": "^3.2.4"
|
|
206
206
|
},
|
|
207
207
|
"optionalDependencies": {
|
|
208
|
-
"@rollup/rollup-darwin-arm64": "^4.
|
|
209
|
-
"@rollup/rollup-win32-x64-msvc": "^4.
|
|
208
|
+
"@rollup/rollup-darwin-arm64": "^4.51.0",
|
|
209
|
+
"@rollup/rollup-win32-x64-msvc": "^4.51.0"
|
|
210
210
|
}
|
|
211
211
|
}
|
|
@@ -32,7 +32,6 @@ export const CodeEditor = ({
|
|
|
32
32
|
const {
|
|
33
33
|
activePane,
|
|
34
34
|
shareDBDoc,
|
|
35
|
-
content,
|
|
36
35
|
submitOperation,
|
|
37
36
|
localPresence,
|
|
38
37
|
docPresence,
|
|
@@ -152,9 +151,7 @@ export const CodeEditor = ({
|
|
|
152
151
|
useLayoutEffect(() => {
|
|
153
152
|
// Guard against cases where page is still loading.
|
|
154
153
|
if (!codeEditorRef.current) return;
|
|
155
|
-
if (!content) return;
|
|
156
154
|
if (!editorCacheValue) return; // Guard against null editorCacheValue
|
|
157
|
-
// if (openSplitPane) return;
|
|
158
155
|
|
|
159
156
|
const codeEditorEl = codeEditorRef.current;
|
|
160
157
|
|
|
@@ -178,7 +175,7 @@ export const CodeEditor = ({
|
|
|
178
175
|
);
|
|
179
176
|
}
|
|
180
177
|
};
|
|
181
|
-
}, [codeEditorRef,
|
|
178
|
+
}, [codeEditorRef, editorCacheValue]);
|
|
182
179
|
|
|
183
180
|
// Focus the editor
|
|
184
181
|
useEffect(() => {
|
|
@@ -7,9 +7,6 @@ import {
|
|
|
7
7
|
createFilesSnapshot,
|
|
8
8
|
generateFilesUnifiedDiff,
|
|
9
9
|
} from '../../utils/fileDiff.js';
|
|
10
|
-
import { formatFiles } from '../prettier.js';
|
|
11
|
-
import { createSubmitOperation } from '../../submitOperation.js';
|
|
12
|
-
import { VizContent } from '@vizhub/viz-types';
|
|
13
10
|
|
|
14
11
|
// Dev flag for waiting 1 second before starting the LLM function.
|
|
15
12
|
// Useful for debugging and testing purposes, e.g. checking the typing indicator.
|
|
@@ -60,7 +57,7 @@ export const performAIEditing = async ({
|
|
|
60
57
|
llmFunction,
|
|
61
58
|
runCode,
|
|
62
59
|
}) => {
|
|
63
|
-
//
|
|
60
|
+
// Capture the current state of files before editing
|
|
64
61
|
const beforeFiles = createFilesSnapshot(
|
|
65
62
|
shareDBDoc.data.files,
|
|
66
63
|
);
|
|
@@ -70,7 +67,7 @@ export const performAIEditing = async ({
|
|
|
70
67
|
);
|
|
71
68
|
const filesContext = formatMarkdownFiles(files);
|
|
72
69
|
|
|
73
|
-
//
|
|
70
|
+
// Assemble the final prompt
|
|
74
71
|
const fullPrompt = assembleFullPrompt({
|
|
75
72
|
filesContext,
|
|
76
73
|
prompt,
|
|
@@ -83,55 +80,9 @@ export const performAIEditing = async ({
|
|
|
83
80
|
);
|
|
84
81
|
}
|
|
85
82
|
|
|
86
|
-
// Call the LLM function which will handle streaming
|
|
83
|
+
// Call the LLM function which will handle streaming, incremental file updates, and Prettier formatting
|
|
87
84
|
const result = await llmFunction(fullPrompt);
|
|
88
85
|
|
|
89
|
-
// 3. Run Prettier on changed files before running code
|
|
90
|
-
const afterLLMFiles = createFilesSnapshot(
|
|
91
|
-
shareDBDoc.data.files,
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
// Find files that were changed by the AI
|
|
95
|
-
const changedFileIds = Object.keys(afterLLMFiles).filter(
|
|
96
|
-
(fileId) =>
|
|
97
|
-
beforeFiles[fileId]?.text !==
|
|
98
|
-
afterLLMFiles[fileId]?.text,
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
if (changedFileIds.length > 0) {
|
|
102
|
-
// Format the changed files
|
|
103
|
-
const formattedFiles = await formatFiles(
|
|
104
|
-
shareDBDoc.data.files,
|
|
105
|
-
changedFileIds,
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
// Apply formatted versions to shareDBDoc if formatting succeeded
|
|
109
|
-
if (Object.keys(formattedFiles).length > 0) {
|
|
110
|
-
const submitOperation =
|
|
111
|
-
createSubmitOperation(shareDBDoc);
|
|
112
|
-
submitOperation((document: VizContent) => {
|
|
113
|
-
const updatedFiles = { ...document.files };
|
|
114
|
-
|
|
115
|
-
// Apply each formatted file
|
|
116
|
-
Object.entries(formattedFiles).forEach(
|
|
117
|
-
([fileId, formattedText]) => {
|
|
118
|
-
if (updatedFiles[fileId]) {
|
|
119
|
-
updatedFiles[fileId] = {
|
|
120
|
-
...updatedFiles[fileId],
|
|
121
|
-
text: formattedText,
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
return {
|
|
128
|
-
...document,
|
|
129
|
-
files: updatedFiles,
|
|
130
|
-
};
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
86
|
runCode();
|
|
136
87
|
|
|
137
88
|
// 4. Capture the state of files after editing and formatting, then generate diff
|
|
@@ -4,8 +4,10 @@ import {
|
|
|
4
4
|
StreamingMarkdownParser,
|
|
5
5
|
} from 'llm-code-format';
|
|
6
6
|
import { mergeFileChanges } from 'editcodewithai';
|
|
7
|
-
import {
|
|
8
|
-
|
|
7
|
+
import {
|
|
8
|
+
FileCollection,
|
|
9
|
+
VizChatId,
|
|
10
|
+
} from '@vizhub/viz-types';
|
|
9
11
|
import {
|
|
10
12
|
updateFiles,
|
|
11
13
|
updateAIScratchpad,
|
|
@@ -14,11 +16,11 @@ import {
|
|
|
14
16
|
updateStreamingStatus,
|
|
15
17
|
finalizeStreamingMessage,
|
|
16
18
|
} from './chatOperations.js';
|
|
17
|
-
import { diff } from '../../ot.js';
|
|
18
19
|
import {
|
|
19
20
|
ShareDBDoc,
|
|
20
21
|
ExtendedVizContent,
|
|
21
22
|
} from '../../types.js';
|
|
23
|
+
import { formatFiles } from '../prettier.js';
|
|
22
24
|
|
|
23
25
|
const DEBUG = false;
|
|
24
26
|
|
|
@@ -285,51 +287,30 @@ export const createLLMFunction = ({
|
|
|
285
287
|
await completeFileEditing(currentEditingFileName);
|
|
286
288
|
}
|
|
287
289
|
|
|
290
|
+
// // Capture the current state of files before applying changes
|
|
291
|
+
// const beforeFiles = createFilesSnapshot(
|
|
292
|
+
// shareDBDoc.data.files,
|
|
293
|
+
// );
|
|
294
|
+
|
|
295
|
+
// Parse the full content to extract file changes
|
|
296
|
+
// export type FileCollection = Record<string, string>;
|
|
297
|
+
const newFilesUnformatted: FileCollection =
|
|
298
|
+
parseMarkdownFiles(fullContent, 'bold').files;
|
|
299
|
+
|
|
300
|
+
// Run Prettier on `newFiles` before applying them
|
|
301
|
+
const newFilesFormatted = await formatFiles(
|
|
302
|
+
newFilesUnformatted,
|
|
303
|
+
);
|
|
304
|
+
|
|
288
305
|
// Apply all the edits at once
|
|
289
|
-
|
|
290
|
-
shareDBDoc,
|
|
291
|
-
|
|
292
|
-
shareDBDoc.data.files,
|
|
293
|
-
parseMarkdownFiles(fullContent, 'bold').files,
|
|
294
|
-
),
|
|
306
|
+
const mergedChanges = mergeFileChanges(
|
|
307
|
+
shareDBDoc.data.files,
|
|
308
|
+
newFilesFormatted,
|
|
295
309
|
);
|
|
310
|
+
updateFiles(shareDBDoc, mergedChanges);
|
|
296
311
|
|
|
297
312
|
// Finalize streaming message
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
// Generate a new runId to trigger a run when AI finishes editing
|
|
301
|
-
// This will trigger a re-run without hot reloading
|
|
302
|
-
const newRunId = generateRunId();
|
|
303
|
-
const runIdOp = diff(shareDBDoc.data, {
|
|
304
|
-
...shareDBDoc.data,
|
|
305
|
-
runId: newRunId,
|
|
306
|
-
});
|
|
307
|
-
shareDBDoc.submitOp(runIdOp, (error) => {
|
|
308
|
-
if (error) {
|
|
309
|
-
console.warn(
|
|
310
|
-
'Error setting runId after AI editing:',
|
|
311
|
-
error,
|
|
312
|
-
);
|
|
313
|
-
} else {
|
|
314
|
-
DEBUG &&
|
|
315
|
-
console.log(
|
|
316
|
-
'Set new runId after AI editing:',
|
|
317
|
-
newRunId,
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
// Write chunks file for debugging
|
|
323
|
-
// if (DEBUG) {
|
|
324
|
-
// const chunksFileJSONpath = `./ai-chunks-${chatId}.json`;
|
|
325
|
-
// fs.writeFileSync(
|
|
326
|
-
// chunksFileJSONpath,
|
|
327
|
-
// JSON.stringify(chunks, null, 2),
|
|
328
|
-
// );
|
|
329
|
-
// console.log(
|
|
330
|
-
// `AI chunks written to ${chunksFileJSONpath}`,
|
|
331
|
-
// );
|
|
332
|
-
// }
|
|
313
|
+
finalizeStreamingMessage(shareDBDoc, chatId);
|
|
333
314
|
|
|
334
315
|
return {
|
|
335
316
|
content: fullContent,
|
package/src/server/prettier.ts
CHANGED
|
@@ -5,7 +5,10 @@ import * as prettierPluginHtml from 'prettier/plugins/html';
|
|
|
5
5
|
import * as prettierPluginMarkdown from 'prettier/plugins/markdown';
|
|
6
6
|
import * as prettierPluginCSS from 'prettier/plugins/postcss';
|
|
7
7
|
import * as prettierPluginTypescript from 'prettier/plugins/typescript';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
VizFileId,
|
|
10
|
+
FileCollection,
|
|
11
|
+
} from '@vizhub/viz-types';
|
|
9
12
|
|
|
10
13
|
// Parser mappings - matches client-side implementation
|
|
11
14
|
const parsers = {
|
|
@@ -88,23 +91,36 @@ export const formatFile = async (
|
|
|
88
91
|
* Returns a map of fileId -> formatted text for successfully formatted files
|
|
89
92
|
*/
|
|
90
93
|
export const formatFiles = async (
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
fileCollection:
|
|
95
|
+
| FileCollection
|
|
96
|
+
| { [key: string]: { name: string; text: string } },
|
|
93
97
|
): Promise<{ [fileId: VizFileId]: string }> => {
|
|
94
98
|
const results: { [fileId: VizFileId]: string } = {};
|
|
95
|
-
const targetFileIds =
|
|
99
|
+
const targetFileIds = Object.keys(fileCollection);
|
|
96
100
|
|
|
97
101
|
// Process files in parallel for better performance
|
|
98
102
|
const formatPromises = targetFileIds.map(
|
|
99
103
|
async (fileId) => {
|
|
100
|
-
const
|
|
101
|
-
if (!
|
|
104
|
+
const fileData = fileCollection[fileId];
|
|
105
|
+
if (!fileData) return;
|
|
106
|
+
|
|
107
|
+
// Handle both FileCollection format and test format
|
|
108
|
+
const fileName =
|
|
109
|
+
typeof fileData === 'string'
|
|
110
|
+
? fileId
|
|
111
|
+
: fileData.name;
|
|
112
|
+
const fileText =
|
|
113
|
+
typeof fileData === 'string'
|
|
114
|
+
? fileData
|
|
115
|
+
: fileData.text;
|
|
116
|
+
|
|
117
|
+
if (!fileText) return;
|
|
102
118
|
|
|
103
119
|
const formatted = await formatFile(
|
|
104
|
-
|
|
105
|
-
|
|
120
|
+
fileText,
|
|
121
|
+
fileName,
|
|
106
122
|
);
|
|
107
|
-
if (formatted !== null && formatted !==
|
|
123
|
+
if (formatted !== null && formatted !== fileText) {
|
|
108
124
|
results[fileId] = formatted;
|
|
109
125
|
}
|
|
110
126
|
},
|