@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,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser Action Handlers
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { browserPreviewServiceManager, type BrowserPreviewService } from "$backend/lib/preview";
|
|
6
|
+
import type { BrowserAutonomousAction } from "$backend/lib/preview/browser/types";
|
|
7
|
+
import { browserMcpControl } from "$backend/lib/preview";
|
|
8
|
+
import { projectContextService } from "$backend/lib/mcp/project-context";
|
|
9
|
+
import { getActiveTabSession } from "./browser";
|
|
10
|
+
import { debug } from "$shared/utils/logger";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get BrowserPreviewService for current MCP execution context
|
|
14
|
+
*/
|
|
15
|
+
function getPreviewService(projectId?: string): BrowserPreviewService {
|
|
16
|
+
// 1. Use explicit projectId if provided
|
|
17
|
+
if (projectId) {
|
|
18
|
+
debug.log('mcp', `Using explicit projectId: ${projectId}`);
|
|
19
|
+
return browserPreviewServiceManager.getService(projectId);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// 2. Try to get projectId from current execution context
|
|
23
|
+
const contextProjectId = projectContextService.getCurrentProjectId();
|
|
24
|
+
if (contextProjectId) {
|
|
25
|
+
debug.log('mcp', `Using projectId from context: ${contextProjectId}`);
|
|
26
|
+
return browserPreviewServiceManager.getService(contextProjectId);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 3. Fallback: Get first available project's service
|
|
30
|
+
const activeProjects = browserPreviewServiceManager.getActiveProjects();
|
|
31
|
+
if (activeProjects.length > 0) {
|
|
32
|
+
const fallbackProjectId = activeProjects[0];
|
|
33
|
+
debug.warn('mcp', `⚠️ No project context found, falling back to first active project: ${fallbackProjectId}`);
|
|
34
|
+
return browserPreviewServiceManager.getService(fallbackProjectId);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
throw new Error('No active browser preview service found. Project isolation requires projectId.');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Define action types using discriminated union
|
|
41
|
+
type ClickAction = {
|
|
42
|
+
type: 'click';
|
|
43
|
+
x: number;
|
|
44
|
+
y: number;
|
|
45
|
+
click?: 'left' | 'right' | 'middle';
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
type TypeAction = {
|
|
49
|
+
type: 'type';
|
|
50
|
+
text?: string; // text OR key (mutually exclusive)
|
|
51
|
+
key?: string; // text OR key (mutually exclusive)
|
|
52
|
+
clearFirst?: boolean;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
type MoveAction = {
|
|
56
|
+
type: 'move';
|
|
57
|
+
x: number;
|
|
58
|
+
y: number;
|
|
59
|
+
steps?: number;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
type ScrollAction = {
|
|
63
|
+
type: 'scroll';
|
|
64
|
+
deltaX?: number; // deltaX or deltaY or both
|
|
65
|
+
deltaY?: number; // deltaX or deltaY or both
|
|
66
|
+
smooth?: boolean;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
type WaitAction = {
|
|
70
|
+
type: 'wait';
|
|
71
|
+
delay: number;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
type ExtractDataAction = {
|
|
75
|
+
type: 'extract_data';
|
|
76
|
+
selector: string;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
type BrowserAction =
|
|
80
|
+
| ClickAction
|
|
81
|
+
| TypeAction
|
|
82
|
+
| MoveAction
|
|
83
|
+
| ScrollAction
|
|
84
|
+
| WaitAction
|
|
85
|
+
| ExtractDataAction;
|
|
86
|
+
|
|
87
|
+
export async function actionsHandler(args: {
|
|
88
|
+
actions: BrowserAction[];
|
|
89
|
+
projectId?: string;
|
|
90
|
+
}) {
|
|
91
|
+
try {
|
|
92
|
+
// Get active tab and session
|
|
93
|
+
const { tab } = await getActiveTabSession(args.projectId);
|
|
94
|
+
const sessionId = tab.id;
|
|
95
|
+
|
|
96
|
+
// Get preview service
|
|
97
|
+
const previewService = getPreviewService(args.projectId);
|
|
98
|
+
|
|
99
|
+
// Process actions and apply MCP-optimized defaults
|
|
100
|
+
const processedActions: BrowserAutonomousAction[] = args.actions.map(action => {
|
|
101
|
+
const processed: BrowserAutonomousAction = { ...action } as any;
|
|
102
|
+
|
|
103
|
+
// Apply MCP-optimized default delay for type actions with text (30ms)
|
|
104
|
+
if (action.type === 'type' && 'text' in action && action.text && !('delay' in action)) {
|
|
105
|
+
(processed as any).delay = 30;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Apply clearFirst = true by default for MCP autonomous type actions
|
|
109
|
+
if (action.type === 'type' && 'text' in action && action.text && action.clearFirst === undefined) {
|
|
110
|
+
processed.clearFirst = true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return processed;
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Note: Cursor events are emitted by performAutonomousActions internally
|
|
117
|
+
// with proper delays between each action. No need to emit here.
|
|
118
|
+
const results = await previewService.performAutonomousActions(sessionId, processedActions);
|
|
119
|
+
browserMcpControl.updateLastAction();
|
|
120
|
+
|
|
121
|
+
// Format response with extracted data if any
|
|
122
|
+
const extractedData = results?.filter((r: any) => r.action === 'extract_data') || [];
|
|
123
|
+
|
|
124
|
+
let responseText = `Successfully performed ${args.actions.length} action(s) in sequence.`;
|
|
125
|
+
|
|
126
|
+
if (extractedData.length > 0) {
|
|
127
|
+
responseText += '\n\nExtracted Data:';
|
|
128
|
+
extractedData.forEach((item: any, idx: number) => {
|
|
129
|
+
if (item.error) {
|
|
130
|
+
responseText += `\n [${idx + 1}] Error from '${item.selector}': ${item.error}`;
|
|
131
|
+
} else if (item.data !== null && item.data !== undefined) {
|
|
132
|
+
const attrInfo = item.attribute ? ` (via ${item.attribute})` : '';
|
|
133
|
+
responseText += `\n [${idx + 1}] From '${item.selector}'${attrInfo}: ${item.data}`;
|
|
134
|
+
} else {
|
|
135
|
+
responseText += `\n [${idx + 1}] From '${item.selector}': (element not found or empty)`;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
content: [{
|
|
142
|
+
type: "text" as const,
|
|
143
|
+
text: responseText
|
|
144
|
+
}]
|
|
145
|
+
};
|
|
146
|
+
} catch (error) {
|
|
147
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
148
|
+
return {
|
|
149
|
+
content: [{
|
|
150
|
+
type: "text" as const,
|
|
151
|
+
text: `Actions execution failed: ${errorMessage}`
|
|
152
|
+
}],
|
|
153
|
+
isError: true
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser Management Handlers for MCP Browser Automation
|
|
3
|
+
*
|
|
4
|
+
* Provides tools for MCP to manage browser:
|
|
5
|
+
* - List and switch tabs
|
|
6
|
+
* - Open and close tabs (auto session management)
|
|
7
|
+
* - Navigate active tab
|
|
8
|
+
*
|
|
9
|
+
* Session management is handled internally - no session tools exposed.
|
|
10
|
+
* All operations work on the active tab automatically.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { ws } from "$backend/lib/utils/ws";
|
|
14
|
+
import { debug } from "$shared/utils/logger";
|
|
15
|
+
import { browserMcpControl, browserPreviewServiceManager, type BrowserPreviewService } from "$backend/lib/preview";
|
|
16
|
+
import { projectContextService } from "$backend/lib/mcp/project-context";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get BrowserPreviewService for current MCP execution context
|
|
20
|
+
*
|
|
21
|
+
* Uses projectContextService to determine the correct project based on:
|
|
22
|
+
* 1. Explicit projectId parameter (if provided)
|
|
23
|
+
* 2. Current active chat session context
|
|
24
|
+
* 3. Most recent active stream
|
|
25
|
+
* 4. Fallback to first available project
|
|
26
|
+
*/
|
|
27
|
+
function getPreviewService(projectId?: string): BrowserPreviewService {
|
|
28
|
+
// 1. Use explicit projectId if provided
|
|
29
|
+
if (projectId) {
|
|
30
|
+
debug.log('mcp', `Using explicit projectId: ${projectId}`);
|
|
31
|
+
return browserPreviewServiceManager.getService(projectId);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 2. Try to get projectId from current execution context
|
|
35
|
+
const contextProjectId = projectContextService.getCurrentProjectId();
|
|
36
|
+
if (contextProjectId) {
|
|
37
|
+
debug.log('mcp', `Using projectId from context: ${contextProjectId}`);
|
|
38
|
+
return browserPreviewServiceManager.getService(contextProjectId);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 3. Fallback: Get first available project's service
|
|
42
|
+
const activeProjects = browserPreviewServiceManager.getActiveProjects();
|
|
43
|
+
if (activeProjects.length > 0) {
|
|
44
|
+
const fallbackProjectId = activeProjects[0];
|
|
45
|
+
debug.warn('mcp', `⚠️ No project context found, falling back to first active project: ${fallbackProjectId}`);
|
|
46
|
+
return browserPreviewServiceManager.getService(fallbackProjectId);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
throw new Error('No active browser preview service found. Project isolation requires projectId.');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Tab response types
|
|
53
|
+
interface FrontendTab {
|
|
54
|
+
id: string;
|
|
55
|
+
url: string;
|
|
56
|
+
title: string;
|
|
57
|
+
sessionId: string | null;
|
|
58
|
+
isActive: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
interface TabsListResponse {
|
|
62
|
+
tabs: FrontendTab[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface ActiveTabResponse {
|
|
66
|
+
tab: FrontendTab | null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface SwitchTabResponse {
|
|
70
|
+
success: boolean;
|
|
71
|
+
tab?: FrontendTab;
|
|
72
|
+
error?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
interface OpenTabResponse {
|
|
76
|
+
success: boolean;
|
|
77
|
+
tab?: FrontendTab;
|
|
78
|
+
error?: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface CloseTabResponse {
|
|
82
|
+
success: boolean;
|
|
83
|
+
closedTabId?: string;
|
|
84
|
+
newActiveTab?: FrontendTab;
|
|
85
|
+
error?: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Internal helper: Get active tab
|
|
90
|
+
* Throws error if no active tab found
|
|
91
|
+
* Automatically acquires MCP control for the active tab to ensure UI sync
|
|
92
|
+
*/
|
|
93
|
+
export async function getActiveTabSession(projectId?: string) {
|
|
94
|
+
// Get active tab directly from backend tab manager
|
|
95
|
+
const previewService = getPreviewService(projectId);
|
|
96
|
+
const tab = previewService.getActiveTab();
|
|
97
|
+
|
|
98
|
+
if (!tab) {
|
|
99
|
+
throw new Error("No active tab found. Open a tab first using 'open_tab'.");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Acquire control for active tab (ensures UI sync after idle timeout)
|
|
103
|
+
// This is idempotent - if already controlling this tab, just updates timestamp
|
|
104
|
+
if (!browserMcpControl.isTabControlled(tab.id)) {
|
|
105
|
+
const acquired = browserMcpControl.acquireControl(tab.id);
|
|
106
|
+
if (acquired) {
|
|
107
|
+
debug.log('mcp', `🔄 Auto-acquired control for tab ${tab.id} (resumed after idle)`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// For backward compatibility, return both tab and session-like reference
|
|
112
|
+
// Note: In tab-centric architecture, tab IS the session
|
|
113
|
+
return { tab, session: tab };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* List all open tabs in the browser preview
|
|
118
|
+
*/
|
|
119
|
+
export async function listTabsHandler(projectId?: string) {
|
|
120
|
+
try {
|
|
121
|
+
debug.log('mcp', '📋 MCP requesting tab list');
|
|
122
|
+
debug.log('mcp', `🔍 Input projectId: ${projectId || '(none)'}`);
|
|
123
|
+
|
|
124
|
+
// Get all tabs directly from backend
|
|
125
|
+
const previewService = getPreviewService(projectId);
|
|
126
|
+
debug.log('mcp', `✅ Using service for project: ${previewService.getProjectId()}`);
|
|
127
|
+
|
|
128
|
+
const tabs = previewService.getAllTabs();
|
|
129
|
+
debug.log('mcp', `📊 Found ${tabs.length} tabs`);
|
|
130
|
+
|
|
131
|
+
if (tabs.length === 0) {
|
|
132
|
+
return {
|
|
133
|
+
content: [{
|
|
134
|
+
type: "text" as const,
|
|
135
|
+
text: `No browser tabs are currently open.`
|
|
136
|
+
}]
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const tabList = tabs.map((tab: any, index: number) =>
|
|
141
|
+
`${index + 1}. ${tab.isActive ? '* ' : ' '}[${tab.id}] ${tab.title || 'Untitled'}\n URL: ${tab.url || '(empty)'}`
|
|
142
|
+
).join('\n\n');
|
|
143
|
+
|
|
144
|
+
// Update last action to keep control alive
|
|
145
|
+
browserMcpControl.updateLastAction();
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
content: [{
|
|
149
|
+
type: "text" as const,
|
|
150
|
+
text: `Browser Tabs (${tabs.length}):\n\n${tabList}`
|
|
151
|
+
}]
|
|
152
|
+
};
|
|
153
|
+
} catch (error) {
|
|
154
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
155
|
+
return {
|
|
156
|
+
content: [{
|
|
157
|
+
type: "text" as const,
|
|
158
|
+
text: `Failed to list tabs: ${errorMessage}`
|
|
159
|
+
}],
|
|
160
|
+
isError: true
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Switch to a specific tab by ID
|
|
167
|
+
*/
|
|
168
|
+
export async function switchTabHandler(args: { tabId: string; projectId?: string }) {
|
|
169
|
+
try {
|
|
170
|
+
debug.log('mcp', `🔄 MCP switching to tab: ${args.tabId}`);
|
|
171
|
+
|
|
172
|
+
// Switch tab directly in backend
|
|
173
|
+
const previewService = getPreviewService(args.projectId);
|
|
174
|
+
const success = previewService.switchTab(args.tabId);
|
|
175
|
+
|
|
176
|
+
if (!success) {
|
|
177
|
+
return {
|
|
178
|
+
content: [{
|
|
179
|
+
type: "text" as const,
|
|
180
|
+
text: `Failed to switch tab: Tab '${args.tabId}' not found`
|
|
181
|
+
}],
|
|
182
|
+
isError: true
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Get the tab that was just activated
|
|
187
|
+
const tab = previewService.getTab(args.tabId);
|
|
188
|
+
|
|
189
|
+
// Update MCP control to the new tab
|
|
190
|
+
if (tab) {
|
|
191
|
+
browserMcpControl.releaseControl();
|
|
192
|
+
browserMcpControl.acquireControl(tab.id);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Update last action to keep control alive
|
|
196
|
+
browserMcpControl.updateLastAction();
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
content: [{
|
|
200
|
+
type: "text" as const,
|
|
201
|
+
text: `Switched to tab '${args.tabId}'.\n\nTitle: ${tab?.title || 'Untitled'}\nURL: ${tab?.url || '(empty)'}`
|
|
202
|
+
}]
|
|
203
|
+
};
|
|
204
|
+
} catch (error) {
|
|
205
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
206
|
+
return {
|
|
207
|
+
content: [{
|
|
208
|
+
type: "text" as const,
|
|
209
|
+
text: `Failed to switch tab: ${errorMessage}`
|
|
210
|
+
}],
|
|
211
|
+
isError: true
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Open a new tab with optional URL and viewport configuration
|
|
218
|
+
* Auto-creates browser session and acquires MCP control
|
|
219
|
+
*/
|
|
220
|
+
export async function openNewTabHandler(args: { url?: string; deviceSize?: 'desktop' | 'laptop' | 'tablet' | 'mobile'; rotation?: 'portrait' | 'landscape'; projectId?: string }) {
|
|
221
|
+
try {
|
|
222
|
+
const deviceSize = args.deviceSize || 'laptop';
|
|
223
|
+
|
|
224
|
+
// Determine default rotation based on device size if not specified
|
|
225
|
+
let rotation: 'portrait' | 'landscape';
|
|
226
|
+
if (args.rotation) {
|
|
227
|
+
rotation = args.rotation;
|
|
228
|
+
} else {
|
|
229
|
+
// Desktop and laptop default to landscape
|
|
230
|
+
// Tablet and mobile default to portrait
|
|
231
|
+
rotation = (deviceSize === 'desktop' || deviceSize === 'laptop') ? 'landscape' : 'portrait';
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
debug.log('mcp', `📑 MCP opening new tab with URL: ${args.url || '(empty)'}`);
|
|
235
|
+
debug.log('mcp', `📱 Device: ${deviceSize}, Rotation: ${rotation}`);
|
|
236
|
+
debug.log('mcp', `🔍 Input projectId: ${args.projectId || '(none)'}`);
|
|
237
|
+
|
|
238
|
+
// Create tab directly in backend
|
|
239
|
+
const previewService = getPreviewService(args.projectId);
|
|
240
|
+
debug.log('mcp', `✅ Using service for project: ${previewService.getProjectId()}`);
|
|
241
|
+
|
|
242
|
+
const tab = await previewService.createTab(args.url || undefined, deviceSize, rotation);
|
|
243
|
+
debug.log('mcp', `✅ Tab created: ${tab.id}`);
|
|
244
|
+
|
|
245
|
+
// Auto-acquire control of the new tab
|
|
246
|
+
browserMcpControl.releaseControl();
|
|
247
|
+
browserMcpControl.acquireControl(tab.id);
|
|
248
|
+
|
|
249
|
+
// Update last action to keep control alive
|
|
250
|
+
browserMcpControl.updateLastAction();
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
content: [{
|
|
254
|
+
type: "text" as const,
|
|
255
|
+
text: `New tab opened successfully.\n\nTab ID: ${tab.id}\nTitle: ${tab.title}\nURL: ${tab.url || '(empty)'}\nViewport: ${deviceSize} (${rotation})`
|
|
256
|
+
}]
|
|
257
|
+
};
|
|
258
|
+
} catch (error) {
|
|
259
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
260
|
+
return {
|
|
261
|
+
content: [{
|
|
262
|
+
type: "text" as const,
|
|
263
|
+
text: `Failed to open new tab: ${errorMessage}`
|
|
264
|
+
}],
|
|
265
|
+
isError: true
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Close a specific tab by ID
|
|
272
|
+
* Auto-destroys browser session and releases MCP control
|
|
273
|
+
*/
|
|
274
|
+
export async function closeTabHandler(args: { tabId: string; projectId?: string }) {
|
|
275
|
+
try {
|
|
276
|
+
debug.log('mcp', `❌ MCP closing tab: ${args.tabId}`);
|
|
277
|
+
|
|
278
|
+
// Close tab directly in backend
|
|
279
|
+
const previewService = getPreviewService(args.projectId);
|
|
280
|
+
const result = await previewService.closeTab(args.tabId);
|
|
281
|
+
|
|
282
|
+
if (!result.success) {
|
|
283
|
+
return {
|
|
284
|
+
content: [{
|
|
285
|
+
type: "text" as const,
|
|
286
|
+
text: `Failed to close tab: Tab '${args.tabId}' not found`
|
|
287
|
+
}],
|
|
288
|
+
isError: true
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Release control of closed tab
|
|
293
|
+
browserMcpControl.releaseControl();
|
|
294
|
+
|
|
295
|
+
// If there's a new active tab, acquire control
|
|
296
|
+
if (result.newActiveTabId) {
|
|
297
|
+
const newActiveTab = previewService.getTab(result.newActiveTabId);
|
|
298
|
+
if (newActiveTab) {
|
|
299
|
+
browserMcpControl.acquireControl(newActiveTab.id);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Update last action to keep control alive
|
|
304
|
+
browserMcpControl.updateLastAction();
|
|
305
|
+
|
|
306
|
+
let responseText = `Tab '${args.tabId}' closed successfully.`;
|
|
307
|
+
if (result.newActiveTabId) {
|
|
308
|
+
const newActiveTab = previewService.getTab(result.newActiveTabId);
|
|
309
|
+
if (newActiveTab) {
|
|
310
|
+
responseText += `\n\nNew active tab: ${newActiveTab.id}\nURL: ${newActiveTab.url || '(empty)'}`;
|
|
311
|
+
}
|
|
312
|
+
} else {
|
|
313
|
+
responseText += `\n\nNo remaining tabs.`;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
content: [{
|
|
318
|
+
type: "text" as const,
|
|
319
|
+
text: responseText
|
|
320
|
+
}]
|
|
321
|
+
};
|
|
322
|
+
} catch (error) {
|
|
323
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
324
|
+
return {
|
|
325
|
+
content: [{
|
|
326
|
+
type: "text" as const,
|
|
327
|
+
text: `Failed to close tab: ${errorMessage}`
|
|
328
|
+
}],
|
|
329
|
+
isError: true
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Navigate active tab to a different URL
|
|
336
|
+
* Waits for page load. Session state preserved.
|
|
337
|
+
*/
|
|
338
|
+
export async function navigateHandler(args: { url: string; projectId?: string }) {
|
|
339
|
+
try {
|
|
340
|
+
// Get active tab session
|
|
341
|
+
const { session } = await getActiveTabSession(args.projectId);
|
|
342
|
+
|
|
343
|
+
// Navigate and wait for page to load
|
|
344
|
+
await session.page.goto(args.url, {
|
|
345
|
+
waitUntil: 'domcontentloaded',
|
|
346
|
+
timeout: 30000
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// Wait a bit for dynamic content to load
|
|
350
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
351
|
+
|
|
352
|
+
const finalUrl = session.page.url();
|
|
353
|
+
browserMcpControl.updateLastAction();
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
content: [{
|
|
357
|
+
type: "text" as const,
|
|
358
|
+
text: `Navigation successful.\n\nFinal URL: ${finalUrl}`
|
|
359
|
+
}]
|
|
360
|
+
};
|
|
361
|
+
} catch (error) {
|
|
362
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
363
|
+
return {
|
|
364
|
+
content: [{
|
|
365
|
+
type: "text" as const,
|
|
366
|
+
text: `Navigation failed: ${errorMessage}`
|
|
367
|
+
}],
|
|
368
|
+
isError: true
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Change viewport settings (device size and rotation) for active tab
|
|
375
|
+
*/
|
|
376
|
+
export async function setViewportHandler(args: { deviceSize?: 'desktop' | 'laptop' | 'tablet' | 'mobile'; rotation?: 'portrait' | 'landscape'; projectId?: string }) {
|
|
377
|
+
try {
|
|
378
|
+
// Get active tab
|
|
379
|
+
const { tab } = await getActiveTabSession(args.projectId);
|
|
380
|
+
|
|
381
|
+
const deviceSize = args.deviceSize || tab.deviceSize;
|
|
382
|
+
const rotation = args.rotation || tab.rotation;
|
|
383
|
+
|
|
384
|
+
debug.log('mcp', `📱 MCP changing viewport for tab ${tab.id}: ${deviceSize} (${rotation})`);
|
|
385
|
+
|
|
386
|
+
// Get preview service and update viewport
|
|
387
|
+
const previewService = getPreviewService(args.projectId);
|
|
388
|
+
const success = await previewService.setViewport(tab.id, deviceSize, rotation);
|
|
389
|
+
|
|
390
|
+
if (!success) {
|
|
391
|
+
return {
|
|
392
|
+
content: [{
|
|
393
|
+
type: "text" as const,
|
|
394
|
+
text: `Failed to change viewport for tab '${tab.id}'`
|
|
395
|
+
}],
|
|
396
|
+
isError: true
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Update last action to keep control alive
|
|
401
|
+
browserMcpControl.updateLastAction();
|
|
402
|
+
|
|
403
|
+
return {
|
|
404
|
+
content: [{
|
|
405
|
+
type: "text" as const,
|
|
406
|
+
text: `Viewport changed successfully.\n\nTab ID: ${tab.id}\nDevice: ${deviceSize}\nRotation: ${rotation}`
|
|
407
|
+
}]
|
|
408
|
+
};
|
|
409
|
+
} catch (error) {
|
|
410
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
411
|
+
return {
|
|
412
|
+
content: [{
|
|
413
|
+
type: "text" as const,
|
|
414
|
+
text: `Failed to change viewport: ${errorMessage}`
|
|
415
|
+
}],
|
|
416
|
+
isError: true
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
}
|