@myrialabs/clopen 0.0.1
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/.env.example +6 -0
- package/.github/workflows/release.yml +60 -0
- package/.github/workflows/test.yml +40 -0
- package/CONTRIBUTING.md +499 -0
- package/LICENSE +21 -0
- package/README.md +209 -0
- package/backend/index.ts +156 -0
- package/backend/lib/chat/helpers.ts +42 -0
- package/backend/lib/chat/index.ts +2 -0
- package/backend/lib/chat/stream-manager.ts +1126 -0
- package/backend/lib/database/README.md +77 -0
- package/backend/lib/database/index.ts +119 -0
- package/backend/lib/database/migrations/001_create_projects_table.ts +31 -0
- package/backend/lib/database/migrations/002_create_chat_sessions_table.ts +33 -0
- package/backend/lib/database/migrations/003_create_messages_table.ts +32 -0
- package/backend/lib/database/migrations/004_create_prompt_templates_table.ts +34 -0
- package/backend/lib/database/migrations/005_create_settings_table.ts +24 -0
- package/backend/lib/database/migrations/006_add_user_to_messages.ts +58 -0
- package/backend/lib/database/migrations/007_create_stream_states_table.ts +41 -0
- package/backend/lib/database/migrations/008_create_message_snapshots_table.ts +62 -0
- package/backend/lib/database/migrations/009_add_delta_snapshot_fields.ts +41 -0
- package/backend/lib/database/migrations/010_add_soft_delete_and_branch_support.ts +70 -0
- package/backend/lib/database/migrations/011_git_like_commit_graph.ts +156 -0
- package/backend/lib/database/migrations/012_add_file_change_statistics.ts +41 -0
- package/backend/lib/database/migrations/013_checkpoint_tree_state.ts +118 -0
- package/backend/lib/database/migrations/014_add_engine_to_sessions.ts +18 -0
- package/backend/lib/database/migrations/015_add_model_to_sessions.ts +18 -0
- package/backend/lib/database/migrations/016_create_user_projects_table.ts +34 -0
- package/backend/lib/database/migrations/017_add_current_session_to_user_projects.ts +32 -0
- package/backend/lib/database/migrations/018_create_claude_accounts_table.ts +24 -0
- package/backend/lib/database/migrations/019_add_claude_account_to_sessions.ts +18 -0
- package/backend/lib/database/migrations/020_add_snapshot_tree_hash.ts +32 -0
- package/backend/lib/database/migrations/021_drop_prompt_templates_table.ts +33 -0
- package/backend/lib/database/migrations/index.ts +154 -0
- package/backend/lib/database/queries/checkpoint-queries.ts +87 -0
- package/backend/lib/database/queries/engine-queries.ts +75 -0
- package/backend/lib/database/queries/index.ts +9 -0
- package/backend/lib/database/queries/message-queries.ts +472 -0
- package/backend/lib/database/queries/project-queries.ts +117 -0
- package/backend/lib/database/queries/session-queries.ts +271 -0
- package/backend/lib/database/queries/settings-queries.ts +34 -0
- package/backend/lib/database/queries/snapshot-queries.ts +326 -0
- package/backend/lib/database/queries/utils-queries.ts +59 -0
- package/backend/lib/database/seeders/index.ts +13 -0
- package/backend/lib/database/seeders/settings_seeder.ts +84 -0
- package/backend/lib/database/utils/connection.ts +174 -0
- package/backend/lib/database/utils/index.ts +4 -0
- package/backend/lib/database/utils/migration-runner.ts +118 -0
- package/backend/lib/database/utils/seeder-runner.ts +121 -0
- package/backend/lib/engine/adapters/claude/environment.ts +164 -0
- package/backend/lib/engine/adapters/claude/error-handler.ts +60 -0
- package/backend/lib/engine/adapters/claude/index.ts +1 -0
- package/backend/lib/engine/adapters/claude/path-utils.ts +38 -0
- package/backend/lib/engine/adapters/claude/stream.ts +177 -0
- package/backend/lib/engine/adapters/opencode/index.ts +2 -0
- package/backend/lib/engine/adapters/opencode/message-converter.ts +862 -0
- package/backend/lib/engine/adapters/opencode/server.ts +104 -0
- package/backend/lib/engine/adapters/opencode/stream.ts +755 -0
- package/backend/lib/engine/index.ts +196 -0
- package/backend/lib/engine/types.ts +58 -0
- package/backend/lib/files/file-operations.ts +478 -0
- package/backend/lib/files/file-reading.ts +308 -0
- package/backend/lib/files/file-watcher.ts +383 -0
- package/backend/lib/files/path-browsing.ts +382 -0
- package/backend/lib/git/git-executor.ts +88 -0
- package/backend/lib/git/git-parser.ts +411 -0
- package/backend/lib/git/git-service.ts +505 -0
- package/backend/lib/mcp/README.md +1144 -0
- package/backend/lib/mcp/config.ts +316 -0
- package/backend/lib/mcp/index.ts +35 -0
- package/backend/lib/mcp/project-context.ts +236 -0
- package/backend/lib/mcp/servers/browser-automation/actions.ts +156 -0
- package/backend/lib/mcp/servers/browser-automation/browser.ts +419 -0
- package/backend/lib/mcp/servers/browser-automation/index.ts +791 -0
- package/backend/lib/mcp/servers/browser-automation/inspection.ts +501 -0
- package/backend/lib/mcp/servers/helper.ts +143 -0
- package/backend/lib/mcp/servers/index.ts +45 -0
- package/backend/lib/mcp/servers/weather/get-temperature.ts +56 -0
- package/backend/lib/mcp/servers/weather/index.ts +31 -0
- package/backend/lib/mcp/stdio-server.ts +103 -0
- package/backend/lib/mcp/types.ts +65 -0
- package/backend/lib/preview/browser/browser-audio-capture.ts +86 -0
- package/backend/lib/preview/browser/browser-console-manager.ts +263 -0
- package/backend/lib/preview/browser/browser-dialog-handler.ts +222 -0
- package/backend/lib/preview/browser/browser-interaction-handler.ts +421 -0
- package/backend/lib/preview/browser/browser-mcp-control.ts +415 -0
- package/backend/lib/preview/browser/browser-native-ui-handler.ts +512 -0
- package/backend/lib/preview/browser/browser-navigation-tracker.ts +104 -0
- package/backend/lib/preview/browser/browser-pool.ts +357 -0
- package/backend/lib/preview/browser/browser-preview-service.ts +882 -0
- package/backend/lib/preview/browser/browser-tab-manager.ts +935 -0
- package/backend/lib/preview/browser/browser-video-capture.ts +695 -0
- package/backend/lib/preview/browser/scripts/audio-stream.ts +292 -0
- package/backend/lib/preview/browser/scripts/cursor-tracking.ts +85 -0
- package/backend/lib/preview/browser/scripts/video-stream.ts +438 -0
- package/backend/lib/preview/browser/types.ts +359 -0
- package/backend/lib/preview/index.ts +24 -0
- package/backend/lib/project/index.ts +2 -0
- package/backend/lib/project/status-manager.ts +182 -0
- package/backend/lib/shared/index.ts +2 -0
- package/backend/lib/shared/port-utils.ts +25 -0
- package/backend/lib/shared/process-manager.ts +281 -0
- package/backend/lib/snapshot/blob-store.ts +227 -0
- package/backend/lib/snapshot/gitignore.ts +307 -0
- package/backend/lib/snapshot/helpers.ts +397 -0
- package/backend/lib/snapshot/snapshot-service.ts +483 -0
- package/backend/lib/terminal/helpers.ts +14 -0
- package/backend/lib/terminal/index.ts +8 -0
- package/backend/lib/terminal/pty-manager.ts +4 -0
- package/backend/lib/terminal/pty-session-manager.ts +387 -0
- package/backend/lib/terminal/shell-utils.ts +313 -0
- package/backend/lib/terminal/stream-manager.ts +293 -0
- package/backend/lib/tunnel/global-tunnel-manager.ts +243 -0
- package/backend/lib/tunnel/project-tunnel-manager.ts +311 -0
- package/backend/lib/user/helpers.ts +87 -0
- package/backend/lib/utils/ws.ts +944 -0
- package/backend/lib/vite-dev.ts +353 -0
- package/backend/middleware/cors.ts +15 -0
- package/backend/middleware/error-handler.ts +49 -0
- package/backend/middleware/logger.ts +9 -0
- package/backend/types/api.ts +24 -0
- package/backend/ws/README.md +1505 -0
- package/backend/ws/chat/background.ts +198 -0
- package/backend/ws/chat/index.ts +21 -0
- package/backend/ws/chat/stream.ts +707 -0
- package/backend/ws/engine/claude/accounts.ts +401 -0
- package/backend/ws/engine/claude/index.ts +13 -0
- package/backend/ws/engine/claude/status.ts +43 -0
- package/backend/ws/engine/index.ts +14 -0
- package/backend/ws/engine/opencode/index.ts +11 -0
- package/backend/ws/engine/opencode/status.ts +30 -0
- package/backend/ws/engine/utils.ts +36 -0
- package/backend/ws/files/index.ts +30 -0
- package/backend/ws/files/read.ts +189 -0
- package/backend/ws/files/search.ts +453 -0
- package/backend/ws/files/watch.ts +124 -0
- package/backend/ws/files/write.ts +143 -0
- package/backend/ws/git/branch.ts +106 -0
- package/backend/ws/git/commit.ts +39 -0
- package/backend/ws/git/conflict.ts +68 -0
- package/backend/ws/git/diff.ts +69 -0
- package/backend/ws/git/index.ts +24 -0
- package/backend/ws/git/log.ts +41 -0
- package/backend/ws/git/remote.ts +214 -0
- package/backend/ws/git/staging.ts +84 -0
- package/backend/ws/git/status.ts +90 -0
- package/backend/ws/index.ts +69 -0
- package/backend/ws/mcp/index.ts +61 -0
- package/backend/ws/messages/crud.ts +74 -0
- package/backend/ws/messages/index.ts +14 -0
- package/backend/ws/preview/browser/cleanup.ts +129 -0
- package/backend/ws/preview/browser/console.ts +114 -0
- package/backend/ws/preview/browser/interact.ts +513 -0
- package/backend/ws/preview/browser/mcp.ts +129 -0
- package/backend/ws/preview/browser/native-ui.ts +235 -0
- package/backend/ws/preview/browser/stats.ts +55 -0
- package/backend/ws/preview/browser/tab-info.ts +126 -0
- package/backend/ws/preview/browser/tab.ts +166 -0
- package/backend/ws/preview/browser/webcodecs.ts +293 -0
- package/backend/ws/preview/index.ts +146 -0
- package/backend/ws/projects/crud.ts +113 -0
- package/backend/ws/projects/index.ts +25 -0
- package/backend/ws/projects/presence.ts +46 -0
- package/backend/ws/projects/status.ts +116 -0
- package/backend/ws/sessions/crud.ts +327 -0
- package/backend/ws/sessions/index.ts +33 -0
- package/backend/ws/settings/crud.ts +112 -0
- package/backend/ws/settings/index.ts +14 -0
- package/backend/ws/snapshot/index.ts +17 -0
- package/backend/ws/snapshot/restore.ts +173 -0
- package/backend/ws/snapshot/timeline.ts +141 -0
- package/backend/ws/system/index.ts +14 -0
- package/backend/ws/system/operations.ts +49 -0
- package/backend/ws/terminal/index.ts +40 -0
- package/backend/ws/terminal/persistence.ts +153 -0
- package/backend/ws/terminal/session.ts +382 -0
- package/backend/ws/terminal/stream.ts +79 -0
- package/backend/ws/tunnel/index.ts +14 -0
- package/backend/ws/tunnel/operations.ts +91 -0
- package/backend/ws/types.ts +20 -0
- package/backend/ws/user/crud.ts +156 -0
- package/backend/ws/user/index.ts +14 -0
- package/bin/clopen.ts +307 -0
- package/bun.lock +1352 -0
- package/frontend/App.svelte +34 -0
- package/frontend/app.css +313 -0
- package/frontend/lib/app-environment.ts +10 -0
- package/frontend/lib/components/chat/ChatInterface.svelte +407 -0
- package/frontend/lib/components/chat/formatters/ErrorMessage.svelte +57 -0
- package/frontend/lib/components/chat/formatters/MessageFormatter.svelte +224 -0
- package/frontend/lib/components/chat/formatters/TextMessage.svelte +395 -0
- package/frontend/lib/components/chat/formatters/Tools.svelte +70 -0
- package/frontend/lib/components/chat/formatters/index.ts +3 -0
- package/frontend/lib/components/chat/input/ChatInput.svelte +421 -0
- package/frontend/lib/components/chat/input/components/ChatInputActions.svelte +78 -0
- package/frontend/lib/components/chat/input/components/DragDropOverlay.svelte +30 -0
- package/frontend/lib/components/chat/input/components/EditModeIndicator.svelte +33 -0
- package/frontend/lib/components/chat/input/components/EngineModelPicker.svelte +619 -0
- package/frontend/lib/components/chat/input/components/FileAttachmentPreview.svelte +48 -0
- package/frontend/lib/components/chat/input/components/LoadingIndicator.svelte +31 -0
- package/frontend/lib/components/chat/input/composables/use-animations.svelte.ts +201 -0
- package/frontend/lib/components/chat/input/composables/use-chat-actions.svelte.ts +148 -0
- package/frontend/lib/components/chat/input/composables/use-file-handling.svelte.ts +216 -0
- package/frontend/lib/components/chat/input/composables/use-input-state.svelte.ts +357 -0
- package/frontend/lib/components/chat/input/composables/use-textarea-resize.svelte.ts +57 -0
- package/frontend/lib/components/chat/message/ChatMessage.svelte +478 -0
- package/frontend/lib/components/chat/message/ChatMessages.svelte +541 -0
- package/frontend/lib/components/chat/message/DateSeparator.svelte +86 -0
- package/frontend/lib/components/chat/message/MessageBubble.svelte +86 -0
- package/frontend/lib/components/chat/message/MessageHeader.svelte +157 -0
- package/frontend/lib/components/chat/modal/DebugModal.svelte +59 -0
- package/frontend/lib/components/chat/modal/TokenUsageModal.svelte +124 -0
- package/frontend/lib/components/chat/shared/index.ts +2 -0
- package/frontend/lib/components/chat/shared/utils.ts +116 -0
- package/frontend/lib/components/chat/tools/BashOutputTool.svelte +35 -0
- package/frontend/lib/components/chat/tools/BashTool.svelte +46 -0
- package/frontend/lib/components/chat/tools/CustomMcpTool.svelte +139 -0
- package/frontend/lib/components/chat/tools/EditTool.svelte +48 -0
- package/frontend/lib/components/chat/tools/ExitPlanModeTool.svelte +32 -0
- package/frontend/lib/components/chat/tools/GlobTool.svelte +51 -0
- package/frontend/lib/components/chat/tools/GrepTool.svelte +90 -0
- package/frontend/lib/components/chat/tools/KillShellTool.svelte +26 -0
- package/frontend/lib/components/chat/tools/ListMcpResourcesTool.svelte +31 -0
- package/frontend/lib/components/chat/tools/NotebookEditTool.svelte +38 -0
- package/frontend/lib/components/chat/tools/ReadMcpResourceTool.svelte +34 -0
- package/frontend/lib/components/chat/tools/ReadTool.svelte +41 -0
- package/frontend/lib/components/chat/tools/TaskTool.svelte +64 -0
- package/frontend/lib/components/chat/tools/TodoWriteTool.svelte +75 -0
- package/frontend/lib/components/chat/tools/WebFetchTool.svelte +35 -0
- package/frontend/lib/components/chat/tools/WebSearchTool.svelte +84 -0
- package/frontend/lib/components/chat/tools/WriteTool.svelte +33 -0
- package/frontend/lib/components/chat/tools/components/CodeBlock.svelte +79 -0
- package/frontend/lib/components/chat/tools/components/DiffBlock.svelte +408 -0
- package/frontend/lib/components/chat/tools/components/FileHeader.svelte +45 -0
- package/frontend/lib/components/chat/tools/components/InfoLine.svelte +19 -0
- package/frontend/lib/components/chat/tools/components/StatsBadges.svelte +27 -0
- package/frontend/lib/components/chat/tools/components/TerminalCommand.svelte +54 -0
- package/frontend/lib/components/chat/tools/components/index.ts +7 -0
- package/frontend/lib/components/chat/tools/index.ts +26 -0
- package/frontend/lib/components/chat/widgets/FloatingTodoList.svelte +249 -0
- package/frontend/lib/components/chat/widgets/TokenUsage.svelte +78 -0
- package/frontend/lib/components/checkpoint/TimelineModal.svelte +391 -0
- package/frontend/lib/components/checkpoint/timeline/TimelineEdge.svelte +26 -0
- package/frontend/lib/components/checkpoint/timeline/TimelineGraph.svelte +87 -0
- package/frontend/lib/components/checkpoint/timeline/TimelineNode.svelte +108 -0
- package/frontend/lib/components/checkpoint/timeline/TimelineVersionGroup.svelte +59 -0
- package/frontend/lib/components/checkpoint/timeline/animation.ts +168 -0
- package/frontend/lib/components/checkpoint/timeline/config.ts +44 -0
- package/frontend/lib/components/checkpoint/timeline/graph-builder.ts +304 -0
- package/frontend/lib/components/checkpoint/timeline/types.ts +65 -0
- package/frontend/lib/components/checkpoint/timeline/utils.ts +53 -0
- package/frontend/lib/components/common/Alert.svelte +139 -0
- package/frontend/lib/components/common/AvatarBubble.svelte +56 -0
- package/frontend/lib/components/common/Button.svelte +71 -0
- package/frontend/lib/components/common/Card.svelte +102 -0
- package/frontend/lib/components/common/Checkbox.svelte +48 -0
- package/frontend/lib/components/common/Dialog.svelte +249 -0
- package/frontend/lib/components/common/FolderBrowser.svelte +843 -0
- package/frontend/lib/components/common/Icon.svelte +58 -0
- package/frontend/lib/components/common/Input.svelte +72 -0
- package/frontend/lib/components/common/Lightbox.svelte +233 -0
- package/frontend/lib/components/common/LoadingScreen.svelte +52 -0
- package/frontend/lib/components/common/LoadingSpinner.svelte +48 -0
- package/frontend/lib/components/common/Modal.svelte +177 -0
- package/frontend/lib/components/common/ModalProvider.svelte +28 -0
- package/frontend/lib/components/common/ModelSelector.svelte +110 -0
- package/frontend/lib/components/common/MonacoEditor.svelte +569 -0
- package/frontend/lib/components/common/NotificationToast.svelte +113 -0
- package/frontend/lib/components/common/PageTemplate.svelte +76 -0
- package/frontend/lib/components/common/ProjectUserAvatars.svelte +79 -0
- package/frontend/lib/components/common/Select.svelte +98 -0
- package/frontend/lib/components/common/Textarea.svelte +80 -0
- package/frontend/lib/components/common/ThemeToggle.svelte +44 -0
- package/frontend/lib/components/common/lucide-icons.ts +1642 -0
- package/frontend/lib/components/common/material-icons.ts +1082 -0
- package/frontend/lib/components/common/xterm/XTerm.svelte +796 -0
- package/frontend/lib/components/common/xterm/index.ts +16 -0
- package/frontend/lib/components/common/xterm/terminal-config.ts +68 -0
- package/frontend/lib/components/common/xterm/types.ts +31 -0
- package/frontend/lib/components/common/xterm/xterm-service.ts +353 -0
- package/frontend/lib/components/files/FileNode.svelte +384 -0
- package/frontend/lib/components/files/FileTree.svelte +681 -0
- package/frontend/lib/components/files/FileViewer.svelte +728 -0
- package/frontend/lib/components/files/SearchResults.svelte +303 -0
- package/frontend/lib/components/git/BranchManager.svelte +458 -0
- package/frontend/lib/components/git/ChangesSection.svelte +107 -0
- package/frontend/lib/components/git/CommitForm.svelte +76 -0
- package/frontend/lib/components/git/ConflictResolver.svelte +158 -0
- package/frontend/lib/components/git/DiffViewer.svelte +364 -0
- package/frontend/lib/components/git/FileChangeItem.svelte +97 -0
- package/frontend/lib/components/git/GitButton.svelte +33 -0
- package/frontend/lib/components/git/GitLog.svelte +361 -0
- package/frontend/lib/components/git/GitModal.svelte +80 -0
- package/frontend/lib/components/history/HistoryModal.svelte +563 -0
- package/frontend/lib/components/history/HistoryView.svelte +615 -0
- package/frontend/lib/components/index.ts +34 -0
- package/frontend/lib/components/preview/browser/BrowserPreview.svelte +549 -0
- package/frontend/lib/components/preview/browser/components/Canvas.svelte +1058 -0
- package/frontend/lib/components/preview/browser/components/ConsolePanel.svelte +757 -0
- package/frontend/lib/components/preview/browser/components/Container.svelte +450 -0
- package/frontend/lib/components/preview/browser/components/ContextMenu.svelte +236 -0
- package/frontend/lib/components/preview/browser/components/SelectDropdown.svelte +224 -0
- package/frontend/lib/components/preview/browser/components/Toolbar.svelte +339 -0
- package/frontend/lib/components/preview/browser/components/VirtualCursor.svelte +36 -0
- package/frontend/lib/components/preview/browser/core/cleanup.svelte.ts +155 -0
- package/frontend/lib/components/preview/browser/core/coordinator.svelte.ts +837 -0
- package/frontend/lib/components/preview/browser/core/interactions.svelte.ts +113 -0
- package/frontend/lib/components/preview/browser/core/mcp-handlers.svelte.ts +296 -0
- package/frontend/lib/components/preview/browser/core/native-ui-handlers.svelte.ts +391 -0
- package/frontend/lib/components/preview/browser/core/stream-handler.svelte.ts +231 -0
- package/frontend/lib/components/preview/browser/core/tab-manager.svelte.ts +210 -0
- package/frontend/lib/components/preview/browser/core/tab-operations.svelte.ts +239 -0
- package/frontend/lib/components/preview/index.ts +2 -0
- package/frontend/lib/components/settings/SettingsModal.svelte +235 -0
- package/frontend/lib/components/settings/SettingsView.svelte +36 -0
- package/frontend/lib/components/settings/appearance/AppearanceSettings.svelte +51 -0
- package/frontend/lib/components/settings/appearance/LayoutPresetSettings.svelte +160 -0
- package/frontend/lib/components/settings/appearance/LayoutPreview.svelte +76 -0
- package/frontend/lib/components/settings/engines/AIEnginesSettings.svelte +917 -0
- package/frontend/lib/components/settings/general/AdvancedSettings.svelte +187 -0
- package/frontend/lib/components/settings/general/DataManagementSettings.svelte +203 -0
- package/frontend/lib/components/settings/general/GeneralSettings.svelte +10 -0
- package/frontend/lib/components/settings/model/ModelSettings.svelte +357 -0
- package/frontend/lib/components/settings/notifications/NotificationSettings.svelte +205 -0
- package/frontend/lib/components/settings/user/UserSettings.svelte +197 -0
- package/frontend/lib/components/terminal/Terminal.svelte +368 -0
- package/frontend/lib/components/terminal/TerminalTabs.svelte +87 -0
- package/frontend/lib/components/terminal/TerminalView.svelte +55 -0
- package/frontend/lib/components/tunnel/TunnelActive.svelte +142 -0
- package/frontend/lib/components/tunnel/TunnelButton.svelte +54 -0
- package/frontend/lib/components/tunnel/TunnelInactive.svelte +284 -0
- package/frontend/lib/components/tunnel/TunnelModal.svelte +47 -0
- package/frontend/lib/components/tunnel/TunnelQRCode.svelte +49 -0
- package/frontend/lib/components/workspace/DesktopNavigator.svelte +382 -0
- package/frontend/lib/components/workspace/MobileNavigator.svelte +403 -0
- package/frontend/lib/components/workspace/PanelContainer.svelte +100 -0
- package/frontend/lib/components/workspace/PanelHeader.svelte +505 -0
- package/frontend/lib/components/workspace/ViewMenu.svelte +162 -0
- package/frontend/lib/components/workspace/WorkspaceLayout.svelte +169 -0
- package/frontend/lib/components/workspace/layout/DesktopLayout.svelte +15 -0
- package/frontend/lib/components/workspace/layout/MobileLayout.svelte +17 -0
- package/frontend/lib/components/workspace/layout/split-pane/Container.svelte +42 -0
- package/frontend/lib/components/workspace/layout/split-pane/Handle.svelte +85 -0
- package/frontend/lib/components/workspace/layout/split-pane/Layout.svelte +37 -0
- package/frontend/lib/components/workspace/panels/ChatPanel.svelte +274 -0
- package/frontend/lib/components/workspace/panels/FilesPanel.svelte +1261 -0
- package/frontend/lib/components/workspace/panels/GitPanel.svelte +1560 -0
- package/frontend/lib/components/workspace/panels/PreviewPanel.svelte +150 -0
- package/frontend/lib/components/workspace/panels/TerminalPanel.svelte +73 -0
- package/frontend/lib/constants/preview.ts +45 -0
- package/frontend/lib/services/chat/chat.service.ts +704 -0
- package/frontend/lib/services/chat/index.ts +7 -0
- package/frontend/lib/services/notification/global-stream-monitor.ts +86 -0
- package/frontend/lib/services/notification/index.ts +8 -0
- package/frontend/lib/services/notification/push.service.ts +144 -0
- package/frontend/lib/services/notification/sound.service.ts +127 -0
- package/frontend/lib/services/preview/browser/browser-console.service.ts +61 -0
- package/frontend/lib/services/preview/browser/browser-webcodecs.service.ts +1499 -0
- package/frontend/lib/services/preview/browser/mcp-integration.svelte.ts +67 -0
- package/frontend/lib/services/preview/index.ts +23 -0
- package/frontend/lib/services/project/index.ts +8 -0
- package/frontend/lib/services/project/status.service.ts +159 -0
- package/frontend/lib/services/snapshot/snapshot.service.ts +47 -0
- package/frontend/lib/services/terminal/background/index.ts +130 -0
- package/frontend/lib/services/terminal/background/session-restore.ts +274 -0
- package/frontend/lib/services/terminal/background/stream-manager.ts +286 -0
- package/frontend/lib/services/terminal/index.ts +14 -0
- package/frontend/lib/services/terminal/persistence.service.ts +260 -0
- package/frontend/lib/services/terminal/project.service.ts +953 -0
- package/frontend/lib/services/terminal/session.service.ts +364 -0
- package/frontend/lib/services/terminal/terminal.service.ts +369 -0
- package/frontend/lib/stores/core/app.svelte.ts +117 -0
- package/frontend/lib/stores/core/files.svelte.ts +73 -0
- package/frontend/lib/stores/core/presence.svelte.ts +48 -0
- package/frontend/lib/stores/core/projects.svelte.ts +317 -0
- package/frontend/lib/stores/core/sessions.svelte.ts +383 -0
- package/frontend/lib/stores/features/claude-accounts.svelte.ts +58 -0
- package/frontend/lib/stores/features/models.svelte.ts +89 -0
- package/frontend/lib/stores/features/settings.svelte.ts +87 -0
- package/frontend/lib/stores/features/terminal.svelte.ts +701 -0
- package/frontend/lib/stores/features/tunnel.svelte.ts +161 -0
- package/frontend/lib/stores/features/user.svelte.ts +96 -0
- package/frontend/lib/stores/ui/chat-input.svelte.ts +57 -0
- package/frontend/lib/stores/ui/chat-model.svelte.ts +61 -0
- package/frontend/lib/stores/ui/dialog.svelte.ts +59 -0
- package/frontend/lib/stores/ui/edit-mode.svelte.ts +214 -0
- package/frontend/lib/stores/ui/notification.svelte.ts +166 -0
- package/frontend/lib/stores/ui/settings-modal.svelte.ts +88 -0
- package/frontend/lib/stores/ui/theme.svelte.ts +179 -0
- package/frontend/lib/stores/ui/workspace.svelte.ts +754 -0
- package/frontend/lib/types/native-ui.ts +73 -0
- package/frontend/lib/utils/chat/date-separator.ts +39 -0
- package/frontend/lib/utils/chat/message-grouper.ts +219 -0
- package/frontend/lib/utils/chat/message-processor.ts +135 -0
- package/frontend/lib/utils/chat/tool-handler.ts +161 -0
- package/frontend/lib/utils/chat/virtual-scroll.svelte.ts +142 -0
- package/frontend/lib/utils/click-outside.ts +20 -0
- package/frontend/lib/utils/context-manager.ts +257 -0
- package/frontend/lib/utils/file-icon-mappings.ts +769 -0
- package/frontend/lib/utils/folder-icon-mappings.ts +1030 -0
- package/frontend/lib/utils/git-status.ts +68 -0
- package/frontend/lib/utils/platform.ts +113 -0
- package/frontend/lib/utils/port-check.ts +65 -0
- package/frontend/lib/utils/terminalFormatter.ts +207 -0
- package/frontend/lib/utils/theme.ts +6 -0
- package/frontend/lib/utils/tree-visualizer.ts +320 -0
- package/frontend/lib/utils/ws.ts +44 -0
- package/frontend/main.ts +13 -0
- package/index.html +70 -0
- package/package.json +111 -0
- package/scripts/generate-icons.ts +87 -0
- package/scripts/pre-publish-check.sh +142 -0
- package/scripts/setup-hooks.sh +134 -0
- package/scripts/validate-branch-name.sh +47 -0
- package/scripts/validate-commit-msg.sh +42 -0
- package/shared/constants/engines.ts +134 -0
- package/shared/types/database/connection.ts +16 -0
- package/shared/types/database/index.ts +6 -0
- package/shared/types/database/schema.ts +141 -0
- package/shared/types/engine/index.ts +45 -0
- package/shared/types/filesystem/index.ts +22 -0
- package/shared/types/git.ts +171 -0
- package/shared/types/messaging/index.ts +239 -0
- package/shared/types/messaging/tool.ts +526 -0
- package/shared/types/network/api.ts +18 -0
- package/shared/types/network/index.ts +5 -0
- package/shared/types/stores/app.ts +23 -0
- package/shared/types/stores/dialog.ts +21 -0
- package/shared/types/stores/index.ts +3 -0
- package/shared/types/stores/settings.ts +15 -0
- package/shared/types/terminal/index.ts +44 -0
- package/shared/types/ui/components.ts +61 -0
- package/shared/types/ui/icons.ts +23 -0
- package/shared/types/ui/index.ts +22 -0
- package/shared/types/ui/notifications.ts +14 -0
- package/shared/types/ui/theme.ts +12 -0
- package/shared/types/websocket/index.ts +43 -0
- package/shared/types/window.d.ts +13 -0
- package/shared/utils/anonymous-user.ts +168 -0
- package/shared/utils/async.ts +10 -0
- package/shared/utils/diff-calculator.ts +184 -0
- package/shared/utils/file-type-detection.ts +166 -0
- package/shared/utils/logger.ts +158 -0
- package/shared/utils/message-formatter.ts +79 -0
- package/shared/utils/path.ts +47 -0
- package/shared/utils/ws-client.ts +768 -0
- package/shared/utils/ws-server.ts +660 -0
- package/static/audio/notification.ogg +0 -0
- package/static/favicon.svg +8 -0
- package/static/fonts/dm-sans/dm-sans-italic-latin-ext.woff2 +0 -0
- package/static/fonts/dm-sans/dm-sans-italic-latin.woff2 +0 -0
- package/static/fonts/dm-sans/dm-sans-normal-latin-ext.woff2 +0 -0
- package/static/fonts/dm-sans/dm-sans-normal-latin.woff2 +0 -0
- package/static/fonts/dm-sans.css +96 -0
- package/svelte.config.js +20 -0
- package/vite.config.ts +33 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component prop types and interfaces
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface ButtonProps {
|
|
6
|
+
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
|
|
7
|
+
size?: 'sm' | 'md' | 'lg';
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
loading?: boolean;
|
|
10
|
+
type?: 'button' | 'submit' | 'reset';
|
|
11
|
+
onclick?: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface InputProps {
|
|
15
|
+
value?: string;
|
|
16
|
+
placeholder?: string;
|
|
17
|
+
type?: 'text' | 'password' | 'email' | 'number' | 'search';
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
error?: string;
|
|
20
|
+
label?: string;
|
|
21
|
+
required?: boolean;
|
|
22
|
+
onchange?: (value: string) => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface TextareaProps {
|
|
26
|
+
value?: string;
|
|
27
|
+
placeholder?: string;
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
error?: string;
|
|
30
|
+
label?: string;
|
|
31
|
+
required?: boolean;
|
|
32
|
+
rows?: number;
|
|
33
|
+
resize?: 'none' | 'both' | 'horizontal' | 'vertical';
|
|
34
|
+
onchange?: (value: string) => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface SelectOption {
|
|
38
|
+
value: string;
|
|
39
|
+
label: string;
|
|
40
|
+
disabled?: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface SelectProps {
|
|
44
|
+
value?: string;
|
|
45
|
+
placeholder?: string;
|
|
46
|
+
disabled?: boolean;
|
|
47
|
+
error?: string;
|
|
48
|
+
label?: string;
|
|
49
|
+
required?: boolean;
|
|
50
|
+
options: SelectOption[];
|
|
51
|
+
onchange?: (value: string) => void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface CardProps {
|
|
55
|
+
title?: string;
|
|
56
|
+
subtitle?: string;
|
|
57
|
+
variant?: 'default' | 'outlined' | 'elevated' | 'glass';
|
|
58
|
+
padding?: 'none' | 'sm' | 'md' | 'lg';
|
|
59
|
+
clickable?: boolean;
|
|
60
|
+
onclick?: () => void;
|
|
61
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Icon system types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Icon types for type safety
|
|
6
|
+
import type { lucideIconRegistry } from '$frontend/lib/components/common/lucide-icons';
|
|
7
|
+
import type { materialIconRegistry } from '$frontend/lib/components/common/material-icons';
|
|
8
|
+
|
|
9
|
+
// Individual icon type exports from auto-generated files
|
|
10
|
+
export type { LucideIconName } from '$frontend/lib/components/common/lucide-icons';
|
|
11
|
+
export type { MaterialIconName } from '$frontend/lib/components/common/material-icons';
|
|
12
|
+
|
|
13
|
+
// Combined icon registry type
|
|
14
|
+
const iconRegistry = {
|
|
15
|
+
// ALL LUCIDE ICONS
|
|
16
|
+
...({} as typeof lucideIconRegistry),
|
|
17
|
+
|
|
18
|
+
// ALL MATERIAL ICON THEME ICONS
|
|
19
|
+
...({} as typeof materialIconRegistry),
|
|
20
|
+
} as const;
|
|
21
|
+
|
|
22
|
+
// Type for all supported icons
|
|
23
|
+
export type IconName = keyof typeof iconRegistry;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI types barrel export
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export * from './theme';
|
|
6
|
+
export * from './notifications';
|
|
7
|
+
export * from './icons';
|
|
8
|
+
export * from './components';
|
|
9
|
+
|
|
10
|
+
// Common UI types moved from common/ui.ts
|
|
11
|
+
export type NotificationType = 'success' | 'error' | 'warning' | 'info';
|
|
12
|
+
|
|
13
|
+
export interface ButtonAction {
|
|
14
|
+
label: string;
|
|
15
|
+
action: () => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface BaseDialogOptions {
|
|
19
|
+
title?: string;
|
|
20
|
+
message: string;
|
|
21
|
+
type?: NotificationType;
|
|
22
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notification and toast types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { NotificationType, ButtonAction } from './index';
|
|
6
|
+
|
|
7
|
+
export interface ToastNotification {
|
|
8
|
+
id: string;
|
|
9
|
+
type: NotificationType;
|
|
10
|
+
title: string;
|
|
11
|
+
message: string;
|
|
12
|
+
duration?: number;
|
|
13
|
+
actions?: ButtonAction[];
|
|
14
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Shared types for WebSocket communication between backend and frontend
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* WebSocket message format
|
|
9
|
+
*/
|
|
10
|
+
export interface WSMessage<T = any> {
|
|
11
|
+
action: string;
|
|
12
|
+
payload: T;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* WebSocket client options
|
|
17
|
+
*/
|
|
18
|
+
export interface WSClientOptions {
|
|
19
|
+
/** Auto-reconnect on connection loss */
|
|
20
|
+
autoReconnect?: boolean;
|
|
21
|
+
/** Maximum reconnection attempts (0 = infinite) */
|
|
22
|
+
maxReconnectAttempts?: number;
|
|
23
|
+
/** Initial reconnect delay in ms */
|
|
24
|
+
reconnectDelay?: number;
|
|
25
|
+
/** Maximum reconnect delay in ms */
|
|
26
|
+
maxReconnectDelay?: number;
|
|
27
|
+
/** Debug logging */
|
|
28
|
+
debug?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* WebSocket connection state
|
|
33
|
+
*/
|
|
34
|
+
export type WSConnectionState = 'connecting' | 'connected' | 'disconnected' | 'reconnecting';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* WebSocket error types
|
|
38
|
+
*/
|
|
39
|
+
export interface WSError {
|
|
40
|
+
type: 'connection' | 'validation' | 'timeout' | 'unknown';
|
|
41
|
+
message: string;
|
|
42
|
+
details?: any;
|
|
43
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { debug } from '$shared/utils/logger';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Anonymous User Management
|
|
5
|
+
* Client-side utilities for managing anonymous user identities
|
|
6
|
+
* Server-side generation via WebSocket user:anonymous
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Dynamic import to avoid circular dependency and SSR issues
|
|
10
|
+
let wsClient: any = null;
|
|
11
|
+
async function getWS() {
|
|
12
|
+
if (!wsClient && typeof window !== 'undefined') {
|
|
13
|
+
const module = await import('$frontend/lib/utils/ws');
|
|
14
|
+
wsClient = module.default;
|
|
15
|
+
}
|
|
16
|
+
return wsClient;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface AnonymousUser {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
color: string;
|
|
23
|
+
avatar: string;
|
|
24
|
+
createdAt: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Generate a unique anonymous user identity via WebSocket
|
|
29
|
+
*/
|
|
30
|
+
async function generateAnonymousUserFromServer(): Promise<AnonymousUser | null> {
|
|
31
|
+
try {
|
|
32
|
+
const ws = await getWS();
|
|
33
|
+
if (!ws) {
|
|
34
|
+
debug.error('user', 'WebSocket client not available');
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const response = await ws.http('user:anonymous', {});
|
|
39
|
+
|
|
40
|
+
debug.log('user', '✅ Generated anonymous user from server:', response.name);
|
|
41
|
+
return response;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
debug.error('user', 'Error calling anonymous user API:', error);
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get or create anonymous user from localStorage
|
|
50
|
+
* If not found, generates new user via server API
|
|
51
|
+
*/
|
|
52
|
+
export async function getOrCreateAnonymousUser(): Promise<AnonymousUser | null> {
|
|
53
|
+
// Check if we're in browser environment
|
|
54
|
+
if (typeof window === 'undefined') {
|
|
55
|
+
debug.warn('user', 'Cannot create anonymous user on server side');
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const stored = localStorage.getItem('claude-anonymous-user');
|
|
60
|
+
|
|
61
|
+
if (stored) {
|
|
62
|
+
try {
|
|
63
|
+
const user = JSON.parse(stored);
|
|
64
|
+
// Validate the stored user has all required fields
|
|
65
|
+
if (user.id && user.name && user.color && user.avatar) {
|
|
66
|
+
debug.log('user', 'Found existing anonymous user:', user.name);
|
|
67
|
+
return user;
|
|
68
|
+
}
|
|
69
|
+
} catch (e) {
|
|
70
|
+
debug.error('user', 'Invalid stored anonymous user:', e);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Generate new user via server API
|
|
75
|
+
debug.log('user', 'No valid stored user, generating new one from server...');
|
|
76
|
+
const newUser = await generateAnonymousUserFromServer();
|
|
77
|
+
|
|
78
|
+
if (newUser) {
|
|
79
|
+
localStorage.setItem('claude-anonymous-user', JSON.stringify(newUser));
|
|
80
|
+
return newUser;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
debug.error('user', 'Failed to generate anonymous user');
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Get current anonymous user from localStorage
|
|
89
|
+
*/
|
|
90
|
+
export function getCurrentAnonymousUser(): AnonymousUser | null {
|
|
91
|
+
// Check if we're in browser environment
|
|
92
|
+
if (typeof window === 'undefined') {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const stored = localStorage.getItem('claude-anonymous-user');
|
|
97
|
+
|
|
98
|
+
if (stored) {
|
|
99
|
+
try {
|
|
100
|
+
return JSON.parse(stored);
|
|
101
|
+
} catch (e) {
|
|
102
|
+
debug.error('user', 'Failed to parse anonymous user:', e);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Update anonymous user name
|
|
111
|
+
* Updates via WebSocket
|
|
112
|
+
*/
|
|
113
|
+
export async function updateAnonymousUserName(newName: string): Promise<AnonymousUser | null> {
|
|
114
|
+
// Check if we're in browser environment
|
|
115
|
+
if (typeof window === 'undefined') {
|
|
116
|
+
debug.error('user', 'Cannot update user name on server side');
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const currentUser = getCurrentAnonymousUser();
|
|
121
|
+
|
|
122
|
+
if (!currentUser) {
|
|
123
|
+
debug.error('user', 'No current anonymous user found');
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Validate name (basic validation)
|
|
128
|
+
if (!newName || newName.trim().length === 0) {
|
|
129
|
+
debug.error('user', 'Invalid name provided');
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const trimmedName = newName.trim();
|
|
134
|
+
|
|
135
|
+
// Call server via WebSocket to get updated user
|
|
136
|
+
try {
|
|
137
|
+
const ws = await getWS();
|
|
138
|
+
if (!ws) {
|
|
139
|
+
debug.error('user', 'WebSocket client not available');
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const response = await ws.http('user:update', {
|
|
144
|
+
userId: currentUser.id,
|
|
145
|
+
newName: trimmedName
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Save to localStorage
|
|
149
|
+
localStorage.setItem('claude-anonymous-user', JSON.stringify(response));
|
|
150
|
+
debug.log('user', '✅ Updated user name:', response.name);
|
|
151
|
+
return response;
|
|
152
|
+
} catch (error) {
|
|
153
|
+
debug.error('user', 'Error calling update user API:', error);
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Format user display name (shorter version for UI)
|
|
160
|
+
*/
|
|
161
|
+
export function formatUserDisplayName(user: AnonymousUser): string {
|
|
162
|
+
// Extract just the animal and number for shorter display
|
|
163
|
+
const parts = user.name.split(' ');
|
|
164
|
+
if (parts.length >= 3) {
|
|
165
|
+
return `${parts[1]} ${parts[2]}`;
|
|
166
|
+
}
|
|
167
|
+
return user.name;
|
|
168
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diff Calculator Utility
|
|
3
|
+
* Calculates git-like line-level differences between file contents
|
|
4
|
+
* Accepts Buffer for binary-safe handling — converts to string internally for line diffing.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface FileChangeStats {
|
|
8
|
+
filesChanged: number;
|
|
9
|
+
insertions: number;
|
|
10
|
+
deletions: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface FileDiff {
|
|
14
|
+
filepath: string;
|
|
15
|
+
insertions: number;
|
|
16
|
+
deletions: number;
|
|
17
|
+
status: 'added' | 'modified' | 'deleted';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Calculate line-level diff statistics similar to git
|
|
22
|
+
* Compares two file snapshots and returns stats about changes
|
|
23
|
+
*/
|
|
24
|
+
export function calculateFileChangeStats(
|
|
25
|
+
previousSnapshot: Record<string, Buffer>,
|
|
26
|
+
currentSnapshot: Record<string, Buffer>
|
|
27
|
+
): FileChangeStats {
|
|
28
|
+
let totalInsertions = 0;
|
|
29
|
+
let totalDeletions = 0;
|
|
30
|
+
const changedFiles = new Set<string>();
|
|
31
|
+
|
|
32
|
+
// Check added and modified files
|
|
33
|
+
for (const [filepath, newContent] of Object.entries(currentSnapshot)) {
|
|
34
|
+
const oldContent = previousSnapshot[filepath];
|
|
35
|
+
|
|
36
|
+
if (!oldContent) {
|
|
37
|
+
// File was added - count all lines as insertions
|
|
38
|
+
const lines = countLines(newContent.toString('utf-8'));
|
|
39
|
+
totalInsertions += lines;
|
|
40
|
+
changedFiles.add(filepath);
|
|
41
|
+
} else if (!oldContent.equals(newContent)) {
|
|
42
|
+
// File was modified - calculate line diff
|
|
43
|
+
const diff = calculateLineDiff(oldContent.toString('utf-8'), newContent.toString('utf-8'));
|
|
44
|
+
totalInsertions += diff.insertions;
|
|
45
|
+
totalDeletions += diff.deletions;
|
|
46
|
+
changedFiles.add(filepath);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Check deleted files
|
|
51
|
+
for (const [filepath, oldContent] of Object.entries(previousSnapshot)) {
|
|
52
|
+
if (!currentSnapshot[filepath]) {
|
|
53
|
+
// File was deleted - count all lines as deletions
|
|
54
|
+
const lines = countLines(oldContent.toString('utf-8'));
|
|
55
|
+
totalDeletions += lines;
|
|
56
|
+
changedFiles.add(filepath);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
filesChanged: changedFiles.size,
|
|
62
|
+
insertions: totalInsertions,
|
|
63
|
+
deletions: totalDeletions
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get detailed diff for each file
|
|
69
|
+
* Useful for displaying individual file changes
|
|
70
|
+
*/
|
|
71
|
+
export function getDetailedFileDiffs(
|
|
72
|
+
previousSnapshot: Record<string, Buffer>,
|
|
73
|
+
currentSnapshot: Record<string, Buffer>
|
|
74
|
+
): FileDiff[] {
|
|
75
|
+
const diffs: FileDiff[] = [];
|
|
76
|
+
|
|
77
|
+
// Check added and modified files
|
|
78
|
+
for (const [filepath, newContent] of Object.entries(currentSnapshot)) {
|
|
79
|
+
const oldContent = previousSnapshot[filepath];
|
|
80
|
+
|
|
81
|
+
if (!oldContent) {
|
|
82
|
+
// File was added
|
|
83
|
+
diffs.push({
|
|
84
|
+
filepath,
|
|
85
|
+
insertions: countLines(newContent.toString('utf-8')),
|
|
86
|
+
deletions: 0,
|
|
87
|
+
status: 'added'
|
|
88
|
+
});
|
|
89
|
+
} else if (!oldContent.equals(newContent)) {
|
|
90
|
+
// File was modified
|
|
91
|
+
const diff = calculateLineDiff(oldContent.toString('utf-8'), newContent.toString('utf-8'));
|
|
92
|
+
diffs.push({
|
|
93
|
+
filepath,
|
|
94
|
+
insertions: diff.insertions,
|
|
95
|
+
deletions: diff.deletions,
|
|
96
|
+
status: 'modified'
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Check deleted files
|
|
102
|
+
for (const [filepath, oldContent] of Object.entries(previousSnapshot)) {
|
|
103
|
+
if (!currentSnapshot[filepath]) {
|
|
104
|
+
// File was deleted
|
|
105
|
+
diffs.push({
|
|
106
|
+
filepath,
|
|
107
|
+
insertions: 0,
|
|
108
|
+
deletions: countLines(oldContent.toString('utf-8')),
|
|
109
|
+
status: 'deleted'
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return diffs;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Calculate line-level diff between two file contents
|
|
119
|
+
* Uses simple line-by-line comparison (similar to diff -u)
|
|
120
|
+
*/
|
|
121
|
+
function calculateLineDiff(
|
|
122
|
+
oldContent: string,
|
|
123
|
+
newContent: string
|
|
124
|
+
): { insertions: number; deletions: number } {
|
|
125
|
+
const oldLines = splitLines(oldContent);
|
|
126
|
+
const newLines = splitLines(newContent);
|
|
127
|
+
|
|
128
|
+
// Use Myers diff algorithm (simplified version)
|
|
129
|
+
// For performance, we use a simple LCS-based approach
|
|
130
|
+
const lcs = longestCommonSubsequence(oldLines, newLines);
|
|
131
|
+
|
|
132
|
+
const insertions = newLines.length - lcs;
|
|
133
|
+
const deletions = oldLines.length - lcs;
|
|
134
|
+
|
|
135
|
+
return { insertions, deletions };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Calculate Longest Common Subsequence length
|
|
140
|
+
* Used to determine how many lines are unchanged
|
|
141
|
+
*/
|
|
142
|
+
function longestCommonSubsequence(arr1: string[], arr2: string[]): number {
|
|
143
|
+
const m = arr1.length;
|
|
144
|
+
const n = arr2.length;
|
|
145
|
+
|
|
146
|
+
// Create DP table
|
|
147
|
+
const dp: number[][] = Array(m + 1).fill(0).map(() => Array(n + 1).fill(0));
|
|
148
|
+
|
|
149
|
+
// Fill DP table
|
|
150
|
+
for (let i = 1; i <= m; i++) {
|
|
151
|
+
for (let j = 1; j <= n; j++) {
|
|
152
|
+
if (arr1[i - 1] === arr2[j - 1]) {
|
|
153
|
+
dp[i][j] = dp[i - 1][j - 1] + 1;
|
|
154
|
+
} else {
|
|
155
|
+
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return dp[m][n];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Split content into lines
|
|
165
|
+
* Handles different line endings (CRLF, LF)
|
|
166
|
+
*/
|
|
167
|
+
function splitLines(content: string): string[] {
|
|
168
|
+
if (!content) return [];
|
|
169
|
+
// Normalize line endings and split
|
|
170
|
+
return content.replace(/\r\n/g, '\n').split('\n');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Count number of lines in content
|
|
175
|
+
*/
|
|
176
|
+
function countLines(content: string): number {
|
|
177
|
+
if (!content) return 0;
|
|
178
|
+
const lines = splitLines(content);
|
|
179
|
+
// Don't count empty last line
|
|
180
|
+
if (lines.length > 0 && lines[lines.length - 1] === '') {
|
|
181
|
+
return lines.length - 1;
|
|
182
|
+
}
|
|
183
|
+
return lines.length;
|
|
184
|
+
}
|