@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,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Custom Tools Configuration & Registry
|
|
3
|
+
*
|
|
4
|
+
* This file combines server registry and configuration in one place
|
|
5
|
+
* to avoid duplication and make it easier to add new servers.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { McpSdkServerConfigWithInstance, McpServerConfig } from "@anthropic-ai/claude-agent-sdk";
|
|
9
|
+
import type { McpLocalConfig } from '@opencode-ai/sdk';
|
|
10
|
+
import type { ServerConfig, ParsedMcpToolName, ServerName } from './types';
|
|
11
|
+
import { serverRegistry } from './servers';
|
|
12
|
+
import { debug } from '$shared/utils/logger';
|
|
13
|
+
import { resolve } from 'path';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* User-defined MCP Servers Configuration
|
|
17
|
+
*
|
|
18
|
+
* Define your server configuration here. Only specify `enabled` and `tools`.
|
|
19
|
+
* Server instances are automatically merged from the registry.
|
|
20
|
+
*
|
|
21
|
+
* Type-safe: Server names and tool names are validated at compile time!
|
|
22
|
+
*/
|
|
23
|
+
const mcpServersConfig: Record<ServerName, ServerConfig> = {
|
|
24
|
+
"weather-service": {
|
|
25
|
+
enabled: true,
|
|
26
|
+
tools: [
|
|
27
|
+
"get_temperature",
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"browser-automation": {
|
|
31
|
+
enabled: true,
|
|
32
|
+
tools: [
|
|
33
|
+
// Tab Management
|
|
34
|
+
"list_tabs",
|
|
35
|
+
"switch_tab",
|
|
36
|
+
"open_new_tab",
|
|
37
|
+
"close_tab",
|
|
38
|
+
|
|
39
|
+
// Navigation
|
|
40
|
+
"navigate",
|
|
41
|
+
|
|
42
|
+
// Browser Actions
|
|
43
|
+
"actions",
|
|
44
|
+
|
|
45
|
+
// Page Inspection
|
|
46
|
+
"analyze_dom",
|
|
47
|
+
"take_screenshot",
|
|
48
|
+
"get_console_logs",
|
|
49
|
+
"clear_console_logs",
|
|
50
|
+
"execute_console",
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Helper to merge user config with server instances from registry
|
|
57
|
+
*/
|
|
58
|
+
function createServerConfig<T extends Record<ServerName, ServerConfig>>(
|
|
59
|
+
config: T
|
|
60
|
+
): { [K in keyof T]: T[K] & { instance: McpSdkServerConfigWithInstance } } {
|
|
61
|
+
const result = {} as any;
|
|
62
|
+
|
|
63
|
+
for (const [serverName, serverConfig] of Object.entries(config)) {
|
|
64
|
+
result[serverName] = {
|
|
65
|
+
...serverConfig,
|
|
66
|
+
instance: serverRegistry[serverName as ServerName]
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* MCP Servers Configuration with instances
|
|
75
|
+
*
|
|
76
|
+
* This is the final configuration used throughout the application.
|
|
77
|
+
* Automatically merges user config with server instances.
|
|
78
|
+
*/
|
|
79
|
+
export const mcpServers: Record<string, ServerConfig & { instance: McpSdkServerConfigWithInstance }> = createServerConfig(mcpServersConfig);
|
|
80
|
+
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// Server Registry Functions
|
|
83
|
+
// ============================================================================
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get all enabled MCP servers for Claude SDK
|
|
87
|
+
*/
|
|
88
|
+
export function getEnabledMcpServers(): Record<string, McpServerConfig> {
|
|
89
|
+
const enabledServers: Record<string, McpServerConfig> = {};
|
|
90
|
+
|
|
91
|
+
Object.entries(mcpServers).forEach(([serverName, serverConfig]) => {
|
|
92
|
+
if (serverConfig.enabled) {
|
|
93
|
+
enabledServers[serverName] = serverConfig.instance;
|
|
94
|
+
debug.log('mcp', `โ Enabled MCP server: ${serverName}`);
|
|
95
|
+
} else {
|
|
96
|
+
debug.log('mcp', `โ Disabled MCP server: ${serverName}`);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
debug.log('mcp', `Total enabled MCP servers: ${Object.keys(enabledServers).length}`);
|
|
101
|
+
|
|
102
|
+
return enabledServers;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get list of all allowed MCP tool names
|
|
107
|
+
*
|
|
108
|
+
* Tool names follow the format: mcp__{server-name}__{tool-name}
|
|
109
|
+
* Example: "mcp__weather-service__get_temperature"
|
|
110
|
+
*/
|
|
111
|
+
export function getAllowedMcpTools(): string[] {
|
|
112
|
+
const tools: string[] = [];
|
|
113
|
+
|
|
114
|
+
Object.entries(mcpServers).forEach(([serverName, serverConfig]) => {
|
|
115
|
+
if (!serverConfig.enabled) return;
|
|
116
|
+
|
|
117
|
+
serverConfig.tools.forEach((toolName) => {
|
|
118
|
+
const formattedName = `mcp__${serverName}__${toolName}`;
|
|
119
|
+
tools.push(formattedName);
|
|
120
|
+
debug.log('mcp', `โ Allowed MCP tool: ${formattedName}`);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
debug.log('mcp', `Total allowed MCP tools: ${tools.length}`);
|
|
125
|
+
|
|
126
|
+
return tools;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ============================================================================
|
|
130
|
+
// Configuration Helper Functions
|
|
131
|
+
// ============================================================================
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get server configuration by name
|
|
135
|
+
*/
|
|
136
|
+
export function getServerConfig(serverName: string) {
|
|
137
|
+
return mcpServers[serverName];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Check if a tool exists in server configuration
|
|
142
|
+
*/
|
|
143
|
+
export function getToolConfig(serverName: string, toolName: string): boolean {
|
|
144
|
+
const server = getServerConfig(serverName);
|
|
145
|
+
return server?.tools.includes(toolName as any) ?? false;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Check if a server is enabled
|
|
150
|
+
*/
|
|
151
|
+
export function isServerEnabled(serverName: string): boolean {
|
|
152
|
+
return mcpServers[serverName]?.enabled ?? false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Check if a tool is enabled
|
|
157
|
+
*/
|
|
158
|
+
export function isToolEnabled(serverName: string, toolName: string): boolean {
|
|
159
|
+
const server = mcpServers[serverName];
|
|
160
|
+
if (!server?.enabled) return false;
|
|
161
|
+
|
|
162
|
+
return server.tools.includes(toolName as any);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ============================================================================
|
|
166
|
+
// Utility Functions
|
|
167
|
+
// ============================================================================
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Parse MCP tool name into components
|
|
171
|
+
*
|
|
172
|
+
* Format: mcp__{server-name}__{tool-name}
|
|
173
|
+
* Example: "mcp__weather-service__get_temperature"
|
|
174
|
+
*/
|
|
175
|
+
export function parseMcpToolName(fullName: string): ParsedMcpToolName | null {
|
|
176
|
+
if (!fullName.startsWith('mcp__')) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const withoutPrefix = fullName.replace('mcp__', '');
|
|
181
|
+
const parts = withoutPrefix.split('__');
|
|
182
|
+
|
|
183
|
+
if (parts.length !== 2) {
|
|
184
|
+
debug.warn('mcp', `Invalid MCP tool name format: ${fullName}`);
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const [server, tool] = parts;
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
server,
|
|
192
|
+
tool,
|
|
193
|
+
fullName
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Check if a tool name is a custom MCP tool
|
|
199
|
+
*/
|
|
200
|
+
export function isMcpTool(toolName: string): boolean {
|
|
201
|
+
return toolName.startsWith('mcp__');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Get all enabled server names
|
|
206
|
+
*/
|
|
207
|
+
export function getEnabledServerNames(): string[] {
|
|
208
|
+
return Object.entries(mcpServers)
|
|
209
|
+
.filter(([_, config]) => config.enabled)
|
|
210
|
+
.map(([name, _]) => name);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Get all enabled tool names for a specific server
|
|
215
|
+
*/
|
|
216
|
+
export function getEnabledToolsForServer(serverName: string): string[] {
|
|
217
|
+
const serverConfig = mcpServers[serverName];
|
|
218
|
+
if (!serverConfig?.enabled) {
|
|
219
|
+
return [];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return serverConfig.tools.map((toolName) => `mcp__${serverName}__${toolName}`);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Get statistics about MCP servers and tools
|
|
227
|
+
*/
|
|
228
|
+
export function getMcpStats() {
|
|
229
|
+
const enabledServers = getEnabledServerNames();
|
|
230
|
+
const allTools = getAllowedMcpTools();
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
totalServers: Object.keys(mcpServers).length,
|
|
234
|
+
enabledServers: enabledServers.length,
|
|
235
|
+
totalTools: allTools.length,
|
|
236
|
+
serverNames: enabledServers,
|
|
237
|
+
toolNames: allTools
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ============================================================================
|
|
242
|
+
// Open Code Tool Name Resolution (single source of truth)
|
|
243
|
+
// ============================================================================
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Resolve an Open Code tool name to our mcp__server__tool format.
|
|
247
|
+
*
|
|
248
|
+
* Open Code prefixes tool names with the MCP server name:
|
|
249
|
+
* e.g. "clopen-mcp_open_new_tab" โ "mcp__browser-automation__open_new_tab"
|
|
250
|
+
*
|
|
251
|
+
* This function strips the prefix and maps back using the mcpServers
|
|
252
|
+
* registry โ the SAME source that defines which tools exist.
|
|
253
|
+
*
|
|
254
|
+
* Returns null if the tool name is not one of our custom MCP tools.
|
|
255
|
+
*/
|
|
256
|
+
export function resolveOpenCodeToolName(toolName: string): string | null {
|
|
257
|
+
// Already in our format
|
|
258
|
+
if (toolName.startsWith('mcp__')) return toolName;
|
|
259
|
+
|
|
260
|
+
// Strip Open Code MCP server prefix if present
|
|
261
|
+
// Open Code prefixes with the stdio server name: "clopen-mcp_<tool>"
|
|
262
|
+
let rawName = toolName;
|
|
263
|
+
const ocPrefix = 'clopen-mcp_';
|
|
264
|
+
if (rawName.startsWith(ocPrefix)) {
|
|
265
|
+
rawName = rawName.slice(ocPrefix.length);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Look up which server owns this tool
|
|
269
|
+
for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
|
|
270
|
+
if (!serverConfig.enabled) continue;
|
|
271
|
+
if ((serverConfig.tools as readonly string[]).includes(rawName)) {
|
|
272
|
+
return `mcp__${serverName}__${rawName}`;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// ============================================================================
|
|
280
|
+
// Open Code MCP Configuration
|
|
281
|
+
// ============================================================================
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Get MCP configuration for Open Code engine.
|
|
285
|
+
*
|
|
286
|
+
* Open Code expects MCP servers as local (stdio subprocess) or remote (HTTP URL).
|
|
287
|
+
* We provide a single local MCP server that wraps all our custom tools.
|
|
288
|
+
* The server communicates with the main Clopen process via an HTTP bridge
|
|
289
|
+
* for tools that need in-process access (browser-automation).
|
|
290
|
+
*/
|
|
291
|
+
export function getOpenCodeMcpConfig(): Record<string, McpLocalConfig> {
|
|
292
|
+
// Check if any servers are enabled
|
|
293
|
+
const enabledServers = getEnabledServerNames();
|
|
294
|
+
if (enabledServers.length === 0) {
|
|
295
|
+
return {};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Resolve path to the stdio server script
|
|
299
|
+
const stdioServerPath = resolve(import.meta.dir, 'stdio-server.ts');
|
|
300
|
+
const port = process.env.PORT || '9141';
|
|
301
|
+
|
|
302
|
+
debug.log('mcp', `๐ฆ Open Code MCP: stdio server at ${stdioServerPath}`);
|
|
303
|
+
debug.log('mcp', `๐ฆ Open Code MCP: bridge port ${port}`);
|
|
304
|
+
|
|
305
|
+
return {
|
|
306
|
+
'clopen-mcp': {
|
|
307
|
+
type: 'local',
|
|
308
|
+
command: ['bun', 'run', stdioServerPath],
|
|
309
|
+
environment: {
|
|
310
|
+
CLOPEN_PORT: port,
|
|
311
|
+
},
|
|
312
|
+
enabled: true,
|
|
313
|
+
timeout: 10000,
|
|
314
|
+
},
|
|
315
|
+
};
|
|
316
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP (Model Context Protocol) Custom Tools
|
|
3
|
+
*
|
|
4
|
+
* Main export point for the custom MCP tools system.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Type definitions
|
|
8
|
+
export type {
|
|
9
|
+
ParsedMcpToolName,
|
|
10
|
+
McpServerStatus
|
|
11
|
+
} from './types';
|
|
12
|
+
|
|
13
|
+
// Main configuration and all utilities
|
|
14
|
+
export {
|
|
15
|
+
mcpServers,
|
|
16
|
+
getEnabledMcpServers,
|
|
17
|
+
getAllowedMcpTools,
|
|
18
|
+
getServerConfig,
|
|
19
|
+
getToolConfig,
|
|
20
|
+
isServerEnabled,
|
|
21
|
+
isToolEnabled,
|
|
22
|
+
parseMcpToolName,
|
|
23
|
+
isMcpTool,
|
|
24
|
+
getEnabledServerNames,
|
|
25
|
+
getEnabledToolsForServer,
|
|
26
|
+
getMcpStats,
|
|
27
|
+
getOpenCodeMcpConfig,
|
|
28
|
+
resolveOpenCodeToolName
|
|
29
|
+
} from './config';
|
|
30
|
+
|
|
31
|
+
// Server implementations
|
|
32
|
+
export * from './servers';
|
|
33
|
+
|
|
34
|
+
// Project context service for MCP tool handlers
|
|
35
|
+
export { projectContextService } from './project-context';
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Context Service
|
|
3
|
+
*
|
|
4
|
+
* Stores mapping between chat sessions and projectId to provide
|
|
5
|
+
* project context to MCP tool handlers.
|
|
6
|
+
*
|
|
7
|
+
* This is needed because MCP tools are executed within a chat session context,
|
|
8
|
+
* but the Claude Agent SDK doesn't provide a way to pass custom context
|
|
9
|
+
* to tool handlers.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
13
|
+
import { debug } from '$shared/utils/logger';
|
|
14
|
+
|
|
15
|
+
// Execution context for MCP tool handlers
|
|
16
|
+
interface ExecutionContext {
|
|
17
|
+
chatSessionId?: string;
|
|
18
|
+
projectId?: string;
|
|
19
|
+
streamId?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// AsyncLocalStorage for execution context
|
|
23
|
+
const executionContext = new AsyncLocalStorage<ExecutionContext>();
|
|
24
|
+
|
|
25
|
+
class ProjectContextService {
|
|
26
|
+
// Map chat session ID to project ID
|
|
27
|
+
private sessionProjectMap = new Map<string, string>();
|
|
28
|
+
|
|
29
|
+
// Map stream ID to project ID (for additional tracking)
|
|
30
|
+
private streamProjectMap = new Map<string, string>();
|
|
31
|
+
|
|
32
|
+
// Track active streams (streamId -> context)
|
|
33
|
+
private activeStreams = new Map<string, { chatSessionId: string; projectId: string; startedAt: number }>();
|
|
34
|
+
|
|
35
|
+
// Track the most recently active stream (for MCP tool execution context)
|
|
36
|
+
private mostRecentActiveStream: { streamId: string; chatSessionId: string; projectId: string } | null = null;
|
|
37
|
+
|
|
38
|
+
// Track the most recently used projectId (as a last resort fallback)
|
|
39
|
+
private lastUsedProjectId: string | null = null;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Register a chat session with its project ID
|
|
43
|
+
* Should be called when a chat stream starts
|
|
44
|
+
*/
|
|
45
|
+
registerSession(chatSessionId: string, projectId: string): void {
|
|
46
|
+
if (!chatSessionId || !projectId) {
|
|
47
|
+
debug.warn('mcp', `โ ๏ธ Cannot register session: chatSessionId='${chatSessionId}' projectId='${projectId}'`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.sessionProjectMap.set(chatSessionId, projectId);
|
|
52
|
+
this.lastUsedProjectId = projectId;
|
|
53
|
+
|
|
54
|
+
debug.log('mcp', `๐ Registered session: ${chatSessionId} -> project: ${projectId}`);
|
|
55
|
+
debug.log('mcp', `๐ Total sessions registered: ${this.sessionProjectMap.size}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Register a stream ID with its project ID
|
|
60
|
+
* Should be called when a chat stream starts
|
|
61
|
+
*/
|
|
62
|
+
registerStream(streamId: string, projectId: string, chatSessionId?: string): void {
|
|
63
|
+
if (!streamId || !projectId) {
|
|
64
|
+
debug.warn('mcp', `โ ๏ธ Cannot register stream: streamId='${streamId}' projectId='${projectId}'`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this.streamProjectMap.set(streamId, projectId);
|
|
69
|
+
|
|
70
|
+
// Track as active stream
|
|
71
|
+
if (chatSessionId) {
|
|
72
|
+
this.activeStreams.set(streamId, {
|
|
73
|
+
chatSessionId,
|
|
74
|
+
projectId,
|
|
75
|
+
startedAt: Date.now()
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Update most recent active stream
|
|
79
|
+
this.mostRecentActiveStream = { streamId, chatSessionId, projectId };
|
|
80
|
+
|
|
81
|
+
debug.log('mcp', `๐ Registered stream: ${streamId.slice(0, 8)} -> project: ${projectId} (session: ${chatSessionId.slice(0, 8)})`);
|
|
82
|
+
debug.log('mcp', `๐ฏ Most recent active stream set to: ${projectId}`);
|
|
83
|
+
} else {
|
|
84
|
+
debug.log('mcp', `๐ Registered stream: ${streamId.slice(0, 8)} -> project: ${projectId} (no session)`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
debug.log('mcp', `๐ Total active streams: ${this.activeStreams.size}`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get project ID for a chat session
|
|
92
|
+
*/
|
|
93
|
+
getProjectIdForSession(chatSessionId: string): string | null {
|
|
94
|
+
return this.sessionProjectMap.get(chatSessionId) || null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Get project ID for a stream
|
|
99
|
+
*/
|
|
100
|
+
getProjectIdForStream(streamId: string): string | null {
|
|
101
|
+
return this.streamProjectMap.get(streamId) || null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Unregister a session (cleanup)
|
|
106
|
+
*/
|
|
107
|
+
unregisterSession(chatSessionId: string): void {
|
|
108
|
+
this.sessionProjectMap.delete(chatSessionId);
|
|
109
|
+
debug.log('mcp', `๐๏ธ Unregistered session ${chatSessionId}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Unregister a stream (cleanup)
|
|
114
|
+
*/
|
|
115
|
+
unregisterStream(streamId: string): void {
|
|
116
|
+
this.streamProjectMap.delete(streamId);
|
|
117
|
+
this.activeStreams.delete(streamId);
|
|
118
|
+
|
|
119
|
+
// Clear most recent if it was this stream
|
|
120
|
+
if (this.mostRecentActiveStream?.streamId === streamId) {
|
|
121
|
+
// Find another active stream to use as most recent
|
|
122
|
+
const remaining = Array.from(this.activeStreams.entries());
|
|
123
|
+
if (remaining.length > 0) {
|
|
124
|
+
// Get the most recently started stream
|
|
125
|
+
const [latestStreamId, latestContext] = remaining.sort((a, b) => b[1].startedAt - a[1].startedAt)[0];
|
|
126
|
+
this.mostRecentActiveStream = {
|
|
127
|
+
streamId: latestStreamId,
|
|
128
|
+
chatSessionId: latestContext.chatSessionId,
|
|
129
|
+
projectId: latestContext.projectId
|
|
130
|
+
};
|
|
131
|
+
} else {
|
|
132
|
+
this.mostRecentActiveStream = null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Get the last used project ID (fallback)
|
|
139
|
+
* This is used as a last resort when no session context is available
|
|
140
|
+
*/
|
|
141
|
+
getLastUsedProjectId(): string | null {
|
|
142
|
+
return this.lastUsedProjectId;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get all registered sessions (for debugging)
|
|
147
|
+
*/
|
|
148
|
+
getAllSessions(): Array<{ sessionId: string; projectId: string }> {
|
|
149
|
+
return Array.from(this.sessionProjectMap.entries()).map(([sessionId, projectId]) => ({
|
|
150
|
+
sessionId,
|
|
151
|
+
projectId
|
|
152
|
+
}));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Clear all mappings (for testing or cleanup)
|
|
157
|
+
*/
|
|
158
|
+
clear(): void {
|
|
159
|
+
this.sessionProjectMap.clear();
|
|
160
|
+
this.streamProjectMap.clear();
|
|
161
|
+
this.lastUsedProjectId = null;
|
|
162
|
+
debug.log('mcp', '๐งน Cleared all project context mappings');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Get current execution context (from AsyncLocalStorage)
|
|
167
|
+
*/
|
|
168
|
+
getCurrentContext(): ExecutionContext | undefined {
|
|
169
|
+
return executionContext.getStore();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Run callback with execution context
|
|
174
|
+
* This should be called by stream manager when starting MCP tool execution
|
|
175
|
+
*/
|
|
176
|
+
runWithContext<T>(context: ExecutionContext, callback: () => T): T {
|
|
177
|
+
return executionContext.run(context, callback);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Run async callback with execution context
|
|
182
|
+
*/
|
|
183
|
+
async runWithContextAsync<T>(context: ExecutionContext, callback: () => Promise<T>): Promise<T> {
|
|
184
|
+
return executionContext.run(context, callback);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Get project ID from current execution context
|
|
189
|
+
* This is the primary method MCP handlers should use
|
|
190
|
+
*/
|
|
191
|
+
getCurrentProjectId(): string | null {
|
|
192
|
+
const context = this.getCurrentContext();
|
|
193
|
+
|
|
194
|
+
// 1. Try to get from execution context (highest priority)
|
|
195
|
+
if (context?.projectId) {
|
|
196
|
+
debug.log('mcp', `๐ Project ID from execution context: ${context.projectId}`);
|
|
197
|
+
return context.projectId;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// 2. Try to get from session mapping
|
|
201
|
+
if (context?.chatSessionId) {
|
|
202
|
+
const projectId = this.getProjectIdForSession(context.chatSessionId);
|
|
203
|
+
if (projectId) {
|
|
204
|
+
debug.log('mcp', `๐ Project ID from session mapping: ${projectId}`);
|
|
205
|
+
return projectId;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// 3. Try to get from stream mapping
|
|
210
|
+
if (context?.streamId) {
|
|
211
|
+
const projectId = this.getProjectIdForStream(context.streamId);
|
|
212
|
+
if (projectId) {
|
|
213
|
+
debug.log('mcp', `๐ Project ID from stream mapping: ${projectId}`);
|
|
214
|
+
return projectId;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// 4. Try to get from most recent active stream
|
|
219
|
+
if (this.mostRecentActiveStream) {
|
|
220
|
+
debug.log('mcp', `๐ Project ID from most recent active stream: ${this.mostRecentActiveStream.projectId}`);
|
|
221
|
+
return this.mostRecentActiveStream.projectId;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// 5. Fallback to last used project ID
|
|
225
|
+
const fallback = this.getLastUsedProjectId();
|
|
226
|
+
if (fallback) {
|
|
227
|
+
debug.log('mcp', `๐ Project ID from fallback: ${fallback}`);
|
|
228
|
+
} else {
|
|
229
|
+
debug.warn('mcp', 'โ ๏ธ No project ID available in any context!');
|
|
230
|
+
}
|
|
231
|
+
return fallback;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Singleton instance
|
|
236
|
+
export const projectContextService = new ProjectContextService();
|