@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,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database queries for message snapshots and session relationships
|
|
3
|
+
* Used for time travel feature
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { MessageSnapshot, SessionRelationship } from '$shared/types/database/schema';
|
|
7
|
+
import { getDatabase } from '../index';
|
|
8
|
+
|
|
9
|
+
import { debug } from '$shared/utils/logger';
|
|
10
|
+
export const snapshotQueries = {
|
|
11
|
+
/**
|
|
12
|
+
* Create a new message snapshot
|
|
13
|
+
* Supports both full and delta snapshots
|
|
14
|
+
*/
|
|
15
|
+
createSnapshot(data: {
|
|
16
|
+
id?: string; // Optional: allow caller to provide ID (for blob store tree naming)
|
|
17
|
+
message_id: string;
|
|
18
|
+
session_id: string;
|
|
19
|
+
project_id: string;
|
|
20
|
+
files_snapshot: Record<string, string> | {}; // Will be JSON.stringified
|
|
21
|
+
project_metadata?: any;
|
|
22
|
+
snapshot_type?: 'full' | 'delta';
|
|
23
|
+
parent_snapshot_id?: string;
|
|
24
|
+
delta_changes?: any; // DeltaChanges object
|
|
25
|
+
files_changed?: number;
|
|
26
|
+
insertions?: number;
|
|
27
|
+
deletions?: number;
|
|
28
|
+
branch_id?: string;
|
|
29
|
+
tree_hash?: string; // Blob store tree hash (new format)
|
|
30
|
+
}): MessageSnapshot {
|
|
31
|
+
const db = getDatabase();
|
|
32
|
+
const id = data.id || `snapshot_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
33
|
+
const now = new Date().toISOString();
|
|
34
|
+
|
|
35
|
+
const snapshot: MessageSnapshot = {
|
|
36
|
+
id,
|
|
37
|
+
message_id: data.message_id,
|
|
38
|
+
session_id: data.session_id,
|
|
39
|
+
project_id: data.project_id,
|
|
40
|
+
files_snapshot: JSON.stringify(data.files_snapshot),
|
|
41
|
+
project_metadata: data.project_metadata ? JSON.stringify(data.project_metadata) : undefined,
|
|
42
|
+
created_at: now,
|
|
43
|
+
snapshot_type: data.snapshot_type || 'full',
|
|
44
|
+
parent_snapshot_id: data.parent_snapshot_id,
|
|
45
|
+
delta_changes: data.delta_changes ? JSON.stringify(data.delta_changes) : undefined,
|
|
46
|
+
files_changed: data.files_changed || 0,
|
|
47
|
+
insertions: data.insertions || 0,
|
|
48
|
+
deletions: data.deletions || 0,
|
|
49
|
+
is_deleted: 0,
|
|
50
|
+
branch_id: data.branch_id || null,
|
|
51
|
+
tree_hash: data.tree_hash || null
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
db.prepare(`
|
|
55
|
+
INSERT INTO message_snapshots (
|
|
56
|
+
id, message_id, session_id, project_id,
|
|
57
|
+
files_snapshot, project_metadata, created_at,
|
|
58
|
+
snapshot_type, parent_snapshot_id, delta_changes,
|
|
59
|
+
files_changed, insertions, deletions,
|
|
60
|
+
is_deleted, branch_id, tree_hash
|
|
61
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?)
|
|
62
|
+
`).run(
|
|
63
|
+
snapshot.id,
|
|
64
|
+
snapshot.message_id,
|
|
65
|
+
snapshot.session_id,
|
|
66
|
+
snapshot.project_id,
|
|
67
|
+
snapshot.files_snapshot,
|
|
68
|
+
snapshot.project_metadata || null,
|
|
69
|
+
snapshot.created_at,
|
|
70
|
+
snapshot.snapshot_type,
|
|
71
|
+
snapshot.parent_snapshot_id || null,
|
|
72
|
+
snapshot.delta_changes || null,
|
|
73
|
+
snapshot.files_changed,
|
|
74
|
+
snapshot.insertions,
|
|
75
|
+
snapshot.deletions,
|
|
76
|
+
snapshot.branch_id || null,
|
|
77
|
+
snapshot.tree_hash || null
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
return snapshot;
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Get snapshot by ID
|
|
85
|
+
*/
|
|
86
|
+
getById(snapshotId: string): MessageSnapshot | null {
|
|
87
|
+
const db = getDatabase();
|
|
88
|
+
const snapshot = db.prepare(`
|
|
89
|
+
SELECT * FROM message_snapshots WHERE id = ?
|
|
90
|
+
`).get(snapshotId) as MessageSnapshot | null;
|
|
91
|
+
|
|
92
|
+
return snapshot;
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get snapshot by message ID
|
|
97
|
+
*/
|
|
98
|
+
getByMessageId(messageId: string): MessageSnapshot | null {
|
|
99
|
+
const db = getDatabase();
|
|
100
|
+
const snapshot = db.prepare(`
|
|
101
|
+
SELECT * FROM message_snapshots WHERE message_id = ?
|
|
102
|
+
`).get(messageId) as MessageSnapshot | null;
|
|
103
|
+
|
|
104
|
+
return snapshot;
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get all snapshots for a session
|
|
109
|
+
*/
|
|
110
|
+
getBySessionId(sessionId: string): MessageSnapshot[] {
|
|
111
|
+
const db = getDatabase();
|
|
112
|
+
const snapshots = db.prepare(`
|
|
113
|
+
SELECT * FROM message_snapshots
|
|
114
|
+
WHERE session_id = ?
|
|
115
|
+
ORDER BY created_at ASC
|
|
116
|
+
`).all(sessionId) as MessageSnapshot[];
|
|
117
|
+
|
|
118
|
+
return snapshots;
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Get latest snapshot for a project
|
|
123
|
+
*/
|
|
124
|
+
getLatestByProjectId(projectId: string): MessageSnapshot | null {
|
|
125
|
+
const db = getDatabase();
|
|
126
|
+
const snapshot = db.prepare(`
|
|
127
|
+
SELECT * FROM message_snapshots
|
|
128
|
+
WHERE project_id = ?
|
|
129
|
+
ORDER BY created_at DESC
|
|
130
|
+
LIMIT 1
|
|
131
|
+
`).get(projectId) as MessageSnapshot | null;
|
|
132
|
+
|
|
133
|
+
return snapshot;
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Delete snapshots after a certain message in a session
|
|
138
|
+
* Used when restoring to a previous state (hard delete - deprecated)
|
|
139
|
+
*/
|
|
140
|
+
deleteAfterMessage(sessionId: string, messageId: string, messageTimestamp: string): void {
|
|
141
|
+
const db = getDatabase();
|
|
142
|
+
|
|
143
|
+
// Delete snapshots created at and after this message
|
|
144
|
+
db.prepare(`
|
|
145
|
+
DELETE FROM message_snapshots
|
|
146
|
+
WHERE session_id = ?
|
|
147
|
+
AND created_at >= ?
|
|
148
|
+
`).run(sessionId, messageTimestamp);
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Soft delete snapshots after a certain checkpoint message (for undo with branch support)
|
|
153
|
+
* Deletes snapshots from next user message onward, preserving checkpoint conversation snapshots
|
|
154
|
+
*/
|
|
155
|
+
softDeleteAfterMessage(sessionId: string, checkpointTimestamp: string, branchId: string): void {
|
|
156
|
+
const db = getDatabase();
|
|
157
|
+
|
|
158
|
+
// Get snapshots with their associated messages to determine type
|
|
159
|
+
const allSnapshots = db.prepare(`
|
|
160
|
+
SELECT ms.id, ms.created_at, ms.message_id, m.sdk_message
|
|
161
|
+
FROM message_snapshots ms
|
|
162
|
+
JOIN messages m ON ms.message_id = m.id
|
|
163
|
+
WHERE ms.session_id = ?
|
|
164
|
+
ORDER BY ms.created_at ASC
|
|
165
|
+
`).all(sessionId) as { id: string; created_at: string; message_id: string; sdk_message: string }[];
|
|
166
|
+
|
|
167
|
+
// Find the checkpoint snapshot index
|
|
168
|
+
const checkpointIndex = allSnapshots.findIndex(snap => snap.created_at === checkpointTimestamp);
|
|
169
|
+
|
|
170
|
+
if (checkpointIndex === -1) {
|
|
171
|
+
debug.warn('database', `Checkpoint snapshot with timestamp ${checkpointTimestamp} not found`);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Find next USER message snapshot after checkpoint
|
|
176
|
+
let deleteFromIndex = -1;
|
|
177
|
+
for (let i = checkpointIndex + 1; i < allSnapshots.length; i++) {
|
|
178
|
+
const sdkMessage = JSON.parse(allSnapshots[i].sdk_message);
|
|
179
|
+
if (sdkMessage.type === 'user') {
|
|
180
|
+
deleteFromIndex = i;
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// If no user message snapshot found after checkpoint, nothing to delete
|
|
186
|
+
if (deleteFromIndex === -1) {
|
|
187
|
+
debug.log('database', 'No user message snapshots to soft delete after checkpoint');
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Get IDs of snapshots from next user message onward
|
|
192
|
+
const snapshotsToDelete = allSnapshots
|
|
193
|
+
.slice(deleteFromIndex)
|
|
194
|
+
.map(snap => snap.id);
|
|
195
|
+
|
|
196
|
+
if (snapshotsToDelete.length === 0) {
|
|
197
|
+
debug.log('database', 'No snapshots to soft delete after checkpoint');
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Soft delete snapshots
|
|
202
|
+
const placeholders = snapshotsToDelete.map(() => '?').join(',');
|
|
203
|
+
db.prepare(`
|
|
204
|
+
UPDATE message_snapshots
|
|
205
|
+
SET is_deleted = 1, branch_id = ?
|
|
206
|
+
WHERE id IN (${placeholders}) AND (is_deleted IS NULL OR is_deleted = 0)
|
|
207
|
+
`).run(branchId, ...snapshotsToDelete);
|
|
208
|
+
|
|
209
|
+
debug.log('database', `Soft deleted ${snapshotsToDelete.length} snapshots from next user message after checkpoint`);
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Restore snapshots from a specific branch
|
|
214
|
+
*/
|
|
215
|
+
restoreBranchSnapshots(sessionId: string, branchId: string): void {
|
|
216
|
+
const db = getDatabase();
|
|
217
|
+
|
|
218
|
+
// Mark all current active snapshots as deleted
|
|
219
|
+
db.prepare(`
|
|
220
|
+
UPDATE message_snapshots
|
|
221
|
+
SET is_deleted = 1
|
|
222
|
+
WHERE session_id = ? AND (is_deleted IS NULL OR is_deleted = 0)
|
|
223
|
+
`).run(sessionId);
|
|
224
|
+
|
|
225
|
+
// Restore snapshots from target branch
|
|
226
|
+
db.prepare(`
|
|
227
|
+
UPDATE message_snapshots
|
|
228
|
+
SET is_deleted = 0
|
|
229
|
+
WHERE session_id = ? AND branch_id = ?
|
|
230
|
+
`).run(sessionId, branchId);
|
|
231
|
+
|
|
232
|
+
// Restore snapshots on main branch up to branching point
|
|
233
|
+
const firstBranchSnapshot = db.prepare(`
|
|
234
|
+
SELECT MIN(created_at) as min_timestamp
|
|
235
|
+
FROM message_snapshots
|
|
236
|
+
WHERE session_id = ? AND branch_id = ?
|
|
237
|
+
`).get(sessionId, branchId) as { min_timestamp: string } | undefined;
|
|
238
|
+
|
|
239
|
+
if (firstBranchSnapshot?.min_timestamp) {
|
|
240
|
+
db.prepare(`
|
|
241
|
+
UPDATE message_snapshots
|
|
242
|
+
SET is_deleted = 0
|
|
243
|
+
WHERE session_id = ? AND (branch_id IS NULL OR branch_id = '') AND created_at < ?
|
|
244
|
+
`).run(sessionId, firstBranchSnapshot.min_timestamp);
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Create session relationship
|
|
250
|
+
*/
|
|
251
|
+
createRelationship(data: {
|
|
252
|
+
parent_session_id: string;
|
|
253
|
+
child_session_id: string;
|
|
254
|
+
branched_from_message_id?: string;
|
|
255
|
+
}): SessionRelationship {
|
|
256
|
+
const db = getDatabase();
|
|
257
|
+
const id = `rel_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
258
|
+
const now = new Date().toISOString();
|
|
259
|
+
|
|
260
|
+
const relationship: SessionRelationship = {
|
|
261
|
+
id,
|
|
262
|
+
parent_session_id: data.parent_session_id,
|
|
263
|
+
child_session_id: data.child_session_id,
|
|
264
|
+
branched_from_message_id: data.branched_from_message_id,
|
|
265
|
+
created_at: now
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
db.prepare(`
|
|
269
|
+
INSERT INTO session_relationships (
|
|
270
|
+
id, parent_session_id, child_session_id,
|
|
271
|
+
branched_from_message_id, created_at
|
|
272
|
+
) VALUES (?, ?, ?, ?, ?)
|
|
273
|
+
`).run(
|
|
274
|
+
relationship.id,
|
|
275
|
+
relationship.parent_session_id,
|
|
276
|
+
relationship.child_session_id,
|
|
277
|
+
relationship.branched_from_message_id || null,
|
|
278
|
+
relationship.created_at
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
return relationship;
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Get relationship by child session ID
|
|
286
|
+
*/
|
|
287
|
+
getRelationshipByChildId(childSessionId: string): SessionRelationship | null {
|
|
288
|
+
const db = getDatabase();
|
|
289
|
+
const relationship = db.prepare(`
|
|
290
|
+
SELECT * FROM session_relationships WHERE child_session_id = ?
|
|
291
|
+
`).get(childSessionId) as SessionRelationship | null;
|
|
292
|
+
|
|
293
|
+
return relationship;
|
|
294
|
+
},
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Get all child sessions of a parent
|
|
298
|
+
*/
|
|
299
|
+
getChildSessions(parentSessionId: string): SessionRelationship[] {
|
|
300
|
+
const db = getDatabase();
|
|
301
|
+
const relationships = db.prepare(`
|
|
302
|
+
SELECT * FROM session_relationships
|
|
303
|
+
WHERE parent_session_id = ?
|
|
304
|
+
ORDER BY created_at ASC
|
|
305
|
+
`).all(parentSessionId) as SessionRelationship[];
|
|
306
|
+
|
|
307
|
+
return relationships;
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Get complete session tree for a project
|
|
312
|
+
* Returns all relationships for building a timeline
|
|
313
|
+
*/
|
|
314
|
+
getSessionTree(projectId: string): SessionRelationship[] {
|
|
315
|
+
const db = getDatabase();
|
|
316
|
+
const relationships = db.prepare(`
|
|
317
|
+
SELECT sr.*
|
|
318
|
+
FROM session_relationships sr
|
|
319
|
+
INNER JOIN chat_sessions cs ON sr.parent_session_id = cs.id
|
|
320
|
+
WHERE cs.project_id = ?
|
|
321
|
+
ORDER BY sr.created_at ASC
|
|
322
|
+
`).all(projectId) as SessionRelationship[];
|
|
323
|
+
|
|
324
|
+
return relationships;
|
|
325
|
+
}
|
|
326
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { getDatabase } from '../index';
|
|
2
|
+
import type { DatabaseMessage } from '$shared/types/database/schema';
|
|
3
|
+
|
|
4
|
+
import { debug } from '$shared/utils/logger';
|
|
5
|
+
export const dbUtils = {
|
|
6
|
+
// Get dashboard statistics
|
|
7
|
+
getStats(): {
|
|
8
|
+
totalProjects: number;
|
|
9
|
+
totalSessions: number;
|
|
10
|
+
totalMessages: number;
|
|
11
|
+
} {
|
|
12
|
+
const db = getDatabase();
|
|
13
|
+
|
|
14
|
+
const totalProjects = (db.prepare('SELECT COUNT(*) as count FROM projects').get() as { count: number }).count;
|
|
15
|
+
const totalSessions = (db.prepare('SELECT COUNT(*) as count FROM chat_sessions').get() as { count: number }).count;
|
|
16
|
+
const totalMessages = (db.prepare('SELECT COUNT(*) as count FROM messages').get() as { count: number }).count;
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
totalProjects,
|
|
20
|
+
totalSessions,
|
|
21
|
+
totalMessages
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
// Search across messages
|
|
26
|
+
searchMessages(query: string, limit: number = 50): (DatabaseMessage & { project_name: string })[] {
|
|
27
|
+
const db = getDatabase();
|
|
28
|
+
return db.prepare(`
|
|
29
|
+
SELECT m.*, p.name as project_name
|
|
30
|
+
FROM messages m
|
|
31
|
+
JOIN chat_sessions cs ON m.session_id = cs.id
|
|
32
|
+
JOIN projects p ON cs.project_id = p.id
|
|
33
|
+
WHERE m.content LIKE ?
|
|
34
|
+
ORDER BY m.timestamp DESC
|
|
35
|
+
LIMIT ?
|
|
36
|
+
`).all(`%${query}%`, limit) as (DatabaseMessage & { project_name: string })[];
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
// Clean up old data
|
|
40
|
+
cleanupOldData(daysOld: number = 30): void {
|
|
41
|
+
const db = getDatabase();
|
|
42
|
+
const cutoffDate = new Date();
|
|
43
|
+
cutoffDate.setDate(cutoffDate.getDate() - daysOld);
|
|
44
|
+
const cutoff = cutoffDate.toISOString();
|
|
45
|
+
|
|
46
|
+
// Delete old ended sessions and their messages
|
|
47
|
+
const oldSessions = db.prepare(`
|
|
48
|
+
SELECT id FROM chat_sessions
|
|
49
|
+
WHERE ended_at IS NOT NULL AND ended_at < ?
|
|
50
|
+
`).all(cutoff) as { id: string }[];
|
|
51
|
+
|
|
52
|
+
for (const session of oldSessions) {
|
|
53
|
+
db.prepare('DELETE FROM messages WHERE session_id = ?').run(session.id);
|
|
54
|
+
db.prepare('DELETE FROM chat_sessions WHERE id = ?').run(session.id);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
debug.log('database', `โ
Cleaned up ${oldSessions.length} old sessions`);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Import all seeders
|
|
2
|
+
import * as settingsSeeder from './settings_seeder';
|
|
3
|
+
|
|
4
|
+
// Export all seeders
|
|
5
|
+
export const seeders = [
|
|
6
|
+
{
|
|
7
|
+
name: 'settings',
|
|
8
|
+
description: settingsSeeder.description,
|
|
9
|
+
seed: settingsSeeder.seed
|
|
10
|
+
}
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
export default seeders;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { DatabaseConnection } from '$shared/types/database/connection';
|
|
2
|
+
|
|
3
|
+
import { debug } from '$shared/utils/logger';
|
|
4
|
+
export const seed = (db: DatabaseConnection): void => {
|
|
5
|
+
debug.log('seeder', '๐ฑ Seeding default settings...');
|
|
6
|
+
|
|
7
|
+
const now = new Date().toISOString();
|
|
8
|
+
|
|
9
|
+
// Insert default settings
|
|
10
|
+
const insertSetting = db.prepare(`
|
|
11
|
+
INSERT INTO settings (key, value, updated_at)
|
|
12
|
+
VALUES (?, ?, ?)
|
|
13
|
+
`);
|
|
14
|
+
|
|
15
|
+
const defaultSettings = [
|
|
16
|
+
{
|
|
17
|
+
key: 'claude_model',
|
|
18
|
+
value: 'sonnet',
|
|
19
|
+
description: 'Default Claude model for chat'
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
key: 'max_tokens',
|
|
23
|
+
value: '4000',
|
|
24
|
+
description: 'Maximum tokens per response'
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
key: 'temperature',
|
|
28
|
+
value: '0.3',
|
|
29
|
+
description: 'AI response creativity (0.0 - 1.0)'
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
key: 'auto_save_sessions',
|
|
33
|
+
value: 'true',
|
|
34
|
+
description: 'Automatically save chat sessions'
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
key: 'file_watch_enabled',
|
|
38
|
+
value: 'true',
|
|
39
|
+
description: 'Enable file system watching'
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: 'theme',
|
|
43
|
+
value: 'system',
|
|
44
|
+
description: 'UI theme preference (light/dark/system)'
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
key: 'session_timeout',
|
|
48
|
+
value: '3600000',
|
|
49
|
+
description: 'Session timeout in milliseconds (1 hour)'
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
key: 'enable_notifications',
|
|
53
|
+
value: 'true',
|
|
54
|
+
description: 'Enable desktop notifications'
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
key: 'auto_cleanup_old_sessions',
|
|
58
|
+
value: 'false',
|
|
59
|
+
description: 'Automatically clean up old chat sessions'
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
key: 'default_project_template',
|
|
63
|
+
value: 'svelte',
|
|
64
|
+
description: 'Default template for new projects'
|
|
65
|
+
}
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
for (const setting of defaultSettings) {
|
|
69
|
+
try {
|
|
70
|
+
insertSetting.run(setting.key, setting.value, now);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
// Skip if setting already exists
|
|
73
|
+
if (error instanceof Error && error.message.includes('UNIQUE constraint failed')) {
|
|
74
|
+
debug.log('seeder', `โน๏ธ Setting ${setting.key} already exists, skipping`);
|
|
75
|
+
} else {
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
debug.log('seeder', `โ
Seeded ${defaultSettings.length} default settings`);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const description = 'Seed default application settings and configuration';
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { join } from 'path';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { Database } from 'bun:sqlite';
|
|
4
|
+
import type { DatabaseConnection } from '$shared/types/database/connection';
|
|
5
|
+
|
|
6
|
+
import { debug } from '$shared/utils/logger';
|
|
7
|
+
export class DatabaseManager {
|
|
8
|
+
private static instance: DatabaseManager | null = null;
|
|
9
|
+
private db: DatabaseConnection | null = null;
|
|
10
|
+
private readonly dbPath: string;
|
|
11
|
+
|
|
12
|
+
private constructor() {
|
|
13
|
+
const clopenDir = join(homedir(), '.clopen');
|
|
14
|
+
this.dbPath = join(clopenDir, 'app.db');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static getInstance(): DatabaseManager {
|
|
18
|
+
if (!DatabaseManager.instance) {
|
|
19
|
+
DatabaseManager.instance = new DatabaseManager();
|
|
20
|
+
}
|
|
21
|
+
return DatabaseManager.instance;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async connect(): Promise<DatabaseConnection> {
|
|
25
|
+
if (this.db) {
|
|
26
|
+
return this.db;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
debug.log('database', '๐ Connecting to database...');
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
// Create ~/.clopen directory if it doesn't exist
|
|
33
|
+
const clopenDir = join(homedir(), '.clopen');
|
|
34
|
+
const dirFile = Bun.file(clopenDir);
|
|
35
|
+
|
|
36
|
+
// Check if directory exists, if not create it
|
|
37
|
+
try {
|
|
38
|
+
await dirFile.stat();
|
|
39
|
+
} catch {
|
|
40
|
+
// Directory doesn't exist, create using Bun.write workaround
|
|
41
|
+
const tempFile = join(clopenDir, '.init');
|
|
42
|
+
await Bun.write(tempFile, '');
|
|
43
|
+
// Remove the temp file
|
|
44
|
+
try {
|
|
45
|
+
const tempFileHandle = Bun.file(tempFile);
|
|
46
|
+
if (await tempFileHandle.exists()) {
|
|
47
|
+
if (process.platform === 'win32') {
|
|
48
|
+
await Bun.spawn(['cmd', '/c', 'del', '/f', '/q', tempFile.replace(/\//g, '\\')], {
|
|
49
|
+
stdout: 'ignore',
|
|
50
|
+
stderr: 'ignore'
|
|
51
|
+
}).exited;
|
|
52
|
+
} else {
|
|
53
|
+
await Bun.spawn(['rm', '-f', tempFile], {
|
|
54
|
+
stdout: 'ignore',
|
|
55
|
+
stderr: 'ignore'
|
|
56
|
+
}).exited;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
// Ignore cleanup errors
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Use Bun's native SQLite exclusively
|
|
65
|
+
this.db = new Database(this.dbPath);
|
|
66
|
+
|
|
67
|
+
// Configure database for optimal performance
|
|
68
|
+
this.configurePragmas();
|
|
69
|
+
|
|
70
|
+
debug.log('database', `โ
Connected to database at: ${this.dbPath}`);
|
|
71
|
+
return this.db;
|
|
72
|
+
|
|
73
|
+
} catch (error) {
|
|
74
|
+
debug.error('database', 'โ Failed to connect to database:', error);
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private configurePragmas(): void {
|
|
80
|
+
if (!this.db) return;
|
|
81
|
+
|
|
82
|
+
debug.log('database', 'โ๏ธ Configuring database pragmas...');
|
|
83
|
+
|
|
84
|
+
// Bun SQLite uses exec for pragmas
|
|
85
|
+
this.db.exec('PRAGMA journal_mode = WAL');
|
|
86
|
+
this.db.exec('PRAGMA synchronous = NORMAL');
|
|
87
|
+
this.db.exec('PRAGMA cache_size = 1000000');
|
|
88
|
+
this.db.exec('PRAGMA temp_store = memory');
|
|
89
|
+
this.db.exec('PRAGMA foreign_keys = ON');
|
|
90
|
+
|
|
91
|
+
debug.log('database', 'โ
Database pragmas configured');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
getConnection(): DatabaseConnection {
|
|
95
|
+
if (!this.db) {
|
|
96
|
+
throw new Error('Database not connected. Call connect() first.');
|
|
97
|
+
}
|
|
98
|
+
return this.db;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
isConnected(): boolean {
|
|
102
|
+
return this.db !== null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
close(): void {
|
|
106
|
+
if (this.db) {
|
|
107
|
+
debug.log('database', '๐ Closing database connection...');
|
|
108
|
+
this.db.close();
|
|
109
|
+
this.db = null;
|
|
110
|
+
debug.log('database', 'โ
Database connection closed');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
getPath(): string {
|
|
115
|
+
return this.dbPath;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async resetDatabase(): Promise<void> {
|
|
119
|
+
debug.log('database', 'โ ๏ธ Resetting database (dropping all tables)...');
|
|
120
|
+
|
|
121
|
+
if (!this.db) {
|
|
122
|
+
throw new Error('Database not connected');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Drop all tables
|
|
126
|
+
const tables = this.db.prepare(`
|
|
127
|
+
SELECT name FROM sqlite_master
|
|
128
|
+
WHERE type='table' AND name NOT LIKE 'sqlite_%'
|
|
129
|
+
`).all() as { name: string }[];
|
|
130
|
+
|
|
131
|
+
for (const table of tables) {
|
|
132
|
+
debug.log('database', `๐๏ธ Dropping table: ${table.name}`);
|
|
133
|
+
this.db.exec(`DROP TABLE IF EXISTS ${table.name}`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
debug.log('database', 'โ
Database reset completed');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async vacuum(): Promise<void> {
|
|
140
|
+
debug.log('database', '๐งน Running database vacuum...');
|
|
141
|
+
|
|
142
|
+
if (!this.db) {
|
|
143
|
+
throw new Error('Database not connected');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
this.db.exec('VACUUM');
|
|
147
|
+
debug.log('database', 'โ
Database vacuum completed');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
getDatabaseInfo(): object {
|
|
151
|
+
if (!this.db) {
|
|
152
|
+
throw new Error('Database not connected');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Helper to get pragma values with Bun SQLite
|
|
156
|
+
const getPragma = (name: string) => {
|
|
157
|
+
const result = this.db!.query(`PRAGMA ${name}`).get() as any;
|
|
158
|
+
return result ? Object.values(result)[0] : null;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
path: this.dbPath,
|
|
163
|
+
journalMode: getPragma('journal_mode'),
|
|
164
|
+
synchronous: getPragma('synchronous'),
|
|
165
|
+
cacheSize: getPragma('cache_size'),
|
|
166
|
+
tempStore: getPragma('temp_store'),
|
|
167
|
+
foreignKeys: getPragma('foreign_keys'),
|
|
168
|
+
userVersion: getPragma('user_version'),
|
|
169
|
+
pageSize: getPragma('page_size'),
|
|
170
|
+
pageCount: getPragma('page_count'),
|
|
171
|
+
freelistCount: getPragma('freelist_count')
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|