@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,157 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Message Header Component
|
|
3
|
+
|
|
4
|
+
Features:
|
|
5
|
+
- Timestamp display
|
|
6
|
+
- Sender name and role badge
|
|
7
|
+
- Agent status indicator
|
|
8
|
+
- Action buttons (copy, undo, edit, token usage, debug)
|
|
9
|
+
-->
|
|
10
|
+
|
|
11
|
+
<script lang="ts">
|
|
12
|
+
import type { SDKMessageFormatter } from '$shared/types/database/schema';
|
|
13
|
+
import type { IconName } from '$shared/types/ui/icons';
|
|
14
|
+
import Icon from '$frontend/lib/components/common/Icon.svelte';
|
|
15
|
+
import { appState } from '$frontend/lib/stores/core/app.svelte';
|
|
16
|
+
|
|
17
|
+
const {
|
|
18
|
+
message,
|
|
19
|
+
messageTimestamp,
|
|
20
|
+
isLastUserMessage = false,
|
|
21
|
+
roleConfig,
|
|
22
|
+
roleCategory,
|
|
23
|
+
agentStatus,
|
|
24
|
+
senderName,
|
|
25
|
+
hasTokenUsageData,
|
|
26
|
+
formatTime,
|
|
27
|
+
onCopy,
|
|
28
|
+
onRestore,
|
|
29
|
+
onEdit,
|
|
30
|
+
onShowTokenUsage,
|
|
31
|
+
onShowDebug
|
|
32
|
+
}: {
|
|
33
|
+
message: SDKMessageFormatter;
|
|
34
|
+
messageTimestamp: string;
|
|
35
|
+
isLastUserMessage?: boolean;
|
|
36
|
+
roleConfig: { gradient: string; icon: IconName; name: string };
|
|
37
|
+
roleCategory: 'user' | 'assistant' | 'agent' | string;
|
|
38
|
+
agentStatus: 'processing' | 'success' | 'error' | null;
|
|
39
|
+
senderName: string | null;
|
|
40
|
+
hasTokenUsageData: any;
|
|
41
|
+
formatTime: (timestamp?: string) => string;
|
|
42
|
+
onCopy: () => void;
|
|
43
|
+
onRestore: () => void;
|
|
44
|
+
onEdit: () => void;
|
|
45
|
+
onShowTokenUsage: () => void;
|
|
46
|
+
onShowDebug: () => void;
|
|
47
|
+
} = $props();
|
|
48
|
+
|
|
49
|
+
// State untuk copy button
|
|
50
|
+
let isCopied = $state(false);
|
|
51
|
+
|
|
52
|
+
// Handle copy dengan perubahan icon
|
|
53
|
+
function handleCopy() {
|
|
54
|
+
onCopy();
|
|
55
|
+
isCopied = true;
|
|
56
|
+
setTimeout(() => {
|
|
57
|
+
isCopied = false;
|
|
58
|
+
}, 1000);
|
|
59
|
+
}
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<div class="flex items-center justify-between gap-5 px-3 md:px-4 py-1 border-b border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800">
|
|
63
|
+
<!-- Timestamp and Type -->
|
|
64
|
+
<div class="flex items-center gap-2">
|
|
65
|
+
<span class="text-xs text-slate-500 dark:text-slate-400 font-medium">
|
|
66
|
+
{formatTime(messageTimestamp)}
|
|
67
|
+
</span>
|
|
68
|
+
<span class="w-1 h-1 bg-current rounded-full opacity-50"></span>
|
|
69
|
+
<div class="flex items-center gap-1.5">
|
|
70
|
+
<span class="text-xs text-slate-400 dark:text-slate-500 capitalize">
|
|
71
|
+
{roleCategory === 'user' && senderName ? senderName : roleConfig.name}
|
|
72
|
+
</span>
|
|
73
|
+
<!-- Agent Status Indicator -->
|
|
74
|
+
{#if agentStatus}
|
|
75
|
+
{#if agentStatus === 'processing'}
|
|
76
|
+
<span title="Agent is processing...">
|
|
77
|
+
<Icon name="lucide:loader" class="w-3 h-3 text-violet-500 dark:text-violet-400 animate-spin" />
|
|
78
|
+
</span>
|
|
79
|
+
{:else if agentStatus === 'success'}
|
|
80
|
+
<span title="Agent completed successfully">
|
|
81
|
+
<Icon name="lucide:check" class="w-3 h-3 text-green-500 dark:text-green-400" />
|
|
82
|
+
</span>
|
|
83
|
+
{:else if agentStatus === 'error'}
|
|
84
|
+
<span title="Agent encountered an error">
|
|
85
|
+
<Icon name="lucide:x" class="w-3 h-3 text-red-500 dark:text-red-400" />
|
|
86
|
+
</span>
|
|
87
|
+
{/if}
|
|
88
|
+
{/if}
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<!-- Compact Actions - Always visible but subtle -->
|
|
93
|
+
<div class="flex items-center space-x-1 -mr-1">
|
|
94
|
+
<!-- Copy button - hanya untuk user dan assistant (tidak untuk agent) -->
|
|
95
|
+
{#if roleCategory === 'user' || roleCategory === 'assistant'}
|
|
96
|
+
<button
|
|
97
|
+
onclick={handleCopy}
|
|
98
|
+
class="inline-flex p-1.5 rounded-md hover:bg-slate-200 dark:hover:bg-slate-600 transition-colors opacity-60 hover:opacity-100"
|
|
99
|
+
aria-label="Copy message"
|
|
100
|
+
title="Copy message"
|
|
101
|
+
>
|
|
102
|
+
<Icon name={isCopied ? "lucide:check" : "lucide:copy"} class="w-3.5 h-3.5" />
|
|
103
|
+
</button>
|
|
104
|
+
{/if}
|
|
105
|
+
|
|
106
|
+
<!-- Undo and Edit buttons for user messages (disabled saat streaming) -->
|
|
107
|
+
{#if roleCategory === 'user'}
|
|
108
|
+
<!-- Undo button (not shown for last user message) -->
|
|
109
|
+
{#if !isLastUserMessage}
|
|
110
|
+
<button
|
|
111
|
+
onclick={onRestore}
|
|
112
|
+
disabled={appState.isLoading}
|
|
113
|
+
class="inline-flex p-1.5 rounded-md transition-colors {appState.isLoading ? 'cursor-not-allowed opacity-40' : 'hover:bg-slate-200 dark:hover:bg-slate-600 opacity-60 hover:opacity-100'}"
|
|
114
|
+
aria-label="Undo to this checkpoint"
|
|
115
|
+
title="Undo to this checkpoint"
|
|
116
|
+
>
|
|
117
|
+
<Icon name="lucide:undo-2" class="w-3.5 h-3.5" />
|
|
118
|
+
</button>
|
|
119
|
+
{/if}
|
|
120
|
+
|
|
121
|
+
<!-- Edit button for user messages -->
|
|
122
|
+
<button
|
|
123
|
+
onclick={onEdit}
|
|
124
|
+
disabled={appState.isLoading}
|
|
125
|
+
class="inline-flex p-1.5 rounded-md transition-colors {appState.isLoading ? 'cursor-not-allowed opacity-40' : 'hover:bg-slate-200 dark:hover:bg-slate-600 opacity-60 hover:opacity-100'}"
|
|
126
|
+
aria-label="Edit message"
|
|
127
|
+
title="Edit message"
|
|
128
|
+
>
|
|
129
|
+
<Icon name="lucide:pencil" class="w-3.5 h-3.5" />
|
|
130
|
+
</button>
|
|
131
|
+
{/if}
|
|
132
|
+
|
|
133
|
+
<!-- Token Usage button -->
|
|
134
|
+
{#if hasTokenUsageData}
|
|
135
|
+
<button
|
|
136
|
+
onclick={onShowTokenUsage}
|
|
137
|
+
class="inline-flex p-1.5 rounded-md hover:bg-slate-200 dark:hover:bg-slate-600 transition-colors opacity-60 hover:opacity-100"
|
|
138
|
+
aria-label="Show token usage info"
|
|
139
|
+
title="Token usage"
|
|
140
|
+
>
|
|
141
|
+
<Icon name="lucide:zap" class="w-3.5 h-3.5" />
|
|
142
|
+
</button>
|
|
143
|
+
{/if}
|
|
144
|
+
|
|
145
|
+
<!-- Debug toggle button -->
|
|
146
|
+
{#if 'parent_tool_use_id' in message}
|
|
147
|
+
<button
|
|
148
|
+
onclick={onShowDebug}
|
|
149
|
+
class="inline-flex p-1.5 rounded-md hover:bg-slate-200 dark:hover:bg-slate-600 transition-colors opacity-60 hover:opacity-100"
|
|
150
|
+
aria-label="Show debug info"
|
|
151
|
+
title="Debug info"
|
|
152
|
+
>
|
|
153
|
+
<Icon name="lucide:bug" class="w-3.5 h-3.5" />
|
|
154
|
+
</button>
|
|
155
|
+
{/if}
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Debug Modal Component
|
|
3
|
+
|
|
4
|
+
Features:
|
|
5
|
+
- Display raw message data
|
|
6
|
+
- JSON formatting
|
|
7
|
+
- Copy to clipboard
|
|
8
|
+
-->
|
|
9
|
+
|
|
10
|
+
<script lang="ts">
|
|
11
|
+
import type { SDKMessageFormatter } from '$shared/types/database/schema';
|
|
12
|
+
import Modal from '$frontend/lib/components/common/Modal.svelte';
|
|
13
|
+
import Icon from '$frontend/lib/components/common/Icon.svelte';
|
|
14
|
+
|
|
15
|
+
let {
|
|
16
|
+
isOpen = $bindable(),
|
|
17
|
+
message,
|
|
18
|
+
onClose
|
|
19
|
+
}: {
|
|
20
|
+
isOpen: boolean;
|
|
21
|
+
message: SDKMessageFormatter;
|
|
22
|
+
onClose: () => void;
|
|
23
|
+
} = $props();
|
|
24
|
+
|
|
25
|
+
function copyToClipboard() {
|
|
26
|
+
navigator.clipboard.writeText(JSON.stringify(message, null, 2));
|
|
27
|
+
}
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<Modal
|
|
31
|
+
bind:isOpen
|
|
32
|
+
title="Debug Information"
|
|
33
|
+
size="lg"
|
|
34
|
+
{onClose}
|
|
35
|
+
>
|
|
36
|
+
{#snippet children()}
|
|
37
|
+
<div class="space-y-6">
|
|
38
|
+
<!-- Raw Message Data -->
|
|
39
|
+
<div>
|
|
40
|
+
<h4 class="font-medium text-slate-900 dark:text-slate-100 mb-2 flex items-center gap-2">
|
|
41
|
+
<Icon name="lucide:code" class="w-4 h-4" />
|
|
42
|
+
Raw Message
|
|
43
|
+
</h4>
|
|
44
|
+
<div class="bg-slate-100 dark:bg-slate-800 rounded-lg p-3 border border-slate-200 dark:border-slate-700">
|
|
45
|
+
<pre class="text-xs font-mono text-slate-700 dark:text-slate-300 overflow-x-auto max-h-80 overflow-y-auto whitespace-pre-wrap break-words">{JSON.stringify(message, null, 2)}</pre>
|
|
46
|
+
</div>
|
|
47
|
+
<div class="mt-3 flex justify-end">
|
|
48
|
+
<button
|
|
49
|
+
onclick={copyToClipboard}
|
|
50
|
+
class="px-3 py-1.5 bg-violet-500 hover:bg-violet-600 text-white rounded-md text-xs font-medium transition-colors flex items-center gap-1"
|
|
51
|
+
>
|
|
52
|
+
<Icon name="lucide:copy" class="w-3 h-3" />
|
|
53
|
+
Copy JSON
|
|
54
|
+
</button>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
{/snippet}
|
|
59
|
+
</Modal>
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Token Usage Modal Component
|
|
3
|
+
|
|
4
|
+
Features:
|
|
5
|
+
- Display token usage statistics
|
|
6
|
+
- Cache read and creation stats
|
|
7
|
+
- Request information
|
|
8
|
+
-->
|
|
9
|
+
|
|
10
|
+
<script lang="ts">
|
|
11
|
+
import Modal from '$frontend/lib/components/common/Modal.svelte';
|
|
12
|
+
import Icon from '$frontend/lib/components/common/Icon.svelte';
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
isOpen = $bindable(),
|
|
16
|
+
tokenUsage,
|
|
17
|
+
timestamp,
|
|
18
|
+
onClose
|
|
19
|
+
}: {
|
|
20
|
+
isOpen: boolean;
|
|
21
|
+
tokenUsage: any;
|
|
22
|
+
timestamp: string;
|
|
23
|
+
onClose: () => void;
|
|
24
|
+
} = $props();
|
|
25
|
+
|
|
26
|
+
// Format timestamp
|
|
27
|
+
const formatTime = (timestamp?: string) => {
|
|
28
|
+
if (!timestamp) return 'Unknown';
|
|
29
|
+
const date = new Date(timestamp);
|
|
30
|
+
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
31
|
+
};
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<Modal
|
|
35
|
+
bind:isOpen
|
|
36
|
+
title="Token Usage"
|
|
37
|
+
size="md"
|
|
38
|
+
{onClose}
|
|
39
|
+
>
|
|
40
|
+
{#snippet children()}
|
|
41
|
+
{#if tokenUsage}
|
|
42
|
+
<div class="space-y-4">
|
|
43
|
+
<!-- Token Usage Stats -->
|
|
44
|
+
<div class="bg-violet-50 dark:bg-violet-900/20 rounded-lg p-4">
|
|
45
|
+
<h4 class="font-medium text-violet-900 dark:text-violet-100 mb-2 flex items-center gap-2">
|
|
46
|
+
<Icon name="lucide:zap" class="w-4 h-4" />
|
|
47
|
+
Token Usage
|
|
48
|
+
</h4>
|
|
49
|
+
<div class="space-y-3 text-slate-600 dark:text-slate-400">
|
|
50
|
+
<div class="flex justify-between items-center">
|
|
51
|
+
<span class="text-sm">Input Tokens:</span>
|
|
52
|
+
<span class="font-mono font-semibold text-violet-600 dark:text-violet-400">
|
|
53
|
+
{(tokenUsage.input_tokens ?? 0).toLocaleString()}
|
|
54
|
+
</span>
|
|
55
|
+
</div>
|
|
56
|
+
<div class="flex justify-between items-center">
|
|
57
|
+
<span class="text-sm">Output Tokens:</span>
|
|
58
|
+
<span class="font-mono font-semibold text-violet-600 dark:text-violet-400">
|
|
59
|
+
{(tokenUsage.output_tokens ?? 0).toLocaleString()}
|
|
60
|
+
</span>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="flex justify-between items-center">
|
|
63
|
+
<span class="text-sm">Cache Read:</span>
|
|
64
|
+
<span class="font-mono font-semibold text-green-600 dark:text-green-400">
|
|
65
|
+
{(tokenUsage.cache_read_input_tokens ?? 0).toLocaleString()}
|
|
66
|
+
</span>
|
|
67
|
+
</div>
|
|
68
|
+
<div class="flex justify-between items-center">
|
|
69
|
+
<span class="text-sm">Cache Creation:</span>
|
|
70
|
+
<span class="font-mono font-semibold text-violet-600 dark:text-violet-400">
|
|
71
|
+
{(tokenUsage.cache_creation_input_tokens ?? 0).toLocaleString()}
|
|
72
|
+
</span>
|
|
73
|
+
</div>
|
|
74
|
+
<!-- Total -->
|
|
75
|
+
<div class="border-t border-violet-200/50 dark:border-violet-800/50 pt-3 mt-3">
|
|
76
|
+
<div class="flex justify-between items-center">
|
|
77
|
+
<span class="text-sm font-medium">Total Tokens:</span>
|
|
78
|
+
<span class="font-mono font-bold text-lg text-violet-600 dark:text-violet-400">
|
|
79
|
+
{((tokenUsage.input_tokens || 0) + (tokenUsage.output_tokens || 0)).toLocaleString()}
|
|
80
|
+
</span>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<!-- Request Info -->
|
|
87
|
+
<div class="bg-slate-50 dark:bg-slate-800 rounded-lg p-4 border border-slate-200 dark:border-slate-700">
|
|
88
|
+
<h4 class="font-medium text-slate-900 dark:text-slate-100 mb-2 flex items-center gap-2">
|
|
89
|
+
<Icon name="lucide:info" class="w-4 h-4" />
|
|
90
|
+
Request Info
|
|
91
|
+
</h4>
|
|
92
|
+
<div class="space-y-2">
|
|
93
|
+
<div class="flex justify-between items-center">
|
|
94
|
+
<span class="text-sm text-slate-600 dark:text-slate-400">Time:</span>
|
|
95
|
+
<span class="text-sm font-mono text-slate-900 dark:text-slate-100">
|
|
96
|
+
{formatTime(timestamp || new Date().toISOString())}
|
|
97
|
+
</span>
|
|
98
|
+
</div>
|
|
99
|
+
<div class="flex justify-between items-center">
|
|
100
|
+
<span class="text-sm text-slate-600 dark:text-slate-400">Date:</span>
|
|
101
|
+
<span class="text-sm font-mono text-slate-900 dark:text-slate-100">
|
|
102
|
+
{timestamp ? new Date(timestamp).toLocaleDateString() : 'Unknown'}
|
|
103
|
+
</span>
|
|
104
|
+
</div>
|
|
105
|
+
{#if tokenUsage.service_tier}
|
|
106
|
+
<div class="flex justify-between items-center">
|
|
107
|
+
<span class="text-sm text-slate-600 dark:text-slate-400">Service Tier:</span>
|
|
108
|
+
<span class="text-sm font-medium capitalize text-slate-900 dark:text-slate-100">
|
|
109
|
+
{tokenUsage.service_tier}
|
|
110
|
+
</span>
|
|
111
|
+
</div>
|
|
112
|
+
{/if}
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
{:else}
|
|
117
|
+
<div class="text-center py-8">
|
|
118
|
+
<Icon name="lucide:info" class="w-12 h-12 text-slate-400 mx-auto mb-2" />
|
|
119
|
+
<p class="text-slate-600 dark:text-slate-400">No token usage data available</p>
|
|
120
|
+
<p class="text-sm text-slate-500 dark:text-slate-500 mt-1">This message doesn't contain token usage information</p>
|
|
121
|
+
</div>
|
|
122
|
+
{/if}
|
|
123
|
+
{/snippet}
|
|
124
|
+
</Modal>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Utility functions for tool displays
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Format file path for display by shortening long paths
|
|
5
|
+
*/
|
|
6
|
+
export function formatPath(path: string): string {
|
|
7
|
+
if (path === 'current directory') return path;
|
|
8
|
+
|
|
9
|
+
if (path.length > 60) {
|
|
10
|
+
const parts = path.split(/[/\\]/);
|
|
11
|
+
if (parts.length > 3) {
|
|
12
|
+
return `.../${parts.slice(-3).join('/')}`;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return path;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Format content by truncating long text intelligently
|
|
20
|
+
*/
|
|
21
|
+
export function formatContent(content: string, maxLength: number = 500): string {
|
|
22
|
+
if (content.length <= maxLength) {
|
|
23
|
+
return content;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const lines = content.split('\n');
|
|
27
|
+
if (lines.length > 10) {
|
|
28
|
+
return lines.slice(0, 5).join('\n') +
|
|
29
|
+
'\n... (' + (lines.length - 10) + ' more lines) ...\n' +
|
|
30
|
+
lines.slice(-5).join('\n');
|
|
31
|
+
}
|
|
32
|
+
return content.substring(0, maxLength) + '...';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Format file size in human readable format
|
|
37
|
+
*/
|
|
38
|
+
export function formatFileSize(bytes: number): string {
|
|
39
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
40
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
41
|
+
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
42
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Truncate text with ellipsis
|
|
47
|
+
*/
|
|
48
|
+
export function truncateText(text: string, maxLength: number): string {
|
|
49
|
+
if (text.length > maxLength) {
|
|
50
|
+
return text.substring(0, maxLength - 3) + '...';
|
|
51
|
+
}
|
|
52
|
+
return text;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Remove common indentation from a string
|
|
57
|
+
*/
|
|
58
|
+
export function removeCommonIndentation(input: string): string {
|
|
59
|
+
const lines = input.split('\n');
|
|
60
|
+
|
|
61
|
+
// Find minimum indentation across all non-empty lines
|
|
62
|
+
let minIndent = Infinity;
|
|
63
|
+
|
|
64
|
+
for (const line of lines) {
|
|
65
|
+
if (line.trim()) { // Skip empty lines
|
|
66
|
+
const match = line.match(/^(\s*)/);
|
|
67
|
+
if (match) {
|
|
68
|
+
minIndent = Math.min(minIndent, match[1].length);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Remove common indentation from all lines
|
|
74
|
+
if (minIndent > 0 && minIndent < Infinity) {
|
|
75
|
+
return lines.map(line => {
|
|
76
|
+
if (line.trim()) {
|
|
77
|
+
return line.substring(minIndent);
|
|
78
|
+
}
|
|
79
|
+
return line;
|
|
80
|
+
}).join('\n');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return input;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Remove common indentation from an array of lines
|
|
88
|
+
*/
|
|
89
|
+
export function removeCommonIndentationFromLines(lines: string[]): { lines: string[], commonIndent: string } {
|
|
90
|
+
// Find minimum indentation across all non-empty lines
|
|
91
|
+
let minIndent = Infinity;
|
|
92
|
+
let commonIndent = '';
|
|
93
|
+
|
|
94
|
+
for (const line of lines) {
|
|
95
|
+
if (line.trim()) { // Skip empty lines
|
|
96
|
+
const match = line.match(/^(\s*)/);
|
|
97
|
+
if (match) {
|
|
98
|
+
const indent = match[1].length;
|
|
99
|
+
if (indent < minIndent) {
|
|
100
|
+
minIndent = indent;
|
|
101
|
+
commonIndent = match[1].substring(0, minIndent);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Remove common indentation from all lines
|
|
108
|
+
if (minIndent > 0 && minIndent < Infinity) {
|
|
109
|
+
return {
|
|
110
|
+
lines: lines.map(line => line.startsWith(commonIndent) ? line.substring(minIndent) : line),
|
|
111
|
+
commonIndent
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return { lines, commonIndent: '' };
|
|
116
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { BashOutputToolInput } from '$shared/types/messaging';
|
|
3
|
+
import { InfoLine } from './components';
|
|
4
|
+
import TextMessage from '../formatters/TextMessage.svelte';
|
|
5
|
+
|
|
6
|
+
const { toolInput }: { toolInput: BashOutputToolInput } = $props();
|
|
7
|
+
|
|
8
|
+
const taskId = toolInput.input.task_id;
|
|
9
|
+
const block = toolInput.input.block;
|
|
10
|
+
const timeout = toolInput.input.timeout;
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<div class="bg-white dark:bg-slate-800 rounded-md border border-slate-200/60 dark:border-slate-700/60 p-3">
|
|
14
|
+
<!-- Command Info -->
|
|
15
|
+
<div class="flex gap-3">
|
|
16
|
+
<InfoLine icon="lucide:terminal" text="Reading output from task: {taskId}" />
|
|
17
|
+
{#if block}
|
|
18
|
+
<InfoLine icon="lucide:clock" text="Blocking: {block}" />
|
|
19
|
+
{/if}
|
|
20
|
+
{#if timeout}
|
|
21
|
+
<InfoLine icon="lucide:timer" text="Timeout: {timeout}ms" />
|
|
22
|
+
{/if}
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<!-- Tool Result -->
|
|
27
|
+
{#if toolInput.$result}
|
|
28
|
+
<div class="mt-4 bg-white dark:bg-slate-800 rounded-md border border-slate-200/60 dark:border-slate-700/60 p-3">
|
|
29
|
+
{#if typeof toolInput.$result.content === 'string'}
|
|
30
|
+
<TextMessage content={toolInput.$result.content} />
|
|
31
|
+
{:else}
|
|
32
|
+
<TextMessage content={JSON.stringify(toolInput.$result.content)} />
|
|
33
|
+
{/if}
|
|
34
|
+
</div>
|
|
35
|
+
{/if}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { BashToolInput, BashOutputToolOutput } from '$shared/types/messaging';
|
|
3
|
+
import { TerminalCommand } from './components';
|
|
4
|
+
import CodeBlock from './components/CodeBlock.svelte';
|
|
5
|
+
|
|
6
|
+
const { toolInput }: { toolInput: BashToolInput } = $props();
|
|
7
|
+
|
|
8
|
+
const command = toolInput.input.command || '';
|
|
9
|
+
const description = toolInput.input.description;
|
|
10
|
+
const timeout = toolInput.input.timeout;
|
|
11
|
+
const isBackground = toolInput.input.run_in_background;
|
|
12
|
+
|
|
13
|
+
function parseBashOutputToolOutput(content: string): BashOutputToolOutput {
|
|
14
|
+
const statusMatch = content.match(/<status>(.*?)<\/status>/);
|
|
15
|
+
const stdoutMatch = content.match(/<stdout>(.*?)<\/stdout>/s);
|
|
16
|
+
const timestampMatch = content.match(/<timestamp>(.*?)<\/timestamp>/);
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
status: statusMatch ? statusMatch[1] as BashOutputToolOutput['status'] : 'completed',
|
|
20
|
+
output: stdoutMatch ? stdoutMatch[1].trim() : ""
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Parse the output content if it's from BashOutput format
|
|
25
|
+
const outputContent = $derived.by(() => {
|
|
26
|
+
if (!toolInput.$result?.content) return '';
|
|
27
|
+
|
|
28
|
+
// Check if this is a background command that has been merged with BashOutput
|
|
29
|
+
if (isBackground && toolInput.$result.content.includes('<status>')) {
|
|
30
|
+
const parsed = parseBashOutputToolOutput(toolInput.$result.content);
|
|
31
|
+
return parsed.output;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return toolInput.$result.content;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<TerminalCommand {command} {description} {timeout} />
|
|
40
|
+
|
|
41
|
+
<!-- Tool Result -->
|
|
42
|
+
{#if outputContent}
|
|
43
|
+
<div class="mt-4 bg-white dark:bg-slate-800 rounded-md border border-slate-200/60 dark:border-slate-700/60 p-3">
|
|
44
|
+
<CodeBlock code={outputContent} type="neutral" label="Output" />
|
|
45
|
+
</div>
|
|
46
|
+
{/if}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { FileHeader, CodeBlock } from './components';
|
|
3
|
+
import Icon from '$frontend/lib/components/common/Icon.svelte';
|
|
4
|
+
import type { ToolInput } from '$shared/types/messaging';
|
|
5
|
+
|
|
6
|
+
const { toolInput }: { toolInput: ToolInput } = $props();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Parse MCP tool name
|
|
10
|
+
* Format: mcp__server-name__tool-name
|
|
11
|
+
*/
|
|
12
|
+
interface ParsedToolName {
|
|
13
|
+
server: string;
|
|
14
|
+
tool: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function parseMcpToolName(fullName: string): ParsedToolName {
|
|
18
|
+
// Remove "mcp__" prefix
|
|
19
|
+
const withoutPrefix = fullName.replace('mcp__', '');
|
|
20
|
+
const parts = withoutPrefix.split('__');
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
server: parts[0] || 'unknown',
|
|
24
|
+
tool: parts[1] || 'unknown'
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { server, tool } = parseMcpToolName(toolInput.name);
|
|
29
|
+
|
|
30
|
+
// Format server name for display (e.g., "weather-service" -> "Weather Service")
|
|
31
|
+
const serverDisplayName = $derived.by(() => {
|
|
32
|
+
return server
|
|
33
|
+
.split('-')
|
|
34
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
35
|
+
.join(' ');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Format tool name for display (e.g., "get_temperature" -> "Get Temperature")
|
|
39
|
+
const toolDisplayName = $derived.by(() => {
|
|
40
|
+
return tool
|
|
41
|
+
.split('_')
|
|
42
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
43
|
+
.join(' ');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Extract result content
|
|
47
|
+
const resultContent = $derived.by(() => {
|
|
48
|
+
if (!toolInput.$result?.content) return null;
|
|
49
|
+
|
|
50
|
+
const content = toolInput.$result.content;
|
|
51
|
+
|
|
52
|
+
// If content is already a string, return it
|
|
53
|
+
if (typeof content === 'string') {
|
|
54
|
+
return content;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// If content is an array (MCP format)
|
|
58
|
+
if (Array.isArray(content)) {
|
|
59
|
+
// Extract text from first text block
|
|
60
|
+
const textBlock = (content as any[]).find((block: any) => block.type === 'text');
|
|
61
|
+
if (textBlock && textBlock.text) {
|
|
62
|
+
return textBlock.text;
|
|
63
|
+
}
|
|
64
|
+
// Fallback: stringify the array
|
|
65
|
+
return JSON.stringify(content, null, 2);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// If content is an object, stringify it
|
|
69
|
+
if (typeof content === 'object' && content !== null) {
|
|
70
|
+
return JSON.stringify(content, null, 2);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Fallback: convert to string
|
|
74
|
+
return String(content);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Check if result is an error
|
|
78
|
+
const isError = $derived.by(() => {
|
|
79
|
+
if (!toolInput.$result?.content) return false;
|
|
80
|
+
|
|
81
|
+
const content = toolInput.$result.content;
|
|
82
|
+
|
|
83
|
+
// Check for error markers in string content
|
|
84
|
+
if (typeof content === 'string') {
|
|
85
|
+
return content.toLowerCase().includes('error:');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Check for error markers in array content (MCP format)
|
|
89
|
+
if (Array.isArray(content)) {
|
|
90
|
+
const textBlock = (content as any[]).find((block: any) => block.type === 'text');
|
|
91
|
+
if (textBlock && textBlock.text) {
|
|
92
|
+
return textBlock.text.toLowerCase().includes('error:');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Check for isError property in object content
|
|
97
|
+
if (typeof content === 'object' && content !== null) {
|
|
98
|
+
return (content as any).isError === true;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return false;
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Format input for display
|
|
105
|
+
const formattedInput = $derived(JSON.stringify(toolInput.input, null, 2));
|
|
106
|
+
</script>
|
|
107
|
+
|
|
108
|
+
<div class="mb-2">
|
|
109
|
+
<h3 class="text-slate-900 dark:text-slate-100 flex items-center gap-x-3 gap-y-1 flex-wrap">
|
|
110
|
+
<div class="flex items-center gap-1.5">
|
|
111
|
+
<Icon name="lucide:tool-case" class="w-4 h-4" />
|
|
112
|
+
<span>{serverDisplayName}</span>
|
|
113
|
+
</div>
|
|
114
|
+
<div class="flex items-center gap-1.5">
|
|
115
|
+
<Icon name="lucide:hammer" class="w-4 h-4" />
|
|
116
|
+
<span>{toolDisplayName}</span>
|
|
117
|
+
</div>
|
|
118
|
+
</h3>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<!-- Tool Input -->
|
|
122
|
+
{#if toolInput.input && Object.keys(toolInput.input).length > 0}
|
|
123
|
+
<div class="bg-white dark:bg-slate-800 rounded-md border border-slate-200/60 dark:border-slate-700/60 p-3">
|
|
124
|
+
<CodeBlock code={formattedInput} type="neutral" label="Input" />
|
|
125
|
+
</div>
|
|
126
|
+
{/if}
|
|
127
|
+
|
|
128
|
+
<!-- Tool Result -->
|
|
129
|
+
{#if resultContent}
|
|
130
|
+
<div class="mt-4 bg-white dark:bg-slate-800 rounded-md border border-slate-200/60 dark:border-slate-700/60 p-3">
|
|
131
|
+
<CodeBlock code={resultContent} type="neutral" label={isError ? 'Error' : 'Result'} />
|
|
132
|
+
<!-- {@html resultContent.replace(/\n/g, '<br>')} -->
|
|
133
|
+
</div>
|
|
134
|
+
{:else if toolInput.$result}
|
|
135
|
+
<!-- Empty result -->
|
|
136
|
+
<div class="mt-4 bg-white dark:bg-slate-800 rounded-md border border-slate-200/60 dark:border-slate-700/60 p-3">
|
|
137
|
+
<p class="text-sm text-slate-500 dark:text-slate-400 italic">No result returned</p>
|
|
138
|
+
</div>
|
|
139
|
+
{/if}
|