@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,917 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount, onDestroy } from 'svelte';
|
|
3
|
+
import { browser } from '$frontend/lib/app-environment';
|
|
4
|
+
import Icon from '$frontend/lib/components/common/Icon.svelte';
|
|
5
|
+
import Dialog from '$frontend/lib/components/common/Dialog.svelte';
|
|
6
|
+
import ws from '$frontend/lib/utils/ws';
|
|
7
|
+
import { isDarkMode } from '$frontend/lib/utils/theme';
|
|
8
|
+
import { ENGINES } from '$shared/constants/engines';
|
|
9
|
+
import { claudeAccountsStore, type ClaudeAccountItem as ClaudeCodeAccountItem } from '$frontend/lib/stores/features/claude-accounts.svelte';
|
|
10
|
+
import type { Terminal } from 'xterm';
|
|
11
|
+
import type { FitAddon } from '@xterm/addon-fit';
|
|
12
|
+
|
|
13
|
+
const claudeCodeEngine = ENGINES.find(e => e.type === 'claude-code')!;
|
|
14
|
+
const openCodeEngine = ENGINES.find(e => e.type === 'opencode')!;
|
|
15
|
+
|
|
16
|
+
interface ClaudeCodeStatus {
|
|
17
|
+
installed: boolean;
|
|
18
|
+
version: string | null;
|
|
19
|
+
activeAccount: { id: number; name: string } | null;
|
|
20
|
+
accountsCount: number;
|
|
21
|
+
backendOS: 'windows' | 'macos' | 'linux';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface OpenCodeStatus {
|
|
25
|
+
installed: boolean;
|
|
26
|
+
version: string | null;
|
|
27
|
+
backendOS: 'windows' | 'macos' | 'linux';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let claudeCodeStatus = $state<ClaudeCodeStatus | null>(null);
|
|
31
|
+
let isLoadingClaudeCodeStatus = $state(true);
|
|
32
|
+
const claudeCodeAccounts = $derived(claudeAccountsStore.accounts);
|
|
33
|
+
|
|
34
|
+
// OpenCode state
|
|
35
|
+
let openCodeStatus = $state<OpenCodeStatus | null>(null);
|
|
36
|
+
let isLoadingOpenCodeStatus = $state(true);
|
|
37
|
+
|
|
38
|
+
// Add account flow
|
|
39
|
+
type ClaudeCodeSetupStep = 'idle' | 'loading-url' | 'waiting-code' | 'submitting' | 'success' | 'error';
|
|
40
|
+
let claudeCodeSetupStep = $state<ClaudeCodeSetupStep>('idle');
|
|
41
|
+
let claudeCodeSetupId = $state<string | null>(null);
|
|
42
|
+
let claudeCodeAuthUrl = $state<string | null>(null);
|
|
43
|
+
let claudeCodeAuthCode = $state('');
|
|
44
|
+
let claudeCodeAccountName = $state('');
|
|
45
|
+
let claudeCodeSetupError = $state('');
|
|
46
|
+
|
|
47
|
+
// Install guide - Claude Code
|
|
48
|
+
type ClaudeCodeInstallTab = 'unix' | 'powershell';
|
|
49
|
+
let activeClaudeCodeInstallTab = $state<ClaudeCodeInstallTab>('unix');
|
|
50
|
+
|
|
51
|
+
// Install guide - OpenCode
|
|
52
|
+
type OpenCodeInstallTab = 'unix' | 'bun';
|
|
53
|
+
let activeOpenCodeInstallTab = $state<OpenCodeInstallTab>('unix');
|
|
54
|
+
|
|
55
|
+
// Rename
|
|
56
|
+
let claudeCodeRenamingId = $state<number | null>(null);
|
|
57
|
+
let claudeCodeRenameValue = $state('');
|
|
58
|
+
|
|
59
|
+
// Delete confirmation dialog
|
|
60
|
+
let claudeCodeDeleteDialogOpen = $state(false);
|
|
61
|
+
let claudeCodeDeleteTargetId = $state<number | null>(null);
|
|
62
|
+
|
|
63
|
+
// Copy URL feedback
|
|
64
|
+
let claudeCodeUrlCopied = $state(false);
|
|
65
|
+
let claudeCodeUrlCopiedTimer: ReturnType<typeof setTimeout> | null = null;
|
|
66
|
+
|
|
67
|
+
// Copy command feedback
|
|
68
|
+
let claudeCodeCommandCopied = $state(false);
|
|
69
|
+
let claudeCodeCommandCopiedTimer: ReturnType<typeof setTimeout> | null = null;
|
|
70
|
+
|
|
71
|
+
// Copy command feedback - OpenCode
|
|
72
|
+
let openCodeCommandCopied = $state(false);
|
|
73
|
+
let openCodeCommandCopiedTimer: ReturnType<typeof setTimeout> | null = null;
|
|
74
|
+
|
|
75
|
+
// Debug PTY (xterm.js)
|
|
76
|
+
const showDebug = $state(false);
|
|
77
|
+
let debugTermContainer = $state<HTMLDivElement>();
|
|
78
|
+
let debugTerminal: Terminal | null = null;
|
|
79
|
+
let debugFitAddon: FitAddon | null = null;
|
|
80
|
+
let debugTermReady = $state(false);
|
|
81
|
+
let ptyPhase = $state('');
|
|
82
|
+
let ptyBufferLen = $state(0);
|
|
83
|
+
let hasPtyData = $state(false);
|
|
84
|
+
|
|
85
|
+
// Event listener cleanup functions
|
|
86
|
+
const cleanups: Array<() => void> = [];
|
|
87
|
+
|
|
88
|
+
const claudeCodeInstallCommands: Record<ClaudeCodeInstallTab, { label: string; command: string }> = {
|
|
89
|
+
unix: { label: 'macOS / Linux / WSL', command: 'curl -fsSL https://claude.ai/install.sh | bash' },
|
|
90
|
+
powershell: { label: 'Windows PowerShell', command: 'irm https://claude.ai/install.ps1 | iex' },
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const openCodeInstallCommands: Record<OpenCodeInstallTab, { label: string; command: string }> = {
|
|
94
|
+
unix: { label: 'macOS / Linux / WSL', command: 'curl -fsSL https://opencode.ai/install | bash' },
|
|
95
|
+
bun: { label: 'Bun', command: 'bun add -g opencode-ai' },
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
async function initDebugTerminal() {
|
|
99
|
+
if (!browser || !debugTermContainer || debugTerminal) return;
|
|
100
|
+
|
|
101
|
+
const [{ Terminal }, { FitAddon }] = await Promise.all([
|
|
102
|
+
import('xterm'),
|
|
103
|
+
import('@xterm/addon-fit')
|
|
104
|
+
]);
|
|
105
|
+
|
|
106
|
+
await import('xterm/css/xterm.css');
|
|
107
|
+
|
|
108
|
+
debugTerminal = new Terminal({
|
|
109
|
+
theme: {
|
|
110
|
+
background: '#0f172a',
|
|
111
|
+
foreground: '#e2e8f0',
|
|
112
|
+
cursor: '#22c55e',
|
|
113
|
+
black: '#18181b',
|
|
114
|
+
red: '#ef4444',
|
|
115
|
+
green: '#22c55e',
|
|
116
|
+
yellow: '#eab308',
|
|
117
|
+
blue: '#60a5fa',
|
|
118
|
+
magenta: '#a855f7',
|
|
119
|
+
cyan: '#06b6d4',
|
|
120
|
+
white: '#f4f4f5',
|
|
121
|
+
brightBlack: '#52525b',
|
|
122
|
+
brightRed: '#f87171',
|
|
123
|
+
brightGreen: '#4ade80',
|
|
124
|
+
brightYellow: '#facc15',
|
|
125
|
+
brightBlue: '#60a5fa',
|
|
126
|
+
brightMagenta: '#c084fc',
|
|
127
|
+
brightCyan: '#22d3ee',
|
|
128
|
+
brightWhite: '#ffffff'
|
|
129
|
+
},
|
|
130
|
+
fontSize: 11,
|
|
131
|
+
fontFamily: 'JetBrains Mono, Monaco, "Cascadia Code", Consolas, monospace',
|
|
132
|
+
lineHeight: 1.1,
|
|
133
|
+
cursorBlink: false,
|
|
134
|
+
cursorStyle: 'underline' as const,
|
|
135
|
+
convertEol: true,
|
|
136
|
+
scrollback: 5000,
|
|
137
|
+
disableStdin: true,
|
|
138
|
+
allowTransparency: false,
|
|
139
|
+
cols: 120,
|
|
140
|
+
rows: 20
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
debugFitAddon = new FitAddon();
|
|
144
|
+
debugTerminal.loadAddon(debugFitAddon);
|
|
145
|
+
debugTerminal.open(debugTermContainer);
|
|
146
|
+
debugFitAddon.fit();
|
|
147
|
+
debugTermReady = true;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function disposeDebugTerminal() {
|
|
151
|
+
if (debugTerminal) {
|
|
152
|
+
debugTerminal.dispose();
|
|
153
|
+
debugTerminal = null;
|
|
154
|
+
debugFitAddon = null;
|
|
155
|
+
debugTermReady = false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
onMount(async () => {
|
|
160
|
+
// Listen for setup events from backend
|
|
161
|
+
cleanups.push(
|
|
162
|
+
ws.on('engine:claude-account-setup-url', (data: { setupId: string; authUrl: string }) => {
|
|
163
|
+
claudeCodeSetupId = data.setupId;
|
|
164
|
+
claudeCodeAuthUrl = data.authUrl;
|
|
165
|
+
claudeCodeSetupStep = 'waiting-code';
|
|
166
|
+
}),
|
|
167
|
+
ws.on('engine:claude-account-setup-complete', async (_data: { setupId: string; accountId: number }) => {
|
|
168
|
+
claudeCodeSetupStep = 'success';
|
|
169
|
+
await refreshClaudeCodeAccounts();
|
|
170
|
+
}),
|
|
171
|
+
ws.on('engine:claude-account-setup-error', (data: { setupId: string; message: string }) => {
|
|
172
|
+
claudeCodeSetupError = data.message;
|
|
173
|
+
claudeCodeSetupStep = 'error';
|
|
174
|
+
}),
|
|
175
|
+
ws.on('engine:claude-account-setup-pty-data', (data: { setupId: string; data: string; phase: string; bufferLength: number }) => {
|
|
176
|
+
hasPtyData = true;
|
|
177
|
+
ptyPhase = data.phase;
|
|
178
|
+
ptyBufferLen = data.bufferLength;
|
|
179
|
+
// Write raw data to xterm.js — it handles ANSI natively
|
|
180
|
+
if (debugTerminal) {
|
|
181
|
+
debugTerminal.write(data.data);
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
await Promise.all([refreshClaudeCodeStatus(), refreshOpenCodeStatus()]);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
onDestroy(() => {
|
|
190
|
+
// Cleanup all event listeners
|
|
191
|
+
for (const cleanup of cleanups) cleanup();
|
|
192
|
+
cleanups.length = 0;
|
|
193
|
+
|
|
194
|
+
// Dispose debug terminal
|
|
195
|
+
disposeDebugTerminal();
|
|
196
|
+
|
|
197
|
+
// Cancel any running setup
|
|
198
|
+
if (claudeCodeSetupId && claudeCodeSetupStep !== 'idle' && claudeCodeSetupStep !== 'success' && claudeCodeSetupStep !== 'error') {
|
|
199
|
+
ws.emit('engine:claude-account-setup-cancel', { setupId: claudeCodeSetupId });
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// Init debug terminal when container is available
|
|
204
|
+
$effect(() => {
|
|
205
|
+
if (debugTermContainer && !debugTerminal && showDebug) {
|
|
206
|
+
initDebugTerminal();
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Fit debug terminal on resize
|
|
211
|
+
$effect(() => {
|
|
212
|
+
if (debugTermReady && debugFitAddon && debugTermContainer) {
|
|
213
|
+
const observer = new ResizeObserver(() => {
|
|
214
|
+
debugFitAddon?.fit();
|
|
215
|
+
});
|
|
216
|
+
observer.observe(debugTermContainer);
|
|
217
|
+
return () => observer.disconnect();
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
async function refreshClaudeCodeStatus() {
|
|
222
|
+
isLoadingClaudeCodeStatus = true;
|
|
223
|
+
try {
|
|
224
|
+
claudeCodeStatus = await ws.http('engine:claude-status', {});
|
|
225
|
+
|
|
226
|
+
if (claudeCodeStatus) {
|
|
227
|
+
activeClaudeCodeInstallTab = claudeCodeStatus.backendOS === 'windows' ? 'powershell' : 'unix';
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (claudeCodeStatus?.installed) {
|
|
231
|
+
await refreshClaudeCodeAccounts();
|
|
232
|
+
}
|
|
233
|
+
} catch {
|
|
234
|
+
claudeCodeStatus = null;
|
|
235
|
+
}
|
|
236
|
+
isLoadingClaudeCodeStatus = false;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async function refreshClaudeCodeAccounts() {
|
|
240
|
+
await claudeAccountsStore.refresh();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function startClaudeCodeSetup() {
|
|
244
|
+
claudeCodeSetupStep = 'loading-url';
|
|
245
|
+
claudeCodeSetupError = '';
|
|
246
|
+
claudeCodeAuthCode = '';
|
|
247
|
+
claudeCodeAccountName = '';
|
|
248
|
+
ptyPhase = '';
|
|
249
|
+
ptyBufferLen = 0;
|
|
250
|
+
hasPtyData = false;
|
|
251
|
+
// Clear debug terminal
|
|
252
|
+
if (debugTerminal) {
|
|
253
|
+
debugTerminal.clear();
|
|
254
|
+
debugTerminal.reset();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Fire-and-forget: server will emit 'setup-url' or 'setup-error' back
|
|
258
|
+
ws.emit('engine:claude-account-setup-start', {});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function submitClaudeCodeAuth() {
|
|
262
|
+
if (!claudeCodeSetupId || !claudeCodeAuthCode.trim() || !claudeCodeAccountName.trim()) return;
|
|
263
|
+
|
|
264
|
+
claudeCodeSetupStep = 'submitting';
|
|
265
|
+
claudeCodeSetupError = '';
|
|
266
|
+
|
|
267
|
+
// Fire-and-forget: server will emit 'setup-complete' or 'setup-error' back
|
|
268
|
+
ws.emit('engine:claude-account-setup-submit', {
|
|
269
|
+
setupId: claudeCodeSetupId,
|
|
270
|
+
code: claudeCodeAuthCode.trim(),
|
|
271
|
+
name: claudeCodeAccountName.trim()
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function cancelClaudeCodeSetup() {
|
|
276
|
+
if (claudeCodeSetupId) {
|
|
277
|
+
ws.emit('engine:claude-account-setup-cancel', { setupId: claudeCodeSetupId });
|
|
278
|
+
}
|
|
279
|
+
resetClaudeCodeSetup();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function resetClaudeCodeSetup() {
|
|
283
|
+
claudeCodeSetupStep = 'idle';
|
|
284
|
+
claudeCodeSetupId = null;
|
|
285
|
+
claudeCodeAuthUrl = null;
|
|
286
|
+
claudeCodeAuthCode = '';
|
|
287
|
+
claudeCodeAccountName = '';
|
|
288
|
+
claudeCodeSetupError = '';
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async function switchClaudeCodeAccount(id: number) {
|
|
292
|
+
try {
|
|
293
|
+
await ws.http('engine:claude-accounts-switch', { id });
|
|
294
|
+
await refreshClaudeCodeAccounts();
|
|
295
|
+
} catch {
|
|
296
|
+
// Ignore
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function confirmDeleteClaudeCodeAccount(id: number) {
|
|
301
|
+
claudeCodeDeleteTargetId = id;
|
|
302
|
+
claudeCodeDeleteDialogOpen = true;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
async function deleteClaudeCodeAccount() {
|
|
306
|
+
if (claudeCodeDeleteTargetId === null) return;
|
|
307
|
+
try {
|
|
308
|
+
await ws.http('engine:claude-accounts-delete', { id: claudeCodeDeleteTargetId });
|
|
309
|
+
await refreshClaudeCodeAccounts();
|
|
310
|
+
} catch {
|
|
311
|
+
// Ignore
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function startClaudeCodeRename(account: ClaudeCodeAccountItem) {
|
|
316
|
+
claudeCodeRenamingId = account.id;
|
|
317
|
+
claudeCodeRenameValue = account.name;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
async function submitClaudeCodeRename() {
|
|
321
|
+
if (claudeCodeRenamingId === null || !claudeCodeRenameValue.trim()) return;
|
|
322
|
+
|
|
323
|
+
try {
|
|
324
|
+
await ws.http('engine:claude-accounts-rename', { id: claudeCodeRenamingId, name: claudeCodeRenameValue.trim() });
|
|
325
|
+
claudeCodeRenamingId = null;
|
|
326
|
+
claudeCodeRenameValue = '';
|
|
327
|
+
await refreshClaudeCodeAccounts();
|
|
328
|
+
} catch {
|
|
329
|
+
// Ignore
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function cancelClaudeCodeRename() {
|
|
334
|
+
claudeCodeRenamingId = null;
|
|
335
|
+
claudeCodeRenameValue = '';
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
async function refreshOpenCodeStatus() {
|
|
339
|
+
isLoadingOpenCodeStatus = true;
|
|
340
|
+
try {
|
|
341
|
+
openCodeStatus = await ws.http('engine:opencode-status', {});
|
|
342
|
+
|
|
343
|
+
if (openCodeStatus) {
|
|
344
|
+
// On Windows, default to bun since quick install requires WSL
|
|
345
|
+
activeOpenCodeInstallTab = openCodeStatus.backendOS === 'windows' ? 'bun' : 'unix';
|
|
346
|
+
}
|
|
347
|
+
} catch {
|
|
348
|
+
openCodeStatus = null;
|
|
349
|
+
}
|
|
350
|
+
isLoadingOpenCodeStatus = false;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
async function copyToClipboard(text: string) {
|
|
354
|
+
try {
|
|
355
|
+
await navigator.clipboard.writeText(text);
|
|
356
|
+
} catch {
|
|
357
|
+
// Fallback
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
async function copyClaudeCodeCommand() {
|
|
362
|
+
await copyToClipboard(claudeCodeInstallCommands[activeClaudeCodeInstallTab].command);
|
|
363
|
+
claudeCodeCommandCopied = true;
|
|
364
|
+
if (claudeCodeCommandCopiedTimer) clearTimeout(claudeCodeCommandCopiedTimer);
|
|
365
|
+
claudeCodeCommandCopiedTimer = setTimeout(() => { claudeCodeCommandCopied = false; }, 2000);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async function copyOpenCodeCommand() {
|
|
369
|
+
await copyToClipboard(openCodeInstallCommands[activeOpenCodeInstallTab].command);
|
|
370
|
+
openCodeCommandCopied = true;
|
|
371
|
+
if (openCodeCommandCopiedTimer) clearTimeout(openCodeCommandCopiedTimer);
|
|
372
|
+
openCodeCommandCopiedTimer = setTimeout(() => { openCodeCommandCopied = false; }, 2000);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
async function copyClaudeCodeAuthUrl() {
|
|
376
|
+
if (!claudeCodeAuthUrl) return;
|
|
377
|
+
await copyToClipboard(claudeCodeAuthUrl);
|
|
378
|
+
claudeCodeUrlCopied = true;
|
|
379
|
+
if (claudeCodeUrlCopiedTimer) clearTimeout(claudeCodeUrlCopiedTimer);
|
|
380
|
+
claudeCodeUrlCopiedTimer = setTimeout(() => { claudeCodeUrlCopied = false; }, 2000);
|
|
381
|
+
}
|
|
382
|
+
</script>
|
|
383
|
+
|
|
384
|
+
<div class="space-y-6">
|
|
385
|
+
<!-- Header -->
|
|
386
|
+
<h3 class="text-base font-bold text-slate-900 dark:text-slate-100 mb-1.5">AI Engine</h3>
|
|
387
|
+
<p class="text-sm text-slate-600 dark:text-slate-500 mb-4">
|
|
388
|
+
Manage AI engine installations and accounts
|
|
389
|
+
</p>
|
|
390
|
+
|
|
391
|
+
<!-- Claude Code Card -->
|
|
392
|
+
<div class="rounded-xl border border-slate-200 dark:border-slate-700/50 bg-white dark:bg-slate-800/50 overflow-hidden">
|
|
393
|
+
<!-- Card Header -->
|
|
394
|
+
<div class="flex items-center justify-between px-5 py-4 border-b border-slate-200 dark:border-slate-700/50">
|
|
395
|
+
<div class="flex items-center gap-3">
|
|
396
|
+
<div class="flex items-center justify-center [&>svg]:w-6 [&>svg]:h-6">
|
|
397
|
+
{@html isDarkMode() ? claudeCodeEngine.icon.dark : claudeCodeEngine.icon.light}
|
|
398
|
+
</div>
|
|
399
|
+
<div>
|
|
400
|
+
<h3 class="font-semibold text-slate-900 dark:text-slate-100">{claudeCodeEngine.name}</h3>
|
|
401
|
+
<p class="text-xs text-slate-500 dark:text-slate-400">{claudeCodeEngine.description}</p>
|
|
402
|
+
</div>
|
|
403
|
+
</div>
|
|
404
|
+
|
|
405
|
+
{#if isLoadingClaudeCodeStatus}
|
|
406
|
+
<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-slate-100 dark:bg-slate-700 text-slate-500 dark:text-slate-400">
|
|
407
|
+
<Icon name="lucide:loader" class="w-3 h-3 animate-spin" />
|
|
408
|
+
Checking...
|
|
409
|
+
</span>
|
|
410
|
+
{:else if claudeCodeStatus?.installed}
|
|
411
|
+
<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400">
|
|
412
|
+
<span class="w-1.5 h-1.5 rounded-full bg-green-500"></span>
|
|
413
|
+
Installed
|
|
414
|
+
</span>
|
|
415
|
+
{:else}
|
|
416
|
+
<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-400">
|
|
417
|
+
<span class="w-1.5 h-1.5 rounded-full bg-red-500"></span>
|
|
418
|
+
Not Installed
|
|
419
|
+
</span>
|
|
420
|
+
{/if}
|
|
421
|
+
</div>
|
|
422
|
+
|
|
423
|
+
<!-- Card Body -->
|
|
424
|
+
<div class="px-5 py-4">
|
|
425
|
+
{#if isLoadingClaudeCodeStatus}
|
|
426
|
+
<div class="flex items-center justify-center py-8">
|
|
427
|
+
<Icon name="lucide:loader" class="w-6 h-6 animate-spin text-slate-400" />
|
|
428
|
+
</div>
|
|
429
|
+
{:else if claudeCodeStatus && !claudeCodeStatus.installed}
|
|
430
|
+
<!-- Install Guide -->
|
|
431
|
+
<div class="space-y-4">
|
|
432
|
+
<p class="text-sm text-slate-600 dark:text-slate-300">
|
|
433
|
+
Claude Code is not installed on this system. Install it using one of the methods below:
|
|
434
|
+
</p>
|
|
435
|
+
|
|
436
|
+
<!-- Tab Buttons -->
|
|
437
|
+
<div class="flex flex-wrap gap-1.5">
|
|
438
|
+
{#each Object.entries(claudeCodeInstallCommands) as [key, { label }]}
|
|
439
|
+
<button
|
|
440
|
+
type="button"
|
|
441
|
+
class="px-3 py-1.5 rounded-lg text-xs font-medium transition-colors
|
|
442
|
+
{activeClaudeCodeInstallTab === key
|
|
443
|
+
? 'bg-violet-500/15 text-violet-700 dark:text-violet-300'
|
|
444
|
+
: 'bg-slate-100 dark:bg-slate-700/50 text-slate-600 dark:text-slate-400 hover:bg-slate-200 dark:hover:bg-slate-700'}"
|
|
445
|
+
onclick={() => (activeClaudeCodeInstallTab = key as ClaudeCodeInstallTab)}
|
|
446
|
+
>
|
|
447
|
+
{label}
|
|
448
|
+
</button>
|
|
449
|
+
{/each}
|
|
450
|
+
</div>
|
|
451
|
+
|
|
452
|
+
<!-- Command Block -->
|
|
453
|
+
<div class="relative group">
|
|
454
|
+
<pre class="bg-slate-100 dark:bg-slate-950 text-slate-800 dark:text-slate-200 rounded-lg px-4 py-3 text-sm font-mono overflow-x-auto">{claudeCodeInstallCommands[activeClaudeCodeInstallTab].command}</pre>
|
|
455
|
+
<button
|
|
456
|
+
type="button"
|
|
457
|
+
class="flex absolute top-2 right-2 p-1.5 rounded-md transition-colors {claudeCodeCommandCopied ? 'bg-violet-600/80 text-white' : 'bg-slate-300/80 dark:bg-slate-700/80 text-slate-600 dark:text-slate-300 hover:bg-slate-400/80 dark:hover:bg-slate-600'}"
|
|
458
|
+
onclick={copyClaudeCodeCommand}
|
|
459
|
+
aria-label="Copy command"
|
|
460
|
+
>
|
|
461
|
+
<Icon name={claudeCodeCommandCopied ? 'lucide:check' : 'lucide:copy'} class="w-3.5 h-3.5" />
|
|
462
|
+
</button>
|
|
463
|
+
</div>
|
|
464
|
+
|
|
465
|
+
<!-- Windows Git Bash note -->
|
|
466
|
+
{#if claudeCodeStatus.backendOS === 'windows'}
|
|
467
|
+
<div class="flex gap-2.5 p-3 rounded-lg bg-amber-50 dark:bg-amber-900/15 border border-amber-200 dark:border-amber-700/50">
|
|
468
|
+
<Icon name="lucide:info" class="w-4 h-4 shrink-0 mt-0.5 text-amber-600 dark:text-amber-400" />
|
|
469
|
+
<div class="text-sm text-amber-800 dark:text-amber-300 space-y-1">
|
|
470
|
+
<p class="font-medium">Git Bash is required</p>
|
|
471
|
+
<p class="text-xs text-amber-700 dark:text-amber-400">
|
|
472
|
+
Claude Code requires Git Bash to run on Windows. If you haven't installed it yet, download and install it first:
|
|
473
|
+
</p>
|
|
474
|
+
<a
|
|
475
|
+
href="https://git-scm.com/install/windows"
|
|
476
|
+
target="_blank"
|
|
477
|
+
rel="noopener noreferrer"
|
|
478
|
+
class="inline-flex items-center gap-1 text-xs font-medium text-amber-700 dark:text-amber-300 hover:text-amber-900 dark:hover:text-amber-100 underline underline-offset-2"
|
|
479
|
+
>
|
|
480
|
+
https://git-scm.com/install/windows
|
|
481
|
+
</a>
|
|
482
|
+
</div>
|
|
483
|
+
</div>
|
|
484
|
+
{/if}
|
|
485
|
+
|
|
486
|
+
<!-- More info link -->
|
|
487
|
+
<div class="flex items-center gap-2 text-xs text-slate-500 dark:text-slate-400">
|
|
488
|
+
<Icon name="lucide:book-open" class="w-3.5 h-3.5 shrink-0" />
|
|
489
|
+
<div>
|
|
490
|
+
<span>For complete installation instructions, visit the</span>
|
|
491
|
+
<a
|
|
492
|
+
href="https://code.claude.com/docs/en/quickstart"
|
|
493
|
+
target="_blank"
|
|
494
|
+
rel="noopener noreferrer"
|
|
495
|
+
class="inline-flex items-center gap-1 font-medium text-violet-600 dark:text-violet-400 hover:text-violet-800 dark:hover:text-violet-200 underline underline-offset-2"
|
|
496
|
+
>
|
|
497
|
+
official setup guide
|
|
498
|
+
</a>
|
|
499
|
+
</div>
|
|
500
|
+
</div>
|
|
501
|
+
|
|
502
|
+
<button
|
|
503
|
+
type="button"
|
|
504
|
+
class="flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-lg bg-violet-600 text-white hover:bg-violet-700 transition-colors"
|
|
505
|
+
onclick={refreshClaudeCodeStatus}
|
|
506
|
+
>
|
|
507
|
+
<Icon name="lucide:refresh-cw" class="w-4 h-4" />
|
|
508
|
+
Recheck Installation
|
|
509
|
+
</button>
|
|
510
|
+
</div>
|
|
511
|
+
{:else if claudeCodeStatus}
|
|
512
|
+
<!-- Installed View -->
|
|
513
|
+
<div class="space-y-5">
|
|
514
|
+
<!-- Version -->
|
|
515
|
+
<div class="flex items-center gap-2 text-sm text-slate-600 dark:text-slate-300">
|
|
516
|
+
<Icon name="lucide:tag" class="w-4 h-4 text-slate-400" />
|
|
517
|
+
<span>Version: <span class="font-mono font-medium text-slate-900 dark:text-slate-100">{claudeCodeStatus.version || 'Unknown'}</span></span>
|
|
518
|
+
</div>
|
|
519
|
+
|
|
520
|
+
<!-- Accounts Section -->
|
|
521
|
+
<div class="space-y-3">
|
|
522
|
+
<div class="flex items-center justify-between">
|
|
523
|
+
<h4 class="text-sm font-semibold text-slate-700 dark:text-slate-300">Accounts</h4>
|
|
524
|
+
<span class="text-xs text-slate-500">{claudeCodeAccounts.length} account{claudeCodeAccounts.length !== 1 ? 's' : ''}</span>
|
|
525
|
+
</div>
|
|
526
|
+
|
|
527
|
+
{#if claudeCodeAccounts.length === 0}
|
|
528
|
+
<p class="text-sm text-slate-500 dark:text-slate-400 italic">No accounts configured</p>
|
|
529
|
+
{:else}
|
|
530
|
+
<div class="space-y-2">
|
|
531
|
+
{#each claudeCodeAccounts as account (account.id)}
|
|
532
|
+
<div class="flex items-center justify-between px-3.5 py-2.5 rounded-lg border border-slate-200 dark:border-slate-700/50 bg-slate-50 dark:bg-slate-800/80 {account.isActive ? 'ring-1 ring-violet-500/40' : ''}">
|
|
533
|
+
<div class="w-full flex items-center gap-2.5 min-w-0">
|
|
534
|
+
<Icon name="lucide:user" class="w-4 h-4 shrink-0 text-slate-400" />
|
|
535
|
+
{#if claudeCodeRenamingId === account.id}
|
|
536
|
+
<div class="w-full flex items-center gap-2.5">
|
|
537
|
+
<input
|
|
538
|
+
type="text"
|
|
539
|
+
bind:value={claudeCodeRenameValue}
|
|
540
|
+
class="w-full px-2 py-0.5 text-sm rounded border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-700 text-slate-900 dark:text-slate-100 focus:outline-none focus:ring-1 focus:ring-violet-500"
|
|
541
|
+
/>
|
|
542
|
+
<div class="flex items-center gap-1">
|
|
543
|
+
<button
|
|
544
|
+
type="button"
|
|
545
|
+
class="flex p-1.5 rounded-md text-slate-400 hover:text-green-600 hover:bg-green-50 dark:hover:bg-green-900/20 transition-colors"
|
|
546
|
+
onclick={submitClaudeCodeRename}
|
|
547
|
+
aria-label="Save"
|
|
548
|
+
>
|
|
549
|
+
<Icon name="lucide:check" class="w-3.5 h-3.5" />
|
|
550
|
+
</button>
|
|
551
|
+
<button
|
|
552
|
+
type="button"
|
|
553
|
+
class="flex p-1.5 rounded-md text-slate-400 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors"
|
|
554
|
+
onclick={cancelClaudeCodeRename}
|
|
555
|
+
aria-label="Cancel"
|
|
556
|
+
>
|
|
557
|
+
<Icon name="lucide:x" class="w-3.5 h-3.5" />
|
|
558
|
+
</button>
|
|
559
|
+
</div>
|
|
560
|
+
</div>
|
|
561
|
+
{:else}
|
|
562
|
+
<span class="text-sm font-medium text-slate-900 dark:text-slate-100 truncate">{account.name}</span>
|
|
563
|
+
{#if account.isActive}
|
|
564
|
+
<span class="inline-flex items-center px-2 py-0.5 rounded-full text-3xs font-semibold bg-violet-100 dark:bg-violet-900/30 text-violet-700 dark:text-violet-300">
|
|
565
|
+
Active
|
|
566
|
+
</span>
|
|
567
|
+
{/if}
|
|
568
|
+
{/if}
|
|
569
|
+
</div>
|
|
570
|
+
|
|
571
|
+
{#if claudeCodeRenamingId !== account.id}
|
|
572
|
+
<div class="flex items-center gap-1">
|
|
573
|
+
{#if !account.isActive}
|
|
574
|
+
<button
|
|
575
|
+
type="button"
|
|
576
|
+
class="flex p-1.5 rounded-md text-slate-400 hover:text-violet-600 hover:bg-violet-50 dark:hover:bg-violet-900/20 transition-colors"
|
|
577
|
+
onclick={() => switchClaudeCodeAccount(account.id)}
|
|
578
|
+
title="Switch to this account"
|
|
579
|
+
>
|
|
580
|
+
<Icon name="lucide:arrow-right-left" class="w-3.5 h-3.5" />
|
|
581
|
+
</button>
|
|
582
|
+
{/if}
|
|
583
|
+
<button
|
|
584
|
+
type="button"
|
|
585
|
+
class="flex p-1.5 rounded-md text-slate-400 hover:text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/20 transition-colors"
|
|
586
|
+
onclick={() => startClaudeCodeRename(account)}
|
|
587
|
+
title="Rename"
|
|
588
|
+
>
|
|
589
|
+
<Icon name="lucide:pencil" class="w-3.5 h-3.5" />
|
|
590
|
+
</button>
|
|
591
|
+
<button
|
|
592
|
+
type="button"
|
|
593
|
+
class="flex p-1.5 rounded-md text-slate-400 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors"
|
|
594
|
+
onclick={() => confirmDeleteClaudeCodeAccount(account.id)}
|
|
595
|
+
title="Delete account"
|
|
596
|
+
>
|
|
597
|
+
<Icon name="lucide:trash-2" class="w-3.5 h-3.5" />
|
|
598
|
+
</button>
|
|
599
|
+
</div>
|
|
600
|
+
{/if}
|
|
601
|
+
</div>
|
|
602
|
+
{/each}
|
|
603
|
+
</div>
|
|
604
|
+
{/if}
|
|
605
|
+
|
|
606
|
+
<!-- Add Account Flow -->
|
|
607
|
+
<div class="mt-3">
|
|
608
|
+
{#if claudeCodeSetupStep === 'idle'}
|
|
609
|
+
<button
|
|
610
|
+
type="button"
|
|
611
|
+
class="flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-lg border border-dashed border-slate-300 dark:border-slate-600 text-slate-600 dark:text-slate-400 hover:border-violet-400 hover:text-violet-600 dark:hover:text-violet-400 transition-colors w-full justify-center"
|
|
612
|
+
onclick={startClaudeCodeSetup}
|
|
613
|
+
>
|
|
614
|
+
<Icon name="lucide:plus" class="w-4 h-4" />
|
|
615
|
+
Add Account
|
|
616
|
+
</button>
|
|
617
|
+
{:else if claudeCodeSetupStep === 'loading-url'}
|
|
618
|
+
<div class="p-4 rounded-lg border border-violet-200 dark:border-violet-800/50 bg-violet-50/50 dark:bg-violet-900/10">
|
|
619
|
+
<div class="flex items-center justify-center gap-2 text-sm text-slate-500">
|
|
620
|
+
<Icon name="lucide:loader" class="w-4 h-4 animate-spin" />
|
|
621
|
+
<span>Starting authentication process...</span>
|
|
622
|
+
</div>
|
|
623
|
+
</div>
|
|
624
|
+
{:else if claudeCodeSetupStep === 'waiting-code'}
|
|
625
|
+
<div class="space-y-3 p-4 rounded-lg border border-violet-200 dark:border-violet-800/50 bg-violet-50/50 dark:bg-violet-900/10">
|
|
626
|
+
<!-- Step indicator -->
|
|
627
|
+
<div class="flex items-center gap-2 text-xs font-medium text-violet-600 dark:text-violet-400">
|
|
628
|
+
<Icon name="lucide:key" class="w-3.5 h-3.5" />
|
|
629
|
+
Step 1: Authenticate via browser
|
|
630
|
+
</div>
|
|
631
|
+
|
|
632
|
+
<p class="text-sm text-slate-600 dark:text-slate-400">
|
|
633
|
+
Open the URL below in your browser, complete the sign-in, then copy the authentication code back here.
|
|
634
|
+
</p>
|
|
635
|
+
|
|
636
|
+
<!-- Auth URL -->
|
|
637
|
+
<div>
|
|
638
|
+
<div class="bg-white dark:bg-slate-800 rounded-lg px-3 py-2 text-xs font-mono text-slate-700 dark:text-slate-300 break-all border border-slate-200 dark:border-slate-700">
|
|
639
|
+
{claudeCodeAuthUrl}
|
|
640
|
+
</div>
|
|
641
|
+
<div class="flex gap-2 mt-2">
|
|
642
|
+
<button
|
|
643
|
+
type="button"
|
|
644
|
+
class="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md transition-colors
|
|
645
|
+
{claudeCodeUrlCopied
|
|
646
|
+
? 'bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300'
|
|
647
|
+
: 'bg-slate-100 dark:bg-slate-700 text-slate-700 dark:text-slate-300 hover:bg-slate-200 dark:hover:bg-slate-600'}"
|
|
648
|
+
onclick={copyClaudeCodeAuthUrl}
|
|
649
|
+
>
|
|
650
|
+
{#if claudeCodeUrlCopied}
|
|
651
|
+
<Icon name="lucide:check" class="w-3 h-3" />
|
|
652
|
+
Copied
|
|
653
|
+
{:else}
|
|
654
|
+
<Icon name="lucide:copy" class="w-3 h-3" />
|
|
655
|
+
Copy URL
|
|
656
|
+
{/if}
|
|
657
|
+
</button>
|
|
658
|
+
<a
|
|
659
|
+
href={claudeCodeAuthUrl}
|
|
660
|
+
target="_blank"
|
|
661
|
+
rel="noopener noreferrer"
|
|
662
|
+
class="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md bg-violet-100 dark:bg-violet-900/30 text-violet-700 dark:text-violet-300 hover:bg-violet-200 dark:hover:bg-violet-800/40 transition-colors"
|
|
663
|
+
>
|
|
664
|
+
<Icon name="lucide:external-link" class="w-3 h-3" />
|
|
665
|
+
Open in Browser
|
|
666
|
+
</a>
|
|
667
|
+
</div>
|
|
668
|
+
</div>
|
|
669
|
+
|
|
670
|
+
<!-- Divider -->
|
|
671
|
+
<div class="border-t border-slate-200 dark:border-slate-700/50"></div>
|
|
672
|
+
|
|
673
|
+
<!-- Step 2 -->
|
|
674
|
+
<div class="flex items-center gap-2 text-xs font-medium text-violet-600 dark:text-violet-400">
|
|
675
|
+
<Icon name="lucide:clipboard-paste" class="w-3.5 h-3.5" />
|
|
676
|
+
Step 2: Paste the code and name your account
|
|
677
|
+
</div>
|
|
678
|
+
|
|
679
|
+
<div class="space-y-2">
|
|
680
|
+
<input
|
|
681
|
+
type="text"
|
|
682
|
+
bind:value={claudeCodeAuthCode}
|
|
683
|
+
placeholder="Paste authentication code here"
|
|
684
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-violet-500/40 focus:border-violet-500"
|
|
685
|
+
/>
|
|
686
|
+
<input
|
|
687
|
+
type="text"
|
|
688
|
+
bind:value={claudeCodeAccountName}
|
|
689
|
+
placeholder="Account name (e.g. Personal, Work)"
|
|
690
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-violet-500/40 focus:border-violet-500"
|
|
691
|
+
/>
|
|
692
|
+
</div>
|
|
693
|
+
|
|
694
|
+
<!-- Actions -->
|
|
695
|
+
<div class="flex gap-2">
|
|
696
|
+
<button
|
|
697
|
+
type="button"
|
|
698
|
+
class="flex-1 flex items-center justify-center gap-2 px-4 py-2 text-sm font-medium rounded-lg bg-violet-600 text-white hover:bg-violet-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
|
699
|
+
onclick={submitClaudeCodeAuth}
|
|
700
|
+
disabled={!claudeCodeAuthCode.trim() || !claudeCodeAccountName.trim()}
|
|
701
|
+
>
|
|
702
|
+
<Icon name="lucide:send" class="w-4 h-4" />
|
|
703
|
+
Submit
|
|
704
|
+
</button>
|
|
705
|
+
<button
|
|
706
|
+
type="button"
|
|
707
|
+
class="px-4 py-2 text-sm font-medium rounded-lg border border-slate-300 dark:border-slate-600 text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-700 transition-colors"
|
|
708
|
+
onclick={cancelClaudeCodeSetup}
|
|
709
|
+
>
|
|
710
|
+
Cancel
|
|
711
|
+
</button>
|
|
712
|
+
</div>
|
|
713
|
+
|
|
714
|
+
<p class="text-2xs text-slate-400 dark:text-slate-500">
|
|
715
|
+
A background process is running. It will auto-close in 5 minutes if not completed.
|
|
716
|
+
</p>
|
|
717
|
+
</div>
|
|
718
|
+
{:else if claudeCodeSetupStep === 'submitting'}
|
|
719
|
+
<div class="p-4 rounded-lg border border-violet-200 dark:border-violet-800/50 bg-violet-50/50 dark:bg-violet-900/10">
|
|
720
|
+
<div class="flex items-center justify-center gap-2 text-sm text-slate-500">
|
|
721
|
+
<Icon name="lucide:loader" class="w-4 h-4 animate-spin" />
|
|
722
|
+
<span>Verifying code and retrieving token...</span>
|
|
723
|
+
</div>
|
|
724
|
+
</div>
|
|
725
|
+
{:else if claudeCodeSetupStep === 'success'}
|
|
726
|
+
<div class="flex items-center gap-2 p-3 rounded-lg bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800/50">
|
|
727
|
+
<Icon name="lucide:circle-check" class="w-5 h-5 text-green-600 dark:text-green-400" />
|
|
728
|
+
<span class="text-sm text-green-700 dark:text-green-300">Account added successfully!</span>
|
|
729
|
+
<button
|
|
730
|
+
type="button"
|
|
731
|
+
class="ml-auto text-xs text-green-600 dark:text-green-400 hover:underline"
|
|
732
|
+
onclick={resetClaudeCodeSetup}
|
|
733
|
+
>
|
|
734
|
+
Dismiss
|
|
735
|
+
</button>
|
|
736
|
+
</div>
|
|
737
|
+
{:else if claudeCodeSetupStep === 'error'}
|
|
738
|
+
<div class="space-y-3">
|
|
739
|
+
<div class="flex items-center gap-2 p-3 rounded-lg bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800/50">
|
|
740
|
+
<Icon name="lucide:circle-alert" class="w-5 h-5 shrink-0 text-red-600 dark:text-red-400" />
|
|
741
|
+
<span class="text-sm text-red-700 dark:text-red-300">{claudeCodeSetupError}</span>
|
|
742
|
+
</div>
|
|
743
|
+
<button
|
|
744
|
+
type="button"
|
|
745
|
+
class="flex items-center justify-center gap-2 w-full px-4 py-2 text-sm font-medium rounded-lg border border-slate-300 dark:border-slate-700 text-slate-700 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors"
|
|
746
|
+
onclick={resetClaudeCodeSetup}
|
|
747
|
+
>
|
|
748
|
+
<Icon name="lucide:rotate-ccw" class="w-4 h-4" />
|
|
749
|
+
Try Again
|
|
750
|
+
</button>
|
|
751
|
+
</div>
|
|
752
|
+
{/if}
|
|
753
|
+
</div>
|
|
754
|
+
</div>
|
|
755
|
+
</div>
|
|
756
|
+
{/if}
|
|
757
|
+
</div>
|
|
758
|
+
</div>
|
|
759
|
+
|
|
760
|
+
<!-- Debug PTY Output (xterm.js) -->
|
|
761
|
+
{#if showDebug && (hasPtyData || claudeCodeSetupStep !== 'idle')}
|
|
762
|
+
<div class="rounded-xl border border-amber-300 dark:border-amber-700/50 bg-amber-50 dark:bg-amber-900/10 overflow-hidden">
|
|
763
|
+
<div class="flex items-center justify-between px-4 py-2 border-b border-amber-200 dark:border-amber-700/50">
|
|
764
|
+
<div class="flex items-center gap-2">
|
|
765
|
+
<Icon name="lucide:bug" class="w-4 h-4 text-amber-600" />
|
|
766
|
+
<span class="text-xs font-semibold text-amber-700 dark:text-amber-300">Debug: PTY Output</span>
|
|
767
|
+
<span class="text-3xs font-mono px-1.5 py-0.5 rounded bg-amber-200 dark:bg-amber-800 text-amber-800 dark:text-amber-200">
|
|
768
|
+
phase={ptyPhase} | buf={ptyBufferLen} | step={claudeCodeSetupStep}
|
|
769
|
+
</span>
|
|
770
|
+
</div>
|
|
771
|
+
<button
|
|
772
|
+
type="button"
|
|
773
|
+
class="text-xs text-amber-600 hover:text-amber-800 dark:text-amber-400 dark:hover:text-amber-200"
|
|
774
|
+
onclick={() => { if (debugTerminal) { debugTerminal.clear(); debugTerminal.reset(); } hasPtyData = false; }}
|
|
775
|
+
>
|
|
776
|
+
Clear
|
|
777
|
+
</button>
|
|
778
|
+
</div>
|
|
779
|
+
<div
|
|
780
|
+
bind:this={debugTermContainer}
|
|
781
|
+
class="h-80 bg-[#0f172a]"
|
|
782
|
+
></div>
|
|
783
|
+
</div>
|
|
784
|
+
{/if}
|
|
785
|
+
|
|
786
|
+
<!-- OpenCode Card -->
|
|
787
|
+
<div class="rounded-xl border border-slate-200 dark:border-slate-700/50 bg-white dark:bg-slate-800/50 overflow-hidden">
|
|
788
|
+
<!-- Card Header -->
|
|
789
|
+
<div class="flex items-center justify-between px-5 py-4 border-b border-slate-200 dark:border-slate-700/50">
|
|
790
|
+
<div class="flex items-center gap-3">
|
|
791
|
+
<div class="flex items-center justify-center [&>svg]:w-6 [&>svg]:h-6">
|
|
792
|
+
{@html isDarkMode() ? openCodeEngine.icon.dark : openCodeEngine.icon.light}
|
|
793
|
+
</div>
|
|
794
|
+
<div>
|
|
795
|
+
<h3 class="font-semibold text-slate-900 dark:text-slate-100">{openCodeEngine.name}</h3>
|
|
796
|
+
<p class="text-xs text-slate-500 dark:text-slate-400">{openCodeEngine.description}</p>
|
|
797
|
+
</div>
|
|
798
|
+
</div>
|
|
799
|
+
|
|
800
|
+
{#if isLoadingOpenCodeStatus}
|
|
801
|
+
<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-slate-100 dark:bg-slate-700 text-slate-500 dark:text-slate-400">
|
|
802
|
+
<Icon name="lucide:loader" class="w-3 h-3 animate-spin" />
|
|
803
|
+
Checking...
|
|
804
|
+
</span>
|
|
805
|
+
{:else if openCodeStatus?.installed}
|
|
806
|
+
<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400">
|
|
807
|
+
<span class="w-1.5 h-1.5 rounded-full bg-green-500"></span>
|
|
808
|
+
Installed
|
|
809
|
+
</span>
|
|
810
|
+
{:else}
|
|
811
|
+
<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-400">
|
|
812
|
+
<span class="w-1.5 h-1.5 rounded-full bg-red-500"></span>
|
|
813
|
+
Not Installed
|
|
814
|
+
</span>
|
|
815
|
+
{/if}
|
|
816
|
+
</div>
|
|
817
|
+
|
|
818
|
+
<!-- Card Body -->
|
|
819
|
+
<div class="px-5 py-4">
|
|
820
|
+
{#if isLoadingOpenCodeStatus}
|
|
821
|
+
<div class="flex items-center justify-center py-8">
|
|
822
|
+
<Icon name="lucide:loader" class="w-6 h-6 animate-spin text-slate-400" />
|
|
823
|
+
</div>
|
|
824
|
+
{:else if openCodeStatus && !openCodeStatus.installed}
|
|
825
|
+
<!-- Install Guide -->
|
|
826
|
+
<div class="space-y-4">
|
|
827
|
+
<p class="text-sm text-slate-600 dark:text-slate-300">
|
|
828
|
+
Open Code is not installed on this system. Install it using one of the methods below:
|
|
829
|
+
</p>
|
|
830
|
+
|
|
831
|
+
<!-- Tab Buttons -->
|
|
832
|
+
<div class="flex flex-wrap gap-1.5">
|
|
833
|
+
{#each Object.entries(openCodeInstallCommands) as [key, { label }]}
|
|
834
|
+
<button
|
|
835
|
+
type="button"
|
|
836
|
+
class="px-3 py-1.5 rounded-lg text-xs font-medium transition-colors
|
|
837
|
+
{activeOpenCodeInstallTab === key
|
|
838
|
+
? 'bg-violet-500/15 text-violet-700 dark:text-violet-300'
|
|
839
|
+
: 'bg-slate-100 dark:bg-slate-700/50 text-slate-600 dark:text-slate-400 hover:bg-slate-200 dark:hover:bg-slate-700'}"
|
|
840
|
+
onclick={() => (activeOpenCodeInstallTab = key as OpenCodeInstallTab)}
|
|
841
|
+
>
|
|
842
|
+
{label}
|
|
843
|
+
</button>
|
|
844
|
+
{/each}
|
|
845
|
+
</div>
|
|
846
|
+
|
|
847
|
+
<!-- Command Block -->
|
|
848
|
+
<div class="relative group">
|
|
849
|
+
<pre class="bg-slate-100 dark:bg-slate-950 text-slate-800 dark:text-slate-200 rounded-lg px-4 py-3 text-sm font-mono overflow-x-auto">{openCodeInstallCommands[activeOpenCodeInstallTab].command}</pre>
|
|
850
|
+
<button
|
|
851
|
+
type="button"
|
|
852
|
+
class="flex absolute top-2 right-2 p-1.5 rounded-md transition-colors {openCodeCommandCopied ? 'bg-violet-600/80 text-white' : 'bg-slate-300/80 dark:bg-slate-700/80 text-slate-600 dark:text-slate-300 hover:bg-slate-400/80 dark:hover:bg-slate-600'}"
|
|
853
|
+
onclick={copyOpenCodeCommand}
|
|
854
|
+
aria-label="Copy command"
|
|
855
|
+
>
|
|
856
|
+
<Icon name={openCodeCommandCopied ? 'lucide:check' : 'lucide:copy'} class="w-3.5 h-3.5" />
|
|
857
|
+
</button>
|
|
858
|
+
</div>
|
|
859
|
+
|
|
860
|
+
<!-- More info link -->
|
|
861
|
+
<div class="flex items-center gap-2 text-xs text-slate-500 dark:text-slate-400">
|
|
862
|
+
<Icon name="lucide:book-open" class="w-3.5 h-3.5 shrink-0" />
|
|
863
|
+
<div>
|
|
864
|
+
<span>For complete installation instructions, visit the</span>
|
|
865
|
+
<a
|
|
866
|
+
href="https://opencode.ai/docs"
|
|
867
|
+
target="_blank"
|
|
868
|
+
rel="noopener noreferrer"
|
|
869
|
+
class="inline-flex items-center gap-1 font-medium text-violet-600 dark:text-violet-400 hover:text-violet-800 dark:hover:text-violet-200 underline underline-offset-2"
|
|
870
|
+
>
|
|
871
|
+
official documentation
|
|
872
|
+
</a>
|
|
873
|
+
</div>
|
|
874
|
+
</div>
|
|
875
|
+
|
|
876
|
+
<button
|
|
877
|
+
type="button"
|
|
878
|
+
class="flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-lg bg-violet-600 text-white hover:bg-violet-700 transition-colors"
|
|
879
|
+
onclick={refreshOpenCodeStatus}
|
|
880
|
+
>
|
|
881
|
+
<Icon name="lucide:refresh-cw" class="w-4 h-4" />
|
|
882
|
+
Recheck Installation
|
|
883
|
+
</button>
|
|
884
|
+
</div>
|
|
885
|
+
{:else if openCodeStatus}
|
|
886
|
+
<!-- Installed View -->
|
|
887
|
+
<div class="space-y-4">
|
|
888
|
+
<!-- Version -->
|
|
889
|
+
<div class="flex items-center gap-2 text-sm text-slate-600 dark:text-slate-300">
|
|
890
|
+
<Icon name="lucide:tag" class="w-4 h-4 text-slate-400" />
|
|
891
|
+
<span>Version: <span class="font-mono font-medium text-slate-900 dark:text-slate-100">{openCodeStatus.version || 'Unknown'}</span></span>
|
|
892
|
+
</div>
|
|
893
|
+
|
|
894
|
+
<!-- Info note -->
|
|
895
|
+
<div class="flex gap-2.5 p-3 rounded-lg bg-slate-50 dark:bg-slate-800/80 border border-slate-200 dark:border-slate-700/50">
|
|
896
|
+
<Icon name="lucide:info" class="w-4 h-4 shrink-0 mt-0.5 text-slate-500 dark:text-slate-400" />
|
|
897
|
+
<p class="text-xs text-slate-600 dark:text-slate-400">
|
|
898
|
+
Open Code is installed and ready to use. API keys and provider configuration are managed through Open Code's own settings via the <span class="font-mono">/connect</span> command.
|
|
899
|
+
</p>
|
|
900
|
+
</div>
|
|
901
|
+
|
|
902
|
+
</div>
|
|
903
|
+
{/if}
|
|
904
|
+
</div>
|
|
905
|
+
</div>
|
|
906
|
+
</div>
|
|
907
|
+
|
|
908
|
+
<Dialog
|
|
909
|
+
bind:isOpen={claudeCodeDeleteDialogOpen}
|
|
910
|
+
onClose={() => { claudeCodeDeleteDialogOpen = false; claudeCodeDeleteTargetId = null; }}
|
|
911
|
+
type="error"
|
|
912
|
+
title="Delete Account"
|
|
913
|
+
message="Are you sure you want to delete this account? This action cannot be undone."
|
|
914
|
+
confirmText="Delete"
|
|
915
|
+
cancelText="Cancel"
|
|
916
|
+
onConfirm={deleteClaudeCodeAccount}
|
|
917
|
+
/>
|