@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,501 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page Inspection Handlers
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { browserPreviewServiceManager, type BrowserPreviewService } from "$backend/lib/preview";
|
|
6
|
+
import { browserMcpControl } from "$backend/lib/preview";
|
|
7
|
+
import { projectContextService } from "$backend/lib/mcp/project-context";
|
|
8
|
+
import { getActiveTabSession } from "./browser";
|
|
9
|
+
import { debug } from "$shared/utils/logger";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get BrowserPreviewService for current MCP execution context
|
|
13
|
+
*/
|
|
14
|
+
function getPreviewService(projectId?: string): BrowserPreviewService {
|
|
15
|
+
// 1. Use explicit projectId if provided
|
|
16
|
+
if (projectId) {
|
|
17
|
+
debug.log('mcp', `Using explicit projectId: ${projectId}`);
|
|
18
|
+
return browserPreviewServiceManager.getService(projectId);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// 2. Try to get projectId from current execution context
|
|
22
|
+
const contextProjectId = projectContextService.getCurrentProjectId();
|
|
23
|
+
if (contextProjectId) {
|
|
24
|
+
debug.log('mcp', `Using projectId from context: ${contextProjectId}`);
|
|
25
|
+
return browserPreviewServiceManager.getService(contextProjectId);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 3. Fallback: Get first available project's service
|
|
29
|
+
const activeProjects = browserPreviewServiceManager.getActiveProjects();
|
|
30
|
+
if (activeProjects.length > 0) {
|
|
31
|
+
const fallbackProjectId = activeProjects[0];
|
|
32
|
+
debug.warn('mcp', `⚠️ No project context found, falling back to first active project: ${fallbackProjectId}`);
|
|
33
|
+
return browserPreviewServiceManager.getService(fallbackProjectId);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
throw new Error('No active browser preview service found. Project isolation requires projectId.');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function getConsoleLogsHandler(args: {
|
|
40
|
+
limit?: number;
|
|
41
|
+
projectId?: string;
|
|
42
|
+
}) {
|
|
43
|
+
try {
|
|
44
|
+
// Get active tab and session
|
|
45
|
+
const { tab } = await getActiveTabSession(args.projectId);
|
|
46
|
+
const sessionId = tab.id;
|
|
47
|
+
|
|
48
|
+
// Get preview service
|
|
49
|
+
const previewService = getPreviewService(args.projectId);
|
|
50
|
+
const logs = previewService.getConsoleLogs(sessionId);
|
|
51
|
+
|
|
52
|
+
// Update last action to keep control alive
|
|
53
|
+
browserMcpControl.updateLastAction();
|
|
54
|
+
|
|
55
|
+
if (logs.length === 0) {
|
|
56
|
+
return {
|
|
57
|
+
content: [{
|
|
58
|
+
type: "text" as const,
|
|
59
|
+
text: "No console logs available."
|
|
60
|
+
}]
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const limit = Math.min(args.limit || 20, 100);
|
|
65
|
+
const limitedLogs = logs.slice(-limit);
|
|
66
|
+
const formattedLogs = limitedLogs.map((log: any) => {
|
|
67
|
+
const timestamp = new Date(log.timestamp).toLocaleTimeString();
|
|
68
|
+
const type = log.type.toUpperCase().padEnd(5);
|
|
69
|
+
return `[${timestamp}] ${type} ${log.text}`;
|
|
70
|
+
}).join('\n');
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
content: [{
|
|
74
|
+
type: "text" as const,
|
|
75
|
+
text: `Console Logs (${limitedLogs.length} of ${logs.length} total):\n\n${formattedLogs}`
|
|
76
|
+
}]
|
|
77
|
+
};
|
|
78
|
+
} catch (error) {
|
|
79
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
80
|
+
return {
|
|
81
|
+
content: [{
|
|
82
|
+
type: "text" as const,
|
|
83
|
+
text: `Failed to get console logs: ${errorMessage}`
|
|
84
|
+
}],
|
|
85
|
+
isError: true
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function clearConsoleLogsHandler(args: { projectId?: string } = {}) {
|
|
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
|
+
const success = previewService.clearConsoleLogs(sessionId);
|
|
99
|
+
|
|
100
|
+
// Update last action to keep control alive
|
|
101
|
+
browserMcpControl.updateLastAction();
|
|
102
|
+
|
|
103
|
+
if (!success) {
|
|
104
|
+
return {
|
|
105
|
+
content: [{
|
|
106
|
+
type: "text" as const,
|
|
107
|
+
text: `Failed to clear console logs.`
|
|
108
|
+
}],
|
|
109
|
+
isError: true
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
content: [{
|
|
115
|
+
type: "text" as const,
|
|
116
|
+
text: "Console logs cleared successfully."
|
|
117
|
+
}]
|
|
118
|
+
};
|
|
119
|
+
} catch (error) {
|
|
120
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
121
|
+
return {
|
|
122
|
+
content: [{
|
|
123
|
+
type: "text" as const,
|
|
124
|
+
text: `Failed to clear console logs: ${errorMessage}`
|
|
125
|
+
}],
|
|
126
|
+
isError: true
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export async function executeConsoleHandler(args: {
|
|
132
|
+
command: string;
|
|
133
|
+
projectId?: string;
|
|
134
|
+
}) {
|
|
135
|
+
try {
|
|
136
|
+
// Get active tab and session
|
|
137
|
+
const { tab } = await getActiveTabSession(args.projectId);
|
|
138
|
+
const sessionId = tab.id;
|
|
139
|
+
|
|
140
|
+
// Get preview service
|
|
141
|
+
const previewService = getPreviewService(args.projectId);
|
|
142
|
+
const result = await previewService.executeConsoleCommand(sessionId, args.command);
|
|
143
|
+
|
|
144
|
+
// Update last action to keep control alive
|
|
145
|
+
browserMcpControl.updateLastAction();
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
content: [{
|
|
149
|
+
type: "text" as const,
|
|
150
|
+
text: `Execution successful.\n\nCommand: ${args.command}\n\nResult:\n${JSON.stringify(result, null, 2)}`
|
|
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: `Console execution failed: ${errorMessage}`
|
|
159
|
+
}],
|
|
160
|
+
isError: true
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export async function analyzeDomHandler(args: {
|
|
166
|
+
include?: ('navigation' | 'structure' | 'content' | 'forms' | 'summary')[];
|
|
167
|
+
} = {}) {
|
|
168
|
+
try {
|
|
169
|
+
// Get active tab and session
|
|
170
|
+
const { session } = await getActiveTabSession();
|
|
171
|
+
|
|
172
|
+
// Execute comprehensive DOM analysis
|
|
173
|
+
const analysis = await session.page.evaluate(() => {
|
|
174
|
+
// Helper: Get visible text with proper spacing
|
|
175
|
+
const getVisibleText = (el: Element, maxLength: number = 500): string => {
|
|
176
|
+
// Helper to check if element is block-level
|
|
177
|
+
const isBlockElement = (elem: Element): boolean => {
|
|
178
|
+
const style = window.getComputedStyle(elem);
|
|
179
|
+
return style.display === 'block' ||
|
|
180
|
+
style.display === 'flex' ||
|
|
181
|
+
style.display === 'grid' ||
|
|
182
|
+
style.display === 'list-item' ||
|
|
183
|
+
style.display === 'table';
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// Helper to check if element is visible
|
|
187
|
+
const isVisible = (elem: Element): boolean => {
|
|
188
|
+
const style = window.getComputedStyle(elem);
|
|
189
|
+
if (style.display === 'none' || style.visibility === 'hidden') {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
const tagName = elem.tagName.toLowerCase();
|
|
193
|
+
return tagName !== 'script' && tagName !== 'style';
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
// Recursively extract text with proper separators
|
|
197
|
+
const extractText = (node: Node): string[] => {
|
|
198
|
+
const parts: string[] = [];
|
|
199
|
+
|
|
200
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
201
|
+
const text = node.textContent?.trim();
|
|
202
|
+
if (text && text.length > 0) {
|
|
203
|
+
parts.push(text);
|
|
204
|
+
}
|
|
205
|
+
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
206
|
+
const elem = node as Element;
|
|
207
|
+
|
|
208
|
+
if (!isVisible(elem)) {
|
|
209
|
+
return parts;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const isBlock = isBlockElement(elem);
|
|
213
|
+
const childParts: string[] = [];
|
|
214
|
+
|
|
215
|
+
// Process all children
|
|
216
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
217
|
+
const childResults = extractText(node.childNodes[i]);
|
|
218
|
+
if (childResults.length > 0) {
|
|
219
|
+
childParts.push(...childResults);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (childParts.length > 0) {
|
|
224
|
+
// Join child parts and add to results
|
|
225
|
+
const joined = childParts.join(' ');
|
|
226
|
+
parts.push(joined);
|
|
227
|
+
|
|
228
|
+
// Add block separator marker if this is a block element
|
|
229
|
+
if (isBlock && node.nextSibling) {
|
|
230
|
+
parts.push('|BLOCK|');
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return parts;
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// Extract all text parts
|
|
239
|
+
const textParts = extractText(el);
|
|
240
|
+
|
|
241
|
+
// Join parts and handle block separators
|
|
242
|
+
let result = textParts.join(' ');
|
|
243
|
+
|
|
244
|
+
// Replace block separator markers with ' || '
|
|
245
|
+
result = result.replace(/\s*\|BLOCK\|\s*/g, ' || ');
|
|
246
|
+
|
|
247
|
+
// Normalize whitespace (collapse multiple spaces)
|
|
248
|
+
result = result.replace(/\s+/g, ' ').trim();
|
|
249
|
+
|
|
250
|
+
// Clean up any remaining separator artifacts
|
|
251
|
+
// result = result.replace(/\|\s+\|/g, '').replace(/^\|\s*|\s*\|$/g, '');
|
|
252
|
+
result = result.replace(/\|\s+\|/g, '').replace(/\|\s+\|/g, '').replace(/^\|\s*|\s*\|$/g, '').replace(/^\|\s*|\s*\|$/g, '');
|
|
253
|
+
|
|
254
|
+
return result.substring(0, maxLength);
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
// Helper: Check if in viewport
|
|
258
|
+
// const inViewport = (el: Element): boolean => {
|
|
259
|
+
// const rect = el.getBoundingClientRect();
|
|
260
|
+
// return rect.top >= 0 && rect.left >= 0 &&
|
|
261
|
+
// rect.bottom <= window.innerHeight && rect.right <= window.innerWidth;
|
|
262
|
+
// };
|
|
263
|
+
|
|
264
|
+
// Summary
|
|
265
|
+
const summary = {
|
|
266
|
+
url: window.location.href,
|
|
267
|
+
title: document.title,
|
|
268
|
+
hasIframes: document.querySelectorAll('iframe').length > 0,
|
|
269
|
+
hasCaptcha: !!(
|
|
270
|
+
// reCAPTCHA
|
|
271
|
+
document.querySelector('iframe[src*="recaptcha"]') ||
|
|
272
|
+
document.querySelector('iframe[title*="recaptcha" i]') ||
|
|
273
|
+
document.querySelector('.g-recaptcha') ||
|
|
274
|
+
document.querySelector('[data-sitekey]') ||
|
|
275
|
+
// hCaptcha
|
|
276
|
+
document.querySelector('iframe[src*="hcaptcha"]') ||
|
|
277
|
+
document.querySelector('.h-captcha') ||
|
|
278
|
+
// Cloudflare
|
|
279
|
+
document.querySelector('.cf-challenge-running') ||
|
|
280
|
+
document.querySelector('#challenge-running') ||
|
|
281
|
+
document.querySelector('div[id*="cf-challenge"]') ||
|
|
282
|
+
// Turnstile
|
|
283
|
+
document.querySelector('iframe[src*="turnstile"]') ||
|
|
284
|
+
document.querySelector('.cf-turnstile') ||
|
|
285
|
+
// FunCaptcha/ArkoseLabs
|
|
286
|
+
document.querySelector('iframe[src*="funcaptcha"]') ||
|
|
287
|
+
document.querySelector('iframe[src*="arkoselabs"]') ||
|
|
288
|
+
// Generic captcha indicators
|
|
289
|
+
document.querySelector('[class*="captcha" i]') ||
|
|
290
|
+
document.querySelector('[id*="captcha" i]') ||
|
|
291
|
+
// Image/text based captchas
|
|
292
|
+
document.querySelector('img[alt*="captcha" i]') ||
|
|
293
|
+
document.querySelector('img[src*="captcha" i]')
|
|
294
|
+
),
|
|
295
|
+
scrollableHeight: Math.max(
|
|
296
|
+
document.body.scrollHeight,
|
|
297
|
+
document.documentElement.scrollHeight
|
|
298
|
+
),
|
|
299
|
+
viewportHeight: window.innerHeight
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
// Forms structure
|
|
303
|
+
const forms: any[] = [];
|
|
304
|
+
document.querySelectorAll('form').forEach((form, formIdx) => {
|
|
305
|
+
const fields: any[] = [];
|
|
306
|
+
|
|
307
|
+
form.querySelectorAll('input, textarea, select').forEach((field) => {
|
|
308
|
+
const tagName = field.tagName.toLowerCase();
|
|
309
|
+
const type = tagName === 'input' ? (field as HTMLInputElement).type : tagName;
|
|
310
|
+
|
|
311
|
+
let label = '';
|
|
312
|
+
const id = field.id;
|
|
313
|
+
if (id) {
|
|
314
|
+
const labelEl = document.querySelector(`label[for="${id}"]`);
|
|
315
|
+
if (labelEl) label = getVisibleText(labelEl);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (!label) {
|
|
319
|
+
label = (field as any).placeholder || (field as any).name || '(no label)';
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
fields.push({
|
|
323
|
+
label,
|
|
324
|
+
type,
|
|
325
|
+
name: (field as any).name || '',
|
|
326
|
+
placeholder: (field as any).placeholder || '',
|
|
327
|
+
required: (field as any).required || false,
|
|
328
|
+
currentValue: (field as any).value || ''
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
forms.push({
|
|
333
|
+
formId: form.id || `form-${formIdx}`,
|
|
334
|
+
action: form.action || '',
|
|
335
|
+
fields
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
// Navigation - collect ALL links (not just nav), then deduplicate
|
|
340
|
+
const navigation = {
|
|
341
|
+
menus: [] as any[],
|
|
342
|
+
links: [] as any[]
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
// Collect all links with href
|
|
346
|
+
const seenHrefs = new Set<string>();
|
|
347
|
+
document.querySelectorAll('a[href]').forEach((link) => {
|
|
348
|
+
const href = (link as HTMLAnchorElement).href;
|
|
349
|
+
const text = getVisibleText(link, 150);
|
|
350
|
+
|
|
351
|
+
// Skip if: empty href, empty text, already seen, or anchor-only link
|
|
352
|
+
if (!href || !text || seenHrefs.has(href) || href.startsWith('#')) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
seenHrefs.add(href);
|
|
357
|
+
navigation.links.push({
|
|
358
|
+
text,
|
|
359
|
+
href
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// Page structure
|
|
364
|
+
const structure = {
|
|
365
|
+
headings: [] as any[],
|
|
366
|
+
sections: [] as any[]
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
// Collect headings
|
|
370
|
+
document.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach((heading) => {
|
|
371
|
+
structure.headings.push({
|
|
372
|
+
level: parseInt(heading.tagName.substring(1)),
|
|
373
|
+
text: getVisibleText(heading),
|
|
374
|
+
id: heading.id || ''
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// Collect sections
|
|
379
|
+
document.querySelectorAll('section, article, main').forEach((section, idx) => {
|
|
380
|
+
const heading = section.querySelector('h1, h2, h3, h4, h5, h6');
|
|
381
|
+
const headingText = heading ? getVisibleText(heading, 200) : `Section ${idx + 1}`;
|
|
382
|
+
const summary = getVisibleText(section, 400);
|
|
383
|
+
|
|
384
|
+
structure.sections.push({
|
|
385
|
+
heading: headingText,
|
|
386
|
+
summary
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// Text content - collect from various element types
|
|
391
|
+
const content = {
|
|
392
|
+
paragraphs: [] as string[]
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
// Collect text from paragraphs, divs, list items, table cells, spans
|
|
396
|
+
const seenTexts = new Set<string>();
|
|
397
|
+
const textSelectors = 'p, div:not(:has(p)):not(:has(div)), li, td, span:not(:has(span))';
|
|
398
|
+
|
|
399
|
+
document.querySelectorAll(textSelectors).forEach((el) => {
|
|
400
|
+
const text = getVisibleText(el, 800);
|
|
401
|
+
|
|
402
|
+
// Skip if: too short, already seen, or likely navigation/UI element
|
|
403
|
+
if (text.length < 10 || seenTexts.has(text)) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Limit to 100 text items to avoid overflow
|
|
408
|
+
if (content.paragraphs.length >= 100) {
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
seenTexts.add(text);
|
|
413
|
+
content.paragraphs.push(text);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
return {
|
|
417
|
+
navigation,
|
|
418
|
+
structure,
|
|
419
|
+
content,
|
|
420
|
+
forms,
|
|
421
|
+
summary
|
|
422
|
+
};
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
// Filter sections if include provided
|
|
426
|
+
const includeSet = args.include ? new Set(args.include) : null;
|
|
427
|
+
let filtered: any = {};
|
|
428
|
+
|
|
429
|
+
if (includeSet) {
|
|
430
|
+
// Only include requested sections (in priority order)
|
|
431
|
+
if (includeSet.has('navigation')) filtered.navigation = analysis.navigation;
|
|
432
|
+
if (includeSet.has('structure')) filtered.structure = analysis.structure;
|
|
433
|
+
if (includeSet.has('content')) filtered.content = analysis.content;
|
|
434
|
+
if (includeSet.has('forms')) filtered.forms = analysis.forms;
|
|
435
|
+
if (includeSet.has('summary')) filtered.summary = analysis.summary;
|
|
436
|
+
} else {
|
|
437
|
+
// Include all sections
|
|
438
|
+
filtered = analysis;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Update last action to keep control alive
|
|
442
|
+
browserMcpControl.updateLastAction();
|
|
443
|
+
|
|
444
|
+
return {
|
|
445
|
+
content: [{
|
|
446
|
+
type: "text" as const,
|
|
447
|
+
text: JSON.stringify(filtered, null, 2)
|
|
448
|
+
}]
|
|
449
|
+
};
|
|
450
|
+
} catch (error) {
|
|
451
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
452
|
+
return {
|
|
453
|
+
content: [{
|
|
454
|
+
type: "text" as const,
|
|
455
|
+
text: `DOM analysis failed: ${errorMessage}`
|
|
456
|
+
}],
|
|
457
|
+
isError: true
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
export async function takeScreenshotHandler() {
|
|
463
|
+
try {
|
|
464
|
+
// Get active tab and session
|
|
465
|
+
const { session } = await getActiveTabSession();
|
|
466
|
+
|
|
467
|
+
// ALWAYS capture viewport only (cost-efficient, fast)
|
|
468
|
+
const screenshot = await session.page.screenshot({
|
|
469
|
+
encoding: 'base64',
|
|
470
|
+
fullPage: false, // viewport only
|
|
471
|
+
type: 'png'
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
// Update last action to keep control alive
|
|
475
|
+
browserMcpControl.updateLastAction();
|
|
476
|
+
|
|
477
|
+
return {
|
|
478
|
+
content: [
|
|
479
|
+
{
|
|
480
|
+
type: "image" as const,
|
|
481
|
+
data: screenshot,
|
|
482
|
+
mimeType: "image/png"
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
type: "text" as const,
|
|
486
|
+
text: `Screenshot captured successfully (viewport only).`
|
|
487
|
+
}
|
|
488
|
+
]
|
|
489
|
+
};
|
|
490
|
+
} catch (error) {
|
|
491
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
492
|
+
|
|
493
|
+
return {
|
|
494
|
+
content: [{
|
|
495
|
+
type: "text" as const,
|
|
496
|
+
text: `Screenshot failed: ${errorMessage}`
|
|
497
|
+
}],
|
|
498
|
+
isError: true
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper to define MCP servers with automatic metadata extraction
|
|
3
|
+
*
|
|
4
|
+
* Stores both the Claude SDK server instance AND raw tool definitions
|
|
5
|
+
* so the same source can be used for Claude Code (in-process) and
|
|
6
|
+
* Open Code (stdio subprocess via @modelcontextprotocol/sdk).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
|
|
10
|
+
import type { z } from "zod";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Infer argument types from Zod schema
|
|
14
|
+
*/
|
|
15
|
+
type InferArgs<TSchema extends Record<string, z.ZodType<any>>> = {
|
|
16
|
+
[K in keyof TSchema]: z.infer<TSchema[K]>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Content types for MCP responses
|
|
21
|
+
*/
|
|
22
|
+
type MCPContent =
|
|
23
|
+
| { type: "text"; text: string }
|
|
24
|
+
| { type: "image"; data: string; mimeType: string };
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Tool handler type - infers args type from schema
|
|
28
|
+
*/
|
|
29
|
+
type ToolHandler<TSchema extends Record<string, z.ZodType<any>> | undefined> =
|
|
30
|
+
TSchema extends Record<string, z.ZodType<any>>
|
|
31
|
+
? (args: InferArgs<TSchema>) => Promise<{ content: Array<MCPContent>; isError?: boolean }>
|
|
32
|
+
: () => Promise<{ content: Array<MCPContent>; isError?: boolean }>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Raw tool definition — schema, description, and handler.
|
|
36
|
+
* Single source of truth used by:
|
|
37
|
+
* - Claude Code: in-process via createSdkMcpServer
|
|
38
|
+
* - Open Code stdio: schema/description for registration, handler via bridge
|
|
39
|
+
* - MCP bridge: handler for in-process execution
|
|
40
|
+
*/
|
|
41
|
+
export interface RawToolDef {
|
|
42
|
+
description: string;
|
|
43
|
+
schema: Record<string, z.ZodType<any>>;
|
|
44
|
+
handler: (args: any) => Promise<{ content: Array<{ type: string; text?: string; data?: string; mimeType?: string }>; isError?: boolean }>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Server instance with metadata
|
|
49
|
+
*/
|
|
50
|
+
interface ServerWithMeta<
|
|
51
|
+
TName extends string,
|
|
52
|
+
TToolNames extends readonly string[]
|
|
53
|
+
> {
|
|
54
|
+
server: ReturnType<typeof createSdkMcpServer>;
|
|
55
|
+
meta: {
|
|
56
|
+
readonly name: TName;
|
|
57
|
+
readonly tools: TToolNames;
|
|
58
|
+
/** Raw tool definitions (schema + description) for reuse by other transports */
|
|
59
|
+
readonly toolDefs: Record<string, RawToolDef>;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Define an MCP server with automatic metadata extraction and full type inference
|
|
65
|
+
*/
|
|
66
|
+
export function defineServer<
|
|
67
|
+
const TConfig extends {
|
|
68
|
+
name: string;
|
|
69
|
+
version: string;
|
|
70
|
+
tools: Record<string, { description: string; schema?: any; handler: any }>;
|
|
71
|
+
}
|
|
72
|
+
>(
|
|
73
|
+
config: TConfig & {
|
|
74
|
+
tools: {
|
|
75
|
+
[K in keyof TConfig['tools']]: TConfig['tools'][K] extends { schema: infer S extends Record<string, z.ZodType<any>> }
|
|
76
|
+
? { description: string; schema: S; handler: ToolHandler<S> }
|
|
77
|
+
: { description: string; handler: ToolHandler<undefined> }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
): ServerWithMeta<TConfig['name'], ReadonlyArray<keyof TConfig['tools'] & string>> {
|
|
81
|
+
// Extract tool names
|
|
82
|
+
const toolNames = Object.keys(config.tools) as Array<keyof TConfig['tools'] & string>;
|
|
83
|
+
|
|
84
|
+
// Build raw tool definitions (engine-agnostic)
|
|
85
|
+
const toolDefs: Record<string, RawToolDef> = {};
|
|
86
|
+
|
|
87
|
+
// Convert tools object to SDK format (array of tools)
|
|
88
|
+
const sdkTools = toolNames.map((toolName) => {
|
|
89
|
+
const toolDef = config.tools[toolName] as any;
|
|
90
|
+
// If schema is not provided, use empty object
|
|
91
|
+
const schema = toolDef.schema || {};
|
|
92
|
+
|
|
93
|
+
// Store raw definition for reuse
|
|
94
|
+
toolDefs[toolName as string] = {
|
|
95
|
+
description: toolDef.description,
|
|
96
|
+
schema,
|
|
97
|
+
handler: toolDef.handler,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
return tool(toolName as string, toolDef.description, schema, toolDef.handler);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Create SDK server
|
|
104
|
+
const server = createSdkMcpServer({
|
|
105
|
+
name: config.name,
|
|
106
|
+
version: config.version,
|
|
107
|
+
tools: sdkTools
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Return server with metadata
|
|
111
|
+
return {
|
|
112
|
+
server,
|
|
113
|
+
meta: {
|
|
114
|
+
name: config.name,
|
|
115
|
+
tools: toolNames as any,
|
|
116
|
+
toolDefs,
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Build server registries from array of servers
|
|
123
|
+
*/
|
|
124
|
+
export function buildServerRegistries<
|
|
125
|
+
T extends readonly ServerWithMeta<string, readonly string[]>[]
|
|
126
|
+
>(servers: T) {
|
|
127
|
+
const metadata = {} as any;
|
|
128
|
+
const registry = {} as any;
|
|
129
|
+
|
|
130
|
+
for (const server of servers) {
|
|
131
|
+
metadata[server.meta.name] = server.meta;
|
|
132
|
+
registry[server.meta.name] = server.server;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
metadata: metadata as {
|
|
137
|
+
[K in T[number]['meta']['name']]: Extract<T[number], { meta: { name: K } }>['meta']
|
|
138
|
+
},
|
|
139
|
+
registry: registry as {
|
|
140
|
+
[K in T[number]['meta']['name']]: Extract<T[number], { meta: { name: K } }>['server']
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Servers Registry
|
|
3
|
+
*
|
|
4
|
+
* This file exports all custom MCP server implementations and provides
|
|
5
|
+
* a type-safe registry for server configuration.
|
|
6
|
+
*
|
|
7
|
+
* To add a new server:
|
|
8
|
+
* 1. Create your server file (e.g., ./my-server.ts) using defineServer
|
|
9
|
+
* 2. Import it and add to the allServers array below
|
|
10
|
+
* 3. Done! Registries are auto-built and type-safe.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import weather from './weather/index';
|
|
14
|
+
import browserAutomation from './browser-automation/index';
|
|
15
|
+
import { buildServerRegistries } from './helper';
|
|
16
|
+
|
|
17
|
+
// Re-export types for stdio server
|
|
18
|
+
export type { RawToolDef } from './helper';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* All MCP Servers
|
|
22
|
+
*
|
|
23
|
+
* Simply import and add new servers to this array.
|
|
24
|
+
* Metadata and registry will be automatically built.
|
|
25
|
+
*/
|
|
26
|
+
const allServers = [
|
|
27
|
+
weather,
|
|
28
|
+
browserAutomation,
|
|
29
|
+
// Add more servers here...
|
|
30
|
+
] as const;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Auto-build registries from server array
|
|
34
|
+
*/
|
|
35
|
+
const { metadata, registry } = buildServerRegistries(allServers);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Server Metadata Registry - Defines available servers and their tools
|
|
39
|
+
*/
|
|
40
|
+
export const serverMetadata = metadata;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Server Instance Registry - Maps server names to SDK instances
|
|
44
|
+
*/
|
|
45
|
+
export const serverRegistry = registry;
|