vzcode 2.0.0 → 2.3.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/{buildWorker-Dsx6rOdK.js → buildWorker-wLkQ0yz1.js} +64 -64
- package/dist/assets/{index-BM8tDh6M.css → index-BoFeK4GL.css} +1 -1
- package/dist/assets/{index-BgqNq-ww.js → index-DuUjtrt6.js} +107 -107
- package/dist/assets/{worker-BeBZGG1n.js → worker-DHxSPM7N.js} +78 -78
- package/dist/cli.js +113 -0
- package/dist/index.html +2 -2
- package/{src/ot.ts → dist/ot.js} +2 -14
- package/{src/randomId.ts → dist/randomId.js} +5 -6
- package/dist/runCode.js +20 -0
- package/dist/server/aiChatHandler/aiEditing.js +89 -0
- package/dist/server/aiChatHandler/chatOperations.js +360 -0
- package/dist/server/aiChatHandler/errorHandling.js +49 -0
- package/dist/server/aiChatHandler/index.js +112 -0
- package/dist/server/aiChatHandler/llmStreaming.js +284 -0
- package/dist/server/aiChatHandler/validation.js +19 -0
- package/dist/server/computeInitialDocument.js +146 -0
- package/{src/server/config.ts → dist/server/config.js} +4 -7
- package/{src/server/featureFlags.ts → dist/server/featureFlags.js} +0 -3
- package/dist/server/generateAIResponse.js +129 -0
- package/dist/server/handleAIAssist.js +39 -0
- package/dist/server/handleAICopilot.js +81 -0
- package/dist/server/index.js +297 -0
- package/dist/server/livekit.js +17 -0
- package/dist/server/prettier.js +90 -0
- package/{src/server/setupEnv.ts → dist/server/setupEnv.js} +1 -2
- package/dist/submitOperation.js +14 -0
- package/dist/types.js +1 -0
- package/dist/utils/fileDiff.js +66 -0
- package/package.json +23 -22
- package/src/client/AIAssist/AIAssistCodeMirrorKeyMap.ts +0 -42
- package/src/client/AIAssist/AIAssistWidget/index.tsx +0 -135
- package/src/client/AIAssist/AIAssistWidget/style.scss +0 -47
- package/src/client/AIAssist/Spinner.jsx +0 -76
- package/src/client/AIAssist/formatFile.ts +0 -27
- package/src/client/AIAssist/generateFilesContext.ts +0 -25
- package/src/client/AIAssist/index.ts +0 -2
- package/src/client/AIAssist/startAIAssist.ts +0 -95
- package/src/client/App/index.tsx +0 -153
- package/src/client/App/style.scss +0 -82
- package/src/client/App/usePending.ts +0 -51
- package/src/client/App/useShareDB.ts +0 -161
- package/src/client/CodeEditor/Copilot/index.ts +0 -74
- package/src/client/CodeEditor/InteractiveWidgets/boolToggler.ts +0 -12
- package/src/client/CodeEditor/InteractiveWidgets/colorPicker.ts +0 -68
- package/src/client/CodeEditor/InteractiveWidgets/colorsInTextPlugin.ts +0 -174
- package/src/client/CodeEditor/InteractiveWidgets/highlightWidgets.ts +0 -79
- package/src/client/CodeEditor/InteractiveWidgets/index.ts +0 -44
- package/src/client/CodeEditor/InteractiveWidgets/markdownCheckboxToggler.ts +0 -12
- package/src/client/CodeEditor/InteractiveWidgets/numberDragger.ts +0 -20
- package/src/client/CodeEditor/InteractiveWidgets/rotateWidget.ts +0 -143
- package/src/client/CodeEditor/InteractiveWidgets/urlClicker.test.ts +0 -48
- package/src/client/CodeEditor/InteractiveWidgets/urlClicker.ts +0 -12
- package/src/client/CodeEditor/InteractiveWidgets/vec2Slider.ts +0 -25
- package/src/client/CodeEditor/basicSetup.ts +0 -73
- package/src/client/CodeEditor/getOrCreateEditor.tsx +0 -615
- package/src/client/CodeEditor/index.tsx +0 -202
- package/src/client/CodeEditor/json1PresenceBroadcast.ts +0 -41
- package/src/client/CodeEditor/json1PresenceDisplay.ts +0 -350
- package/src/client/CodeEditor/rainbowBrackets.ts +0 -122
- package/src/client/CodeEditor/style.scss +0 -156
- package/src/client/CodeEditor/typescriptExtension/worker.ts +0 -32
- package/src/client/CodeErrorOverlay/index.tsx +0 -77
- package/src/client/CodeErrorOverlay/style.scss +0 -33
- package/src/client/Fonts/fonts.ts +0 -8
- package/src/client/Icons/AdjustmentSVG.tsx +0 -19
- package/src/client/Icons/BugSVG.tsx +0 -20
- package/src/client/Icons/CloseSVG.tsx +0 -19
- package/src/client/Icons/CssSVG.tsx +0 -16
- package/src/client/Icons/DirectoryArrowSVG.tsx +0 -19
- package/src/client/Icons/EditSVG.tsx +0 -19
- package/src/client/Icons/FileSVG.tsx +0 -19
- package/src/client/Icons/FolderSVG.tsx +0 -20
- package/src/client/Icons/GearSVG.tsx +0 -16
- package/src/client/Icons/HtmlSVG.tsx +0 -16
- package/src/client/Icons/JavaScriptSVG.tsx +0 -16
- package/src/client/Icons/JsonSVG.tsx +0 -16
- package/src/client/Icons/MarkdownSVG.tsx +0 -16
- package/src/client/Icons/MicSVG.tsx +0 -25
- package/src/client/Icons/NewSVG.tsx +0 -19
- package/src/client/Icons/PinSVG.tsx +0 -14
- package/src/client/Icons/PlaySVG.tsx +0 -16
- package/src/client/Icons/QuestionMarkSVG.tsx +0 -18
- package/src/client/Icons/ReactSVG.tsx +0 -16
- package/src/client/Icons/SearchSVG.tsx +0 -20
- package/src/client/Icons/SparklesSVG.tsx +0 -23
- package/src/client/Icons/SplitEditorSVG.tsx +0 -34
- package/src/client/Icons/StopSVG.tsx +0 -15
- package/src/client/Icons/SvelteSVG.tsx +0 -16
- package/src/client/Icons/TrashSVG.tsx +0 -19
- package/src/client/Icons/TypeScriptSVG.tsx +0 -16
- package/src/client/Icons/index.tsx +0 -24
- package/src/client/ImageViewer/index.tsx +0 -91
- package/src/client/ImageViewer/style.scss +0 -41
- package/src/client/PresenceNotifications/PresenceNotifications.test.ts +0 -134
- package/src/client/PresenceNotifications/index.tsx +0 -158
- package/src/client/PresenceNotifications/style.scss +0 -17
- package/src/client/RunCodeWidget/index.tsx +0 -117
- package/src/client/RunCodeWidget/style.scss +0 -24
- package/src/client/SplitPaneResizeContext.tsx +0 -159
- package/src/client/TabList/Tab.tsx +0 -73
- package/src/client/TabList/index.tsx +0 -35
- package/src/client/TabList/style.scss +0 -51
- package/src/client/VZCodeContext/index.tsx +0 -29
- package/src/client/VZCodeContext/types.ts +0 -249
- package/src/client/VZCodeContext/useVZCodeState.ts +0 -584
- package/src/client/VZKeyboardShortcutsDoc.tsx +0 -148
- package/src/client/VZLeft.tsx +0 -28
- package/src/client/VZMiddle.tsx +0 -172
- package/src/client/VZResizer/index.tsx +0 -128
- package/src/client/VZResizer/styles.scss +0 -33
- package/src/client/VZRight.tsx +0 -113
- package/src/client/VZSettings.tsx +0 -275
- package/src/client/VZSidebar/AIChat/ChatInput.tsx +0 -196
- package/src/client/VZSidebar/AIChat/DiffView.scss +0 -136
- package/src/client/VZSidebar/AIChat/DiffView.tsx +0 -176
- package/src/client/VZSidebar/AIChat/Message.tsx +0 -143
- package/src/client/VZSidebar/AIChat/MessageList.tsx +0 -205
- package/src/client/VZSidebar/AIChat/StreamingMessage.tsx +0 -35
- package/src/client/VZSidebar/AIChat/ThinkingScratchpad.tsx +0 -156
- package/src/client/VZSidebar/AIChat/TypingIndicator.tsx +0 -19
- package/src/client/VZSidebar/AIChat/index.tsx +0 -273
- package/src/client/VZSidebar/AIChat/styles.scss +0 -627
- package/src/client/VZSidebar/CreateDirModal.tsx +0 -111
- package/src/client/VZSidebar/CreateFileModal.tsx +0 -111
- package/src/client/VZSidebar/DeleteConfirmationModal.tsx +0 -76
- package/src/client/VZSidebar/DirectoryListing.tsx +0 -89
- package/src/client/VZSidebar/EmptyState.tsx +0 -11
- package/src/client/VZSidebar/FileListing.tsx +0 -91
- package/src/client/VZSidebar/FileTypeIcon.tsx +0 -49
- package/src/client/VZSidebar/Item.tsx +0 -237
- package/src/client/VZSidebar/Listing.tsx +0 -47
- package/src/client/VZSidebar/Search.tsx +0 -527
- package/src/client/VZSidebar/VisualEditor.tsx +0 -295
- package/src/client/VZSidebar/VoiceChatModal.tsx +0 -121
- package/src/client/VZSidebar/aiCopyPaste.ts +0 -199
- package/src/client/VZSidebar/index.tsx +0 -728
- package/src/client/VZSidebar/styles.scss +0 -612
- package/src/client/VZSidebar/useDragAndDrop.tsx +0 -408
- package/src/client/bootstrap.ts +0 -26
- package/src/client/buildWorker.ts +0 -3
- package/src/client/featureFlags.ts +0 -8
- package/src/client/generateRequestId.ts +0 -6
- package/src/client/getFileTree.ts +0 -53
- package/src/client/index.ts +0 -19
- package/src/client/main.jsx +0 -10
- package/src/client/presenceColor.ts +0 -8
- package/src/client/shouldTriggerRun.ts +0 -31
- package/src/client/sortFileTree.ts +0 -21
- package/src/client/tabsSearchParameters.test.ts +0 -79
- package/src/client/tabsSearchParameters.ts +0 -137
- package/src/client/themes/index.ts +0 -7
- package/src/client/themes/themes.ts +0 -77
- package/src/client/themes/uiwImports.ts +0 -32
- package/src/client/themes/useDynamicTheme.ts +0 -29
- package/src/client/themes/vizhubTheme/colors.ts +0 -80
- package/src/client/themes/vizhubTheme/index.ts +0 -193
- package/src/client/useActions.ts +0 -288
- package/src/client/useESLint/index.ts +0 -72
- package/src/client/useESLint/worker.ts +0 -113
- package/src/client/useEditorCache.ts +0 -35
- package/src/client/useFileCRUD.ts +0 -228
- package/src/client/useKeyboardShortcuts.ts +0 -451
- package/src/client/useOpenDirectories.ts +0 -99
- package/src/client/usePresenceAutoFollow.ts +0 -85
- package/src/client/usePrettier/index.ts +0 -178
- package/src/client/usePrettier/worker.ts +0 -109
- package/src/client/useRunCode.tsx +0 -15
- package/src/client/useRuntimeError.ts +0 -32
- package/src/client/useSubmitOperation.ts +0 -15
- package/src/client/useURLSync.ts +0 -137
- package/src/client/usernameLocalStorage.ts +0 -43
- package/src/client/utils/fileExtension.ts +0 -10
- package/src/client/utils/isImageFile.ts +0 -12
- package/src/client/vzReducer/aiChatReducer.ts +0 -44
- package/src/client/vzReducer/closeTabReducer.test.ts +0 -205
- package/src/client/vzReducer/closeTabsReducer.ts +0 -96
- package/src/client/vzReducer/createInitialState.ts +0 -38
- package/src/client/vzReducer/editorNoLongerWantsFocusReducer.ts +0 -9
- package/src/client/vzReducer/findPane.ts +0 -19
- package/src/client/vzReducer/index.ts +0 -250
- package/src/client/vzReducer/openTabReducer.test.ts +0 -127
- package/src/client/vzReducer/openTabReducer.ts +0 -74
- package/src/client/vzReducer/searchReducer.test.ts +0 -292
- package/src/client/vzReducer/searchReducer.ts +0 -181
- package/src/client/vzReducer/setActiveFileIdReducer.ts +0 -28
- package/src/client/vzReducer/setActiveFileLeftRightReducer.ts +0 -76
- package/src/client/vzReducer/setIsDocOpenReducer.ts +0 -9
- package/src/client/vzReducer/setIsSettingsOpenReducer.ts +0 -9
- package/src/client/vzReducer/setThemeReducer.ts +0 -9
- package/src/client/vzReducer/setUsernameReducer.ts +0 -9
- package/src/client/vzReducer/splitCurrentPaneReducer.ts +0 -66
- package/src/client/vzReducer/toggleAutoFollowReducer.ts +0 -12
- package/src/client/vzReducer/updatePane.ts +0 -40
- package/src/client/vzReducer/updatePresenceIndicatorReducer.ts +0 -30
- package/src/client/vzReducer/visualEditorReducer.ts +0 -9
- package/src/reactRouterExports.ts +0 -15
- package/src/runCode.ts +0 -27
- package/src/server/aiChatHandler/aiEditing.ts +0 -152
- package/src/server/aiChatHandler/chatOperations.ts +0 -510
- package/src/server/aiChatHandler/errorHandling.ts +0 -66
- package/src/server/aiChatHandler/index.ts +0 -200
- package/src/server/aiChatHandler/llmStreaming.ts +0 -419
- package/src/server/aiChatHandler/undoHandler.ts +0 -97
- package/src/server/aiChatHandler/validation.ts +0 -24
- package/src/server/computeInitialDocument.ts +0 -220
- package/src/server/generateAIResponse.ts +0 -188
- package/src/server/handleAIAssist.ts +0 -53
- package/src/server/handleAIChatUndo.ts +0 -2
- package/src/server/handleAICopilot.ts +0 -97
- package/src/server/index.ts +0 -388
- package/src/server/livekit.ts +0 -24
- package/src/server/prettier.ts +0 -115
- package/src/submitOperation.ts +0 -25
- package/src/types.ts +0 -205
- package/src/utils/fileDiff.ts +0 -117
- package/src/vite-env.d.ts +0 -10
- /package/{src/server/handleAIChatMessage.ts → dist/server/handleAIChatMessage.js} +0 -0
- /package/{src/server/isDirectory.ts → dist/server/isDirectory.js} +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { createTwoFilesPatch } from 'diff';
|
|
2
|
+
/**
|
|
3
|
+
* Generate a unified diff for a single file using the diff library
|
|
4
|
+
*/
|
|
5
|
+
export function generateFileUnifiedDiff(fileId, fileName, beforeContent, afterContent) {
|
|
6
|
+
// Only generate diff if there are actual changes
|
|
7
|
+
if (beforeContent === afterContent) {
|
|
8
|
+
return '';
|
|
9
|
+
}
|
|
10
|
+
// Use the diff library's createTwoFilesPatch function to generate unified diff
|
|
11
|
+
const unifiedDiff = createTwoFilesPatch(fileName, fileName, beforeContent, afterContent, '', '', { context: 3 });
|
|
12
|
+
return unifiedDiff;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Generate unified diffs for multiple files
|
|
16
|
+
*/
|
|
17
|
+
export function generateFilesUnifiedDiff(beforeFiles, afterFiles) {
|
|
18
|
+
const result = {};
|
|
19
|
+
const allFileIds = new Set([
|
|
20
|
+
...Object.keys(beforeFiles),
|
|
21
|
+
...Object.keys(afterFiles),
|
|
22
|
+
]);
|
|
23
|
+
for (const fileId of allFileIds) {
|
|
24
|
+
const beforeFile = beforeFiles[fileId];
|
|
25
|
+
const afterFile = afterFiles[fileId];
|
|
26
|
+
const beforeContent = beforeFile?.text || '';
|
|
27
|
+
const afterContent = afterFile?.text || '';
|
|
28
|
+
const fileName = afterFile?.name || beforeFile?.name || fileId;
|
|
29
|
+
const unifiedDiff = generateFileUnifiedDiff(fileId, fileName, beforeContent, afterContent);
|
|
30
|
+
// Only include files that have changes
|
|
31
|
+
if (unifiedDiff) {
|
|
32
|
+
result[fileId] = unifiedDiff;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a snapshot of current files for diff comparison
|
|
39
|
+
*/
|
|
40
|
+
export function createFilesSnapshot(files) {
|
|
41
|
+
return JSON.parse(JSON.stringify(files));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Parse unified diff to extract basic statistics
|
|
45
|
+
*/
|
|
46
|
+
export function parseUnifiedDiffStats(unifiedDiff) {
|
|
47
|
+
const lines = unifiedDiff.split('\n');
|
|
48
|
+
let additions = 0;
|
|
49
|
+
let deletions = 0;
|
|
50
|
+
for (const line of lines) {
|
|
51
|
+
if (line.startsWith('+') && !line.startsWith('+++')) {
|
|
52
|
+
additions++;
|
|
53
|
+
}
|
|
54
|
+
else if (line.startsWith('-') &&
|
|
55
|
+
!line.startsWith('---')) {
|
|
56
|
+
deletions++;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return { additions, deletions };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Combine multiple unified diffs into a single diff string
|
|
63
|
+
*/
|
|
64
|
+
export function combineUnifiedDiffs(unifiedDiffs) {
|
|
65
|
+
return Object.values(unifiedDiffs).join('\n');
|
|
66
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vzcode",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Multiplayer code editor system",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"bin": "
|
|
7
|
+
"bin": "dist/cli.js",
|
|
8
8
|
"files": [
|
|
9
|
-
"dist/**"
|
|
10
|
-
"src/**"
|
|
9
|
+
"dist/**"
|
|
11
10
|
],
|
|
12
11
|
"scripts": {
|
|
13
12
|
"test": "vitest run",
|
|
@@ -15,8 +14,9 @@
|
|
|
15
14
|
"prettier": "prettier {*.*,**/*.*} --write",
|
|
16
15
|
"typecheck": "tsc --noEmit",
|
|
17
16
|
"dev": "cross-env EDITOR_PORT=5173 concurrently \"npm run test-interactive\" \"vite\"",
|
|
18
|
-
"build": "vite build",
|
|
19
|
-
"build
|
|
17
|
+
"build": "vite build && npm run build:server",
|
|
18
|
+
"build:server": "tsc --project tsconfig.server.json",
|
|
19
|
+
"build-release": "vite build --mode release && npm run build:server",
|
|
20
20
|
"preview": "concurrently \"npm run test-interactive\" \"vite preview\"",
|
|
21
21
|
"tauri": "tauri",
|
|
22
22
|
"tauri:dev": "tauri dev",
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
"@codemirror/state": "^6.5.2",
|
|
118
118
|
"@codemirror/theme-one-dark": "^6.1.3",
|
|
119
119
|
"@codemirror/view": "^6.38.1",
|
|
120
|
-
"@langchain/core": "^0.3.
|
|
120
|
+
"@langchain/core": "^0.3.70",
|
|
121
121
|
"@langchain/openai": "^0.6.7",
|
|
122
122
|
"@lezer/highlight": "^1.2.1",
|
|
123
123
|
"@livekit/components-react": "^2.9.14",
|
|
@@ -127,17 +127,17 @@
|
|
|
127
127
|
"@replit/codemirror-vscode-keymap": "^6.0.2",
|
|
128
128
|
"@teamwork/websocket-json-stream": "^2.0.0",
|
|
129
129
|
"@typescript/vfs": "^1.6.1",
|
|
130
|
-
"@uiw/codemirror-theme-abcdef": "^4.
|
|
131
|
-
"@uiw/codemirror-theme-dracula": "^4.
|
|
132
|
-
"@uiw/codemirror-theme-eclipse": "^4.
|
|
133
|
-
"@uiw/codemirror-theme-github": "^4.
|
|
134
|
-
"@uiw/codemirror-theme-material": "^4.
|
|
135
|
-
"@uiw/codemirror-theme-nord": "^4.
|
|
136
|
-
"@uiw/codemirror-theme-okaidia": "^4.
|
|
137
|
-
"@uiw/codemirror-theme-xcode": "^4.
|
|
138
|
-
"@uiw/codemirror-themes": "^4.
|
|
130
|
+
"@uiw/codemirror-theme-abcdef": "^4.25.1",
|
|
131
|
+
"@uiw/codemirror-theme-dracula": "^4.25.1",
|
|
132
|
+
"@uiw/codemirror-theme-eclipse": "^4.25.1",
|
|
133
|
+
"@uiw/codemirror-theme-github": "^4.25.1",
|
|
134
|
+
"@uiw/codemirror-theme-material": "^4.25.1",
|
|
135
|
+
"@uiw/codemirror-theme-nord": "^4.25.1",
|
|
136
|
+
"@uiw/codemirror-theme-okaidia": "^4.25.1",
|
|
137
|
+
"@uiw/codemirror-theme-xcode": "^4.25.1",
|
|
138
|
+
"@uiw/codemirror-themes": "^4.25.1",
|
|
139
139
|
"@valtown/codemirror-ts": "^2.3.1",
|
|
140
|
-
"@vizhub/runtime": "^4.
|
|
140
|
+
"@vizhub/runtime": "^4.4.0",
|
|
141
141
|
"@vizhub/viz-types": "^0.4.0",
|
|
142
142
|
"@vizhub/viz-utils": "^1.4.0",
|
|
143
143
|
"body-parser": "^2.2.0",
|
|
@@ -153,13 +153,14 @@
|
|
|
153
153
|
"diff2html": "^3.4.52",
|
|
154
154
|
"dotenv": "^17.2.1",
|
|
155
155
|
"editcodewithai": "^2.3.0",
|
|
156
|
-
"eslint-linter-browserify": "^9.
|
|
156
|
+
"eslint-linter-browserify": "^9.33.0",
|
|
157
157
|
"express": "^5.1.0",
|
|
158
158
|
"ignore": "^7.0.5",
|
|
159
159
|
"json0-ot-diff": "^1.1.2",
|
|
160
160
|
"jszip": "^3.10.1",
|
|
161
|
-
"livekit-server-sdk": "^2.13.
|
|
161
|
+
"livekit-server-sdk": "^2.13.2",
|
|
162
162
|
"llm-code-format": "^3.0.0",
|
|
163
|
+
"lucide-react": "^0.539.0",
|
|
163
164
|
"npm": "^11.5.2",
|
|
164
165
|
"open": "^10.2.0",
|
|
165
166
|
"prettier-plugin-svelte": "^3.4.0",
|
|
@@ -176,21 +177,21 @@
|
|
|
176
177
|
"ws": "^8.18.3"
|
|
177
178
|
},
|
|
178
179
|
"devDependencies": {
|
|
179
|
-
"@eslint/js": "^9.
|
|
180
|
+
"@eslint/js": "^9.33.0",
|
|
180
181
|
"@tauri-apps/cli": "^2.7.1",
|
|
181
182
|
"@types/react": "^18",
|
|
182
183
|
"@types/react-dom": "^18",
|
|
183
184
|
"@vitejs/plugin-react": "^5.0.0",
|
|
184
185
|
"concurrently": "^9.2.0",
|
|
185
186
|
"cross-env": "^10.0.0",
|
|
186
|
-
"eslint": "^9.
|
|
187
|
+
"eslint": "^9.33.0",
|
|
187
188
|
"globals": "^16.3.0",
|
|
188
189
|
"npm-check-updates": "^18.0.2",
|
|
189
190
|
"prettier": "^3.6.2",
|
|
190
191
|
"sass": "^1.90.0",
|
|
191
192
|
"ts-node": "^10.9.2",
|
|
192
193
|
"typescript": "^5.9.2",
|
|
193
|
-
"vite": "^7.1.
|
|
194
|
+
"vite": "^7.1.2",
|
|
194
195
|
"vitest": "^3.2.4"
|
|
195
196
|
},
|
|
196
197
|
"optionalDependencies": {
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { EditorView, keymap } from '@codemirror/view';
|
|
2
|
-
import { ShareDBDoc, TabState } from '../../types';
|
|
3
|
-
import { VizContent } from '@vizhub/viz-types';
|
|
4
|
-
|
|
5
|
-
export const AIAssistCodeMirrorKeyMap = ({
|
|
6
|
-
shareDBDoc,
|
|
7
|
-
fileId,
|
|
8
|
-
tabList,
|
|
9
|
-
}: {
|
|
10
|
-
shareDBDoc: ShareDBDoc<VizContent>;
|
|
11
|
-
fileId: string;
|
|
12
|
-
tabList: Array<TabState>;
|
|
13
|
-
}) =>
|
|
14
|
-
keymap.of([
|
|
15
|
-
{
|
|
16
|
-
key: 'control-m',
|
|
17
|
-
run: (view: EditorView) => {
|
|
18
|
-
// if (
|
|
19
|
-
// shareDBDoc.data.aiStreams === undefined ||
|
|
20
|
-
// shareDBDoc.data.aiStreams[mostRecentStreamId] ===
|
|
21
|
-
// null ||
|
|
22
|
-
// shareDBDoc.data.aiStreams[mostRecentStreamId]
|
|
23
|
-
// ?.AIStreamStatus.serverIsRunning !== true
|
|
24
|
-
// ) {
|
|
25
|
-
|
|
26
|
-
// TODO handle starting it
|
|
27
|
-
// startAIAssist({
|
|
28
|
-
// view,
|
|
29
|
-
// shareDBDoc,
|
|
30
|
-
// fileId,
|
|
31
|
-
// tabList,
|
|
32
|
-
// });
|
|
33
|
-
|
|
34
|
-
// TODO handle stopping it
|
|
35
|
-
// } else {
|
|
36
|
-
// haltAIAssist(shareDBDoc);
|
|
37
|
-
// }
|
|
38
|
-
|
|
39
|
-
return true;
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
]);
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { useCallback, useContext, useState } from 'react';
|
|
2
|
-
import { OverlayTrigger, Tooltip } from '../../bootstrap';
|
|
3
|
-
import { PaneId, TabState } from '../../../types';
|
|
4
|
-
import { VizFileId } from '@vizhub/viz-types';
|
|
5
|
-
import { VZCodeContext } from '../../VZCodeContext';
|
|
6
|
-
import {
|
|
7
|
-
RequestId,
|
|
8
|
-
generateRequestId,
|
|
9
|
-
} from '../../generateRequestId';
|
|
10
|
-
import { SparklesSVG } from '../../Icons';
|
|
11
|
-
import { startAIAssist } from '../startAIAssist';
|
|
12
|
-
import { editorCacheKey } from '../../useEditorCache';
|
|
13
|
-
import { Spinner } from '../Spinner';
|
|
14
|
-
import './style.scss';
|
|
15
|
-
|
|
16
|
-
const enableStopGeneration = false;
|
|
17
|
-
|
|
18
|
-
export const AIAssistWidget = ({
|
|
19
|
-
aiAssistEndpoint,
|
|
20
|
-
aiAssistOptions,
|
|
21
|
-
aiAssistTooltipText = 'Start AI Assist',
|
|
22
|
-
aiAssistClickOverride,
|
|
23
|
-
activeFileId,
|
|
24
|
-
tabList,
|
|
25
|
-
paneId,
|
|
26
|
-
}: {
|
|
27
|
-
aiAssistEndpoint: string;
|
|
28
|
-
aiAssistOptions: { [key: string]: string };
|
|
29
|
-
aiAssistTooltipText?: string;
|
|
30
|
-
aiAssistClickOverride?: () => void;
|
|
31
|
-
activeFileId: VizFileId;
|
|
32
|
-
tabList: Array<TabState>;
|
|
33
|
-
paneId: PaneId;
|
|
34
|
-
}) => {
|
|
35
|
-
const {
|
|
36
|
-
shareDBDoc,
|
|
37
|
-
editorCache,
|
|
38
|
-
runPrettierRef,
|
|
39
|
-
runCodeRef,
|
|
40
|
-
} = useContext(VZCodeContext);
|
|
41
|
-
|
|
42
|
-
// The stream ID of the most recent request.
|
|
43
|
-
// * If `null`, no request has been made yet.
|
|
44
|
-
// * If non-null, a request has been made, and the
|
|
45
|
-
// server is processing it.
|
|
46
|
-
const [aiStreamId, setAiStreamId] =
|
|
47
|
-
useState<RequestId | null>(null);
|
|
48
|
-
|
|
49
|
-
const handleClick = useCallback(async () => {
|
|
50
|
-
const isCurrentlyGenerationg = aiStreamId !== null;
|
|
51
|
-
if (isCurrentlyGenerationg) {
|
|
52
|
-
// TODO stop generation
|
|
53
|
-
} else {
|
|
54
|
-
const newAiStreamId = generateRequestId();
|
|
55
|
-
setAiStreamId(newAiStreamId);
|
|
56
|
-
|
|
57
|
-
// Wait for generation to finish.
|
|
58
|
-
await startAIAssist({
|
|
59
|
-
view: editorCache.get(
|
|
60
|
-
editorCacheKey(activeFileId, paneId),
|
|
61
|
-
).editor,
|
|
62
|
-
shareDBDoc,
|
|
63
|
-
fileId: activeFileId,
|
|
64
|
-
tabList,
|
|
65
|
-
aiStreamId: newAiStreamId,
|
|
66
|
-
aiAssistEndpoint,
|
|
67
|
-
aiAssistOptions,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// Introduce a delay before running Prettier
|
|
71
|
-
// and the code, to give the ShareDB ops a chance
|
|
72
|
-
// to be applied and to propagate via WebSockets
|
|
73
|
-
// to the client. This is necessary because sometimes
|
|
74
|
-
// the ShareDB ops from the AI assist actually don't
|
|
75
|
-
// reach the client until AFTER the response comes back
|
|
76
|
-
// from `await startAIAssist`.
|
|
77
|
-
await new Promise((resolve) =>
|
|
78
|
-
setTimeout(resolve, 1000),
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
// Trigger a Prettier run after the AI Assist.
|
|
82
|
-
const runPrettier = runPrettierRef.current;
|
|
83
|
-
if (runPrettier !== null) {
|
|
84
|
-
runPrettier();
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Run the code after the AI Assist.
|
|
88
|
-
const runCode = runCodeRef.current;
|
|
89
|
-
if (runCode !== null) {
|
|
90
|
-
runCode();
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Handles the case that the user has started,
|
|
94
|
-
// stopped, and started again before the first request
|
|
95
|
-
// has finished, by comparing the current stream ID
|
|
96
|
-
// with the stream ID that was active when the request
|
|
97
|
-
// was started.
|
|
98
|
-
setAiStreamId((currentAIStreamId) =>
|
|
99
|
-
currentAIStreamId === newAiStreamId
|
|
100
|
-
? null
|
|
101
|
-
: currentAIStreamId,
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
}, [activeFileId, paneId, aiStreamId]);
|
|
105
|
-
|
|
106
|
-
const showWidget = enableStopGeneration
|
|
107
|
-
? true
|
|
108
|
-
: aiStreamId === null;
|
|
109
|
-
|
|
110
|
-
return (
|
|
111
|
-
<div className="vz-code-ai-assist-widget">
|
|
112
|
-
{aiStreamId ? (
|
|
113
|
-
<Spinner /> // Show spinner when aiStreamId is not null
|
|
114
|
-
) : (
|
|
115
|
-
showWidget && (
|
|
116
|
-
<OverlayTrigger
|
|
117
|
-
placement="left"
|
|
118
|
-
overlay={
|
|
119
|
-
<Tooltip id="ai-assist-widget-tooltip">
|
|
120
|
-
{aiAssistTooltipText}
|
|
121
|
-
</Tooltip>
|
|
122
|
-
}
|
|
123
|
-
>
|
|
124
|
-
<i
|
|
125
|
-
className="icon-button icon-button-dark"
|
|
126
|
-
onClick={aiAssistClickOverride || handleClick}
|
|
127
|
-
>
|
|
128
|
-
<SparklesSVG />
|
|
129
|
-
</i>
|
|
130
|
-
</OverlayTrigger>
|
|
131
|
-
)
|
|
132
|
-
)}
|
|
133
|
-
</div>
|
|
134
|
-
);
|
|
135
|
-
};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
.vz-code-ai-assist-widget {
|
|
2
|
-
position: absolute;
|
|
3
|
-
// bottom: 32px;
|
|
4
|
-
// right: 32px;
|
|
5
|
-
bottom: 16px;
|
|
6
|
-
right: 16px;
|
|
7
|
-
color: var(--vh-color-caution-01);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.vh-spinner {
|
|
11
|
-
display: flex;
|
|
12
|
-
height: 100%;
|
|
13
|
-
flex-direction: column;
|
|
14
|
-
align-items: center;
|
|
15
|
-
justify-content: center;
|
|
16
|
-
overflow: hidden;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/* Fade in after a delay */
|
|
20
|
-
/* https://stackoverflow.com/questions/29846224/css-animation-with-delay-and-opacity */
|
|
21
|
-
.vh-spinner.fade-in svg {
|
|
22
|
-
animation: 1s linear 0s normal forwards 1 fadein;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
@keyframes fadein {
|
|
26
|
-
0% {
|
|
27
|
-
opacity: 0;
|
|
28
|
-
}
|
|
29
|
-
50% {
|
|
30
|
-
opacity: 0;
|
|
31
|
-
}
|
|
32
|
-
100% {
|
|
33
|
-
opacity: 1;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/* Infinite rotation */
|
|
38
|
-
/* https://stackoverflow.com/questions/6410730/css-endless-rotation-animation */
|
|
39
|
-
.vh-spinner-dots {
|
|
40
|
-
animation: rotate 3s linear infinite;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
@keyframes rotate {
|
|
44
|
-
to {
|
|
45
|
-
transform: rotate(360deg);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
// From https://github.com/vizhub-core/vizhub/commit/6ca078935b9771dc6e05a6065bcfd522a4724dcf
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
3
|
-
import './AIAssistWidget/style.scss';
|
|
4
|
-
|
|
5
|
-
// const minRadius = 4;
|
|
6
|
-
// const maxRadius = 10;
|
|
7
|
-
// const numDots = 8;
|
|
8
|
-
// const wheelRadius = 40;
|
|
9
|
-
// const round = (number) => Math.floor(number * 100) / 100;
|
|
10
|
-
// const dots = [];
|
|
11
|
-
// for (let i = 0; i < numDots; i++) {
|
|
12
|
-
// const angle = (i / numDots) * Math.PI * 2;
|
|
13
|
-
// dots.push({
|
|
14
|
-
// x: round(Math.cos(angle) * wheelRadius),
|
|
15
|
-
// y: round(Math.sin(angle) * wheelRadius),
|
|
16
|
-
// r: round(
|
|
17
|
-
// minRadius +
|
|
18
|
-
// (i / (numDots - 1)) * (maxRadius - minRadius),
|
|
19
|
-
// ),
|
|
20
|
-
// });
|
|
21
|
-
// }
|
|
22
|
-
// console.log(JSON.stringify(dots));
|
|
23
|
-
|
|
24
|
-
// Hardcoded to avoid the computation.
|
|
25
|
-
const dots = [
|
|
26
|
-
{ x: 40, y: 0, r: 4 },
|
|
27
|
-
{ x: 28.28, y: 28.28, r: 4.85 },
|
|
28
|
-
{ x: 0, y: 40, r: 5.71 },
|
|
29
|
-
{ x: -28.29, y: 28.28, r: 6.57 },
|
|
30
|
-
{ x: -40, y: 0, r: 7.42 },
|
|
31
|
-
{ x: -28.29, y: -28.29, r: 8.28 },
|
|
32
|
-
{ x: -0.01, y: -40, r: 9.14 },
|
|
33
|
-
{ x: 28.28, y: -28.29, r: 10 },
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
// From https://bl.ocks.org/curran/685fa8300650c4324d571c6b0ecc55de
|
|
37
|
-
// And vizhub-v2/packages/neoFrontend/src/LoadingScreen/index.js
|
|
38
|
-
export const Spinner = ({
|
|
39
|
-
height = 40,
|
|
40
|
-
fill = 'currentcolor',
|
|
41
|
-
fadeIn = true,
|
|
42
|
-
}) => {
|
|
43
|
-
const [show, setShow] = useState(false);
|
|
44
|
-
|
|
45
|
-
// Avoid SSR of all the SVG elements.
|
|
46
|
-
useEffect(() => {
|
|
47
|
-
setShow(true);
|
|
48
|
-
}, []);
|
|
49
|
-
|
|
50
|
-
return (
|
|
51
|
-
show && (
|
|
52
|
-
<div
|
|
53
|
-
className={`vh-spinner${fadeIn ? ' fade-in' : ''}`}
|
|
54
|
-
>
|
|
55
|
-
<svg
|
|
56
|
-
height={height}
|
|
57
|
-
viewBox="0 0 100 100"
|
|
58
|
-
style={{ opacity: 1 }}
|
|
59
|
-
>
|
|
60
|
-
<g transform="translate(50, 50)" fill={fill}>
|
|
61
|
-
<g className="vh-spinner-dots">
|
|
62
|
-
{dots.map(({ x, y, r }, i) => (
|
|
63
|
-
<circle
|
|
64
|
-
key={i}
|
|
65
|
-
cx={x}
|
|
66
|
-
cy={y}
|
|
67
|
-
r={r}
|
|
68
|
-
></circle>
|
|
69
|
-
))}
|
|
70
|
-
</g>
|
|
71
|
-
</g>
|
|
72
|
-
</svg>
|
|
73
|
-
</div>
|
|
74
|
-
)
|
|
75
|
-
);
|
|
76
|
-
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { VizFile } from '@vizhub/viz-types';
|
|
2
|
-
|
|
3
|
-
const maxFileNameLength = 100;
|
|
4
|
-
const maxFileTextLength = 2000;
|
|
5
|
-
|
|
6
|
-
// Formats a file for the prompt.
|
|
7
|
-
export const formatFile = (
|
|
8
|
-
file: VizFile,
|
|
9
|
-
truncateText = true,
|
|
10
|
-
) => {
|
|
11
|
-
const nameTruncated = file.name
|
|
12
|
-
?.substring(0, maxFileNameLength)
|
|
13
|
-
.trim();
|
|
14
|
-
|
|
15
|
-
const textTruncated = (
|
|
16
|
-
truncateText
|
|
17
|
-
? file.text?.substring(0, maxFileTextLength)
|
|
18
|
-
: file.text
|
|
19
|
-
).trim();
|
|
20
|
-
|
|
21
|
-
return [
|
|
22
|
-
'`' + nameTruncated + '`:',
|
|
23
|
-
'```',
|
|
24
|
-
textTruncated,
|
|
25
|
-
'```',
|
|
26
|
-
].join('\n');
|
|
27
|
-
};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// import { File } from '../../types';
|
|
2
|
-
|
|
3
|
-
// const maxFileNameLength = 100;
|
|
4
|
-
// const maxFileTextLength = 2000;
|
|
5
|
-
|
|
6
|
-
// export const generateFilesContext = (
|
|
7
|
-
// goodFiles: Array<File>,
|
|
8
|
-
// ): string => {
|
|
9
|
-
// const input = goodFiles
|
|
10
|
-
// .map((file) => {
|
|
11
|
-
// const nameSubstring = file.name
|
|
12
|
-
// ?.substring(0, maxFileNameLength)
|
|
13
|
-
// .trim();
|
|
14
|
-
|
|
15
|
-
// const textSubstring = file.text
|
|
16
|
-
// ?.substring(0, maxFileTextLength)
|
|
17
|
-
// .trim();
|
|
18
|
-
|
|
19
|
-
// // Generate Markdown that AI will understand.
|
|
20
|
-
// return `File \`${nameSubstring}\`:\n\`\`\`${textSubstring}\`\`\``;
|
|
21
|
-
// })
|
|
22
|
-
// .join('\n\n');
|
|
23
|
-
|
|
24
|
-
// return input;
|
|
25
|
-
// };
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { EditorView } from 'codemirror';
|
|
2
|
-
import { ShareDBDoc, TabState } from '../../types';
|
|
3
|
-
import {
|
|
4
|
-
VizFile,
|
|
5
|
-
VizFileId,
|
|
6
|
-
VizContent,
|
|
7
|
-
} from '@vizhub/viz-types';
|
|
8
|
-
import { RequestId } from '../generateRequestId';
|
|
9
|
-
import { formatFile } from './formatFile';
|
|
10
|
-
|
|
11
|
-
const debug = false;
|
|
12
|
-
|
|
13
|
-
// Enables inclusion of code from open tabs as context.
|
|
14
|
-
const enableTabContext = false;
|
|
15
|
-
|
|
16
|
-
const defaultAIAssistEndpoint = '/ai-assist';
|
|
17
|
-
|
|
18
|
-
export const startAIAssist = async ({
|
|
19
|
-
view,
|
|
20
|
-
shareDBDoc,
|
|
21
|
-
fileId,
|
|
22
|
-
tabList,
|
|
23
|
-
aiAssistEndpoint = defaultAIAssistEndpoint,
|
|
24
|
-
aiAssistOptions = {},
|
|
25
|
-
aiStreamId,
|
|
26
|
-
}: {
|
|
27
|
-
view: EditorView;
|
|
28
|
-
shareDBDoc: ShareDBDoc<VizContent>;
|
|
29
|
-
fileId: VizFileId;
|
|
30
|
-
tabList: Array<TabState>;
|
|
31
|
-
aiAssistEndpoint?: string;
|
|
32
|
-
aiAssistOptions?: {
|
|
33
|
-
[key: string]: any;
|
|
34
|
-
};
|
|
35
|
-
aiStreamId: RequestId;
|
|
36
|
-
}) => {
|
|
37
|
-
const currentFileName =
|
|
38
|
-
shareDBDoc.data.files[fileId].name;
|
|
39
|
-
|
|
40
|
-
// Generate a version of the current file with a
|
|
41
|
-
// <FILL_ME> in the middle.
|
|
42
|
-
const prefix = view.state.sliceDoc(
|
|
43
|
-
0,
|
|
44
|
-
view.state.selection.main.from,
|
|
45
|
-
);
|
|
46
|
-
const suffix = view.state.sliceDoc(
|
|
47
|
-
view.state.selection.main.to,
|
|
48
|
-
);
|
|
49
|
-
const combinedText = prefix + '<FILL_ME>' + suffix;
|
|
50
|
-
const currentFile = {
|
|
51
|
-
name: currentFileName,
|
|
52
|
-
text: combinedText,
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const insertionCursor = view.state.selection.main.to;
|
|
56
|
-
|
|
57
|
-
// The main prompt is the current file, plus the context files.
|
|
58
|
-
let inputText = formatFile(currentFile, false);
|
|
59
|
-
|
|
60
|
-
if (enableTabContext) {
|
|
61
|
-
inputText +=
|
|
62
|
-
'\n\n' +
|
|
63
|
-
tabList
|
|
64
|
-
.filter((tabState) => tabState.fileId !== fileId)
|
|
65
|
-
.map((tabState) =>
|
|
66
|
-
formatFile(
|
|
67
|
-
shareDBDoc.data.files[tabState.fileId],
|
|
68
|
-
),
|
|
69
|
-
)
|
|
70
|
-
.join('\n\n');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const response = await fetch(aiAssistEndpoint, {
|
|
74
|
-
method: 'POST',
|
|
75
|
-
headers: {
|
|
76
|
-
'Content-Type': 'application/json',
|
|
77
|
-
},
|
|
78
|
-
body: JSON.stringify({
|
|
79
|
-
...aiAssistOptions,
|
|
80
|
-
inputText,
|
|
81
|
-
fileId,
|
|
82
|
-
insertionCursor,
|
|
83
|
-
aiStreamId,
|
|
84
|
-
}),
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
const responseJson = await response.json();
|
|
88
|
-
|
|
89
|
-
if (responseJson.error) {
|
|
90
|
-
console.error(
|
|
91
|
-
'[startAIAssist] error from server:',
|
|
92
|
-
responseJson.error,
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
};
|