@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,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal Session Restoration Service
|
|
3
|
+
* Handles restoration of terminal sessions after browser refresh
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { terminalSessionManager } from '../session.service';
|
|
7
|
+
import { terminalPersistenceManager } from '../persistence.service';
|
|
8
|
+
import { terminalStore } from '$frontend/lib/stores/features/terminal.svelte';
|
|
9
|
+
|
|
10
|
+
interface SessionToReconnect {
|
|
11
|
+
sessionId: string;
|
|
12
|
+
streamId: string;
|
|
13
|
+
command: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class SessionRestoreService {
|
|
17
|
+
private isRestorationComplete = false;
|
|
18
|
+
private sessionsToReconnect: SessionToReconnect[] = [];
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check if restoration is done
|
|
22
|
+
*/
|
|
23
|
+
isRestorationDone(): boolean {
|
|
24
|
+
return this.isRestorationComplete;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Check if there are restored sessions
|
|
29
|
+
*/
|
|
30
|
+
hasRestoredSessions(): boolean {
|
|
31
|
+
const persistedData = terminalPersistenceManager.loadTerminalSessions();
|
|
32
|
+
return persistedData !== null && persistedData.sessions.length > 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get sessions that need reconnection
|
|
37
|
+
*/
|
|
38
|
+
getSessionsToReconnect(): SessionToReconnect[] {
|
|
39
|
+
return this.sessionsToReconnect;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Clear sessions to reconnect list
|
|
44
|
+
*/
|
|
45
|
+
clearSessionsToReconnect(): void {
|
|
46
|
+
this.sessionsToReconnect = [];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Restore terminal sessions from persistence
|
|
51
|
+
*/
|
|
52
|
+
async restoreTerminalSessions(): Promise<void> {
|
|
53
|
+
const persistedData = terminalPersistenceManager.loadTerminalSessions();
|
|
54
|
+
if (!persistedData || persistedData.sessions.length === 0) {
|
|
55
|
+
// If no sessions, then clean up any orphaned stream info
|
|
56
|
+
this.cleanupStaleStreamInfo();
|
|
57
|
+
this.isRestorationComplete = true; // Mark as done even if no sessions
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Check if terminal store already has sessions (might be initialized elsewhere)
|
|
62
|
+
const existingSessions = terminalStore.sessions;
|
|
63
|
+
const existingSessionIds = new Set(existingSessions.map(s => s.id));
|
|
64
|
+
|
|
65
|
+
// Update nextSessionId based on restored sessions to avoid conflicts
|
|
66
|
+
let maxSessionId = 0;
|
|
67
|
+
for (const persistedSession of persistedData.sessions) {
|
|
68
|
+
const match = persistedSession.sessionId.match(/terminal-(\d+)/);
|
|
69
|
+
if (match) {
|
|
70
|
+
const id = parseInt(match[1], 10);
|
|
71
|
+
if (id > maxSessionId) {
|
|
72
|
+
maxSessionId = id;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Update terminal store's nextSessionId if needed
|
|
78
|
+
if (maxSessionId > 0) {
|
|
79
|
+
terminalStore.updateNextSessionId(maxSessionId + 1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Track sessions that need stream reconnection
|
|
83
|
+
const sessionsNeedingReconnect: SessionToReconnect[] = [];
|
|
84
|
+
|
|
85
|
+
for (const persistedSession of persistedData.sessions) {
|
|
86
|
+
// Skip if session already exists
|
|
87
|
+
if (existingSessionIds.has(persistedSession.sessionId)) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Restore session in session manager
|
|
92
|
+
terminalSessionManager.restoreSession(
|
|
93
|
+
persistedSession.sessionId,
|
|
94
|
+
persistedSession.projectId,
|
|
95
|
+
persistedSession.projectPath,
|
|
96
|
+
persistedSession.workingDirectory,
|
|
97
|
+
[], // outputHistory will be restored from lines
|
|
98
|
+
persistedSession.commandHistory,
|
|
99
|
+
persistedSession.createdAt,
|
|
100
|
+
persistedSession.lastUsedAt
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
// Restore session in terminal store
|
|
104
|
+
// Extract terminal number from sessionId (format: projectId-terminal-N or terminal-N)
|
|
105
|
+
const sessionParts = persistedSession.sessionId.split('-');
|
|
106
|
+
const terminalNumber = sessionParts[sessionParts.length - 1] || '1';
|
|
107
|
+
|
|
108
|
+
const restoredSession = {
|
|
109
|
+
id: persistedSession.sessionId,
|
|
110
|
+
name: `Terminal ${terminalNumber}`,
|
|
111
|
+
directory: persistedSession.workingDirectory,
|
|
112
|
+
lines: persistedSession.lines || [],
|
|
113
|
+
commandHistory: persistedSession.commandHistory || [],
|
|
114
|
+
isActive: persistedSession.isActive,
|
|
115
|
+
createdAt: persistedSession.createdAt,
|
|
116
|
+
lastUsedAt: persistedSession.lastUsedAt,
|
|
117
|
+
shellType: persistedSession.shellType || 'Unknown',
|
|
118
|
+
terminalBuffer: undefined,
|
|
119
|
+
projectId: persistedSession.projectId,
|
|
120
|
+
projectPath: persistedSession.projectPath
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Add to terminal store only if it doesn't exist
|
|
124
|
+
terminalStore.addSession(restoredSession);
|
|
125
|
+
|
|
126
|
+
// Check if this session was executing and needs reconnection
|
|
127
|
+
if (persistedSession.isExecuting && persistedSession.lastCommand) {
|
|
128
|
+
// Mark this session as restored
|
|
129
|
+
if (typeof window !== 'undefined') {
|
|
130
|
+
sessionStorage.setItem('terminal-restored-' + persistedSession.sessionId, 'true');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Add to reconnection list
|
|
134
|
+
// Use streamId if available, otherwise generate one based on sessionId
|
|
135
|
+
const streamId = persistedSession.streamId || `stream-${persistedSession.sessionId}-${Date.now()}`;
|
|
136
|
+
sessionsNeedingReconnect.push({
|
|
137
|
+
sessionId: persistedSession.sessionId,
|
|
138
|
+
streamId: streamId,
|
|
139
|
+
command: persistedSession.lastCommand
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Note: We don't need to add output history to session manager separately
|
|
144
|
+
// because the lines are already included in restoredSession.lines
|
|
145
|
+
// Adding them again would cause duplication
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Set active session only if it exists in the restored sessions
|
|
149
|
+
if (persistedData.activeSessionId) {
|
|
150
|
+
const activeSessionExists = terminalStore.sessions.find(s => s.id === persistedData.activeSessionId);
|
|
151
|
+
if (activeSessionExists) {
|
|
152
|
+
terminalStore.setActiveSession(persistedData.activeSessionId);
|
|
153
|
+
terminalSessionManager.setActiveSession(persistedData.activeSessionId);
|
|
154
|
+
} else if (terminalStore.sessions.length > 0) {
|
|
155
|
+
// Set first session as active if specified active session doesn't exist
|
|
156
|
+
const firstSession = terminalStore.sessions[0];
|
|
157
|
+
terminalStore.setActiveSession(firstSession.id);
|
|
158
|
+
terminalSessionManager.setActiveSession(firstSession.id);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Mark restoration as complete
|
|
163
|
+
this.isRestorationComplete = true;
|
|
164
|
+
|
|
165
|
+
// Store sessions needing reconnect for later processing
|
|
166
|
+
this.sessionsToReconnect = sessionsNeedingReconnect;
|
|
167
|
+
|
|
168
|
+
// After restoration complete, clean up truly orphaned stream info
|
|
169
|
+
// This will only remove stream info for sessions that don't exist
|
|
170
|
+
this.cleanupStaleStreamInfo();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Clean up stale stream info (in-memory)
|
|
175
|
+
* Only removes stream info that doesn't have corresponding sessions
|
|
176
|
+
*/
|
|
177
|
+
cleanupStaleStreamInfo(): void {
|
|
178
|
+
const validSessionIds = new Set(terminalStore.sessions.map(s => s.id));
|
|
179
|
+
const allStreams = terminalPersistenceManager.getAllActiveStreams();
|
|
180
|
+
|
|
181
|
+
for (const stream of allStreams) {
|
|
182
|
+
if (!validSessionIds.has(stream.sessionId)) {
|
|
183
|
+
terminalPersistenceManager.clearStreamInfo(stream.sessionId, stream.streamId);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Get active streams for reconnection
|
|
190
|
+
*/
|
|
191
|
+
getActiveStreamsForReconnection(): SessionToReconnect[] {
|
|
192
|
+
// Only try to reconnect if we have restored sessions
|
|
193
|
+
const restoredSessions = terminalStore.sessions;
|
|
194
|
+
if (restoredSessions.length === 0) {
|
|
195
|
+
return [];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const activeStreams: SessionToReconnect[] = [];
|
|
199
|
+
const processedStreamIds = new Set<string>();
|
|
200
|
+
|
|
201
|
+
// First, add sessions that were marked as executing during restoration
|
|
202
|
+
if (this.sessionsToReconnect.length > 0) {
|
|
203
|
+
for (const session of this.sessionsToReconnect) {
|
|
204
|
+
activeStreams.push(session);
|
|
205
|
+
processedStreamIds.add(session.streamId);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Check persistence manager for all stream info (session-based and streamId-based)
|
|
210
|
+
const allActiveStreams = terminalPersistenceManager.getAllActiveStreams();
|
|
211
|
+
for (const streamInfo of allActiveStreams) {
|
|
212
|
+
// Skip if already processed
|
|
213
|
+
if (processedStreamIds.has(streamInfo.streamId)) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// IMPORTANT: Only reconnect to streams that belong to current project sessions
|
|
218
|
+
// Don't try to reconnect to streams from other projects during restoration
|
|
219
|
+
let shouldReconnect = false;
|
|
220
|
+
let matchingSessionId: string | null = null;
|
|
221
|
+
|
|
222
|
+
for (const session of restoredSessions) {
|
|
223
|
+
// Only match by exact sessionId (not by projectId during initial restoration)
|
|
224
|
+
// This prevents trying to reconnect to other project's streams
|
|
225
|
+
if (streamInfo.sessionId === session.id) {
|
|
226
|
+
shouldReconnect = true;
|
|
227
|
+
matchingSessionId = session.id;
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (shouldReconnect && matchingSessionId) {
|
|
233
|
+
activeStreams.push({
|
|
234
|
+
sessionId: matchingSessionId,
|
|
235
|
+
streamId: streamInfo.streamId,
|
|
236
|
+
command: streamInfo.command
|
|
237
|
+
});
|
|
238
|
+
processedStreamIds.add(streamInfo.streamId);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return activeStreams;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Save current terminal state
|
|
247
|
+
*/
|
|
248
|
+
saveCurrentState(): void {
|
|
249
|
+
const sessions = terminalStore.sessions;
|
|
250
|
+
const activeSessionId = terminalStore.activeSessionId;
|
|
251
|
+
|
|
252
|
+
// Check for duplicates before saving
|
|
253
|
+
const uniqueSessions = new Map<string, any>();
|
|
254
|
+
for (const session of sessions) {
|
|
255
|
+
if (!uniqueSessions.has(session.id)) {
|
|
256
|
+
// Enhance session with execution state from terminalSessionManager
|
|
257
|
+
const sessionState = terminalSessionManager.getSession(session.id);
|
|
258
|
+
const enhancedSession = {
|
|
259
|
+
...session,
|
|
260
|
+
isExecuting: sessionState?.isExecuting || false,
|
|
261
|
+
lastCommand: sessionState?.lastCommand || undefined,
|
|
262
|
+
streamId: sessionState?.streamId || undefined
|
|
263
|
+
};
|
|
264
|
+
uniqueSessions.set(session.id, enhancedSession);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const cleanSessions = Array.from(uniqueSessions.values());
|
|
269
|
+
terminalPersistenceManager.saveTerminalSessions(cleanSessions, activeSessionId);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Export singleton instance
|
|
274
|
+
export const sessionRestoreService = new SessionRestoreService();
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal Stream Manager
|
|
3
|
+
* Manages active terminal streams and their lifecycle
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { terminalSessionManager } from '../session.service';
|
|
7
|
+
import { terminalPersistenceManager } from '../persistence.service';
|
|
8
|
+
import { terminalStore } from '$frontend/lib/stores/features/terminal.svelte';
|
|
9
|
+
import type { TerminalLine } from '$shared/types/terminal';
|
|
10
|
+
|
|
11
|
+
export interface StreamInfo {
|
|
12
|
+
streamId: string;
|
|
13
|
+
sessionId: string;
|
|
14
|
+
command: string;
|
|
15
|
+
status: 'active' | 'reconnecting' | 'completed' | 'error';
|
|
16
|
+
reconnectAttempts: number;
|
|
17
|
+
maxReconnectAttempts: number;
|
|
18
|
+
outputIndex: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
class StreamManager {
|
|
22
|
+
private streams = new Map<string, StreamInfo>();
|
|
23
|
+
private reconnectTimers = new Map<string, NodeJS.Timeout>();
|
|
24
|
+
private readonly MAX_RECONNECT_ATTEMPTS = 5;
|
|
25
|
+
private readonly RECONNECT_DELAY = 2000; // Start with 2 seconds
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get stream info for a session
|
|
29
|
+
*/
|
|
30
|
+
getStreamInfo(sessionId: string): StreamInfo | undefined {
|
|
31
|
+
return this.streams.get(sessionId);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Check if a session has an active stream (PTY process running)
|
|
36
|
+
*/
|
|
37
|
+
hasActiveStream(sessionId: string): boolean {
|
|
38
|
+
const streamInfo = this.streams.get(sessionId);
|
|
39
|
+
return streamInfo?.status === 'active' || streamInfo?.status === 'reconnecting';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Check if any session has active streams
|
|
44
|
+
*/
|
|
45
|
+
hasAnyActiveStreams(): boolean {
|
|
46
|
+
for (const [_, streamInfo] of this.streams) {
|
|
47
|
+
if (streamInfo.status === 'active' || streamInfo.status === 'reconnecting') {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get active streams count
|
|
56
|
+
*/
|
|
57
|
+
getActiveStreamsCount(): number {
|
|
58
|
+
return this.streams.size;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Start a new terminal stream
|
|
63
|
+
*/
|
|
64
|
+
startStream(sessionId: string, streamId: string, command: string, projectId?: string): void {
|
|
65
|
+
// Save stream info for persistence with projectId
|
|
66
|
+
terminalPersistenceManager.saveActiveStream(sessionId, streamId, command, projectId);
|
|
67
|
+
|
|
68
|
+
// Track stream
|
|
69
|
+
const streamInfo: StreamInfo = {
|
|
70
|
+
streamId,
|
|
71
|
+
sessionId,
|
|
72
|
+
command,
|
|
73
|
+
status: 'active',
|
|
74
|
+
reconnectAttempts: 0,
|
|
75
|
+
maxReconnectAttempts: this.MAX_RECONNECT_ATTEMPTS,
|
|
76
|
+
outputIndex: 0
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
this.streams.set(sessionId, streamInfo);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Update stream status
|
|
84
|
+
*/
|
|
85
|
+
updateStreamStatus(sessionId: string, status: StreamInfo['status']): void {
|
|
86
|
+
const streamInfo = this.streams.get(sessionId);
|
|
87
|
+
if (streamInfo) {
|
|
88
|
+
streamInfo.status = status;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Update output index
|
|
94
|
+
*/
|
|
95
|
+
updateOutputIndex(sessionId: string, index: number): void {
|
|
96
|
+
const streamInfo = this.streams.get(sessionId);
|
|
97
|
+
if (streamInfo) {
|
|
98
|
+
streamInfo.outputIndex = index;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Increment output index
|
|
104
|
+
*/
|
|
105
|
+
incrementOutputIndex(sessionId: string): void {
|
|
106
|
+
const streamInfo = this.streams.get(sessionId);
|
|
107
|
+
if (streamInfo) {
|
|
108
|
+
streamInfo.outputIndex++;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Update reconnect attempts
|
|
114
|
+
*/
|
|
115
|
+
updateReconnectAttempts(sessionId: string, attempts: number): void {
|
|
116
|
+
const streamInfo = this.streams.get(sessionId);
|
|
117
|
+
if (streamInfo) {
|
|
118
|
+
streamInfo.reconnectAttempts = attempts;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Set reconnect timer
|
|
124
|
+
*/
|
|
125
|
+
setReconnectTimer(sessionId: string, timer: NodeJS.Timeout): void {
|
|
126
|
+
// Clear existing timer if any
|
|
127
|
+
this.clearReconnectTimer(sessionId);
|
|
128
|
+
this.reconnectTimers.set(sessionId, timer);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Clear reconnect timer
|
|
133
|
+
*/
|
|
134
|
+
clearReconnectTimer(sessionId: string): void {
|
|
135
|
+
const timer = this.reconnectTimers.get(sessionId);
|
|
136
|
+
if (timer) {
|
|
137
|
+
clearTimeout(timer);
|
|
138
|
+
this.reconnectTimers.delete(sessionId);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* End a terminal stream
|
|
144
|
+
*/
|
|
145
|
+
endStream(sessionId: string, forceClear: boolean = false): void {
|
|
146
|
+
const streamInfo = this.streams.get(sessionId);
|
|
147
|
+
|
|
148
|
+
// If forceClear is true (e.g., from cancelCommand), clear localStorage immediately
|
|
149
|
+
if (forceClear && streamInfo) {
|
|
150
|
+
terminalPersistenceManager.clearStreamInfo(sessionId, streamInfo.streamId);
|
|
151
|
+
}
|
|
152
|
+
// Otherwise DON'T clear stream info from localStorage here
|
|
153
|
+
// It will be cleared by terminal-service when command actually completes
|
|
154
|
+
// This allows reconnection after browser refresh
|
|
155
|
+
|
|
156
|
+
// Remove from active streams in memory
|
|
157
|
+
this.streams.delete(sessionId);
|
|
158
|
+
|
|
159
|
+
// Clear any reconnect timers
|
|
160
|
+
this.clearReconnectTimer(sessionId);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Handle stream completion
|
|
165
|
+
*/
|
|
166
|
+
handleStreamCompletion(sessionId: string): void {
|
|
167
|
+
const streamInfo = this.streams.get(sessionId);
|
|
168
|
+
if (!streamInfo) return;
|
|
169
|
+
|
|
170
|
+
// Clear reconnect timer
|
|
171
|
+
this.clearReconnectTimer(sessionId);
|
|
172
|
+
|
|
173
|
+
// Remove stream
|
|
174
|
+
this.streams.delete(sessionId);
|
|
175
|
+
|
|
176
|
+
// Clear persistence with streamId
|
|
177
|
+
terminalPersistenceManager.clearStreamInfo(sessionId, streamInfo.streamId);
|
|
178
|
+
|
|
179
|
+
// Mark session as not executing
|
|
180
|
+
terminalSessionManager.endExecution(sessionId);
|
|
181
|
+
terminalStore.setExecutingState(sessionId, false);
|
|
182
|
+
|
|
183
|
+
// Trigger prompt display
|
|
184
|
+
terminalStore.triggerPromptDisplay(sessionId);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Handle stream data
|
|
189
|
+
*/
|
|
190
|
+
handleStreamData(sessionId: string, data: any): void {
|
|
191
|
+
const streamInfo = this.streams.get(sessionId);
|
|
192
|
+
if (!streamInfo) return;
|
|
193
|
+
|
|
194
|
+
// Update output index
|
|
195
|
+
streamInfo.outputIndex++;
|
|
196
|
+
|
|
197
|
+
// Handle different data types
|
|
198
|
+
switch (data.type) {
|
|
199
|
+
case 'output':
|
|
200
|
+
case 'error':
|
|
201
|
+
// Add to terminal display
|
|
202
|
+
const outputLine: TerminalLine = {
|
|
203
|
+
content: data.content || '',
|
|
204
|
+
type: data.type,
|
|
205
|
+
timestamp: new Date()
|
|
206
|
+
};
|
|
207
|
+
terminalStore.addOutput(sessionId, outputLine);
|
|
208
|
+
|
|
209
|
+
// Add to session history
|
|
210
|
+
terminalSessionManager.addOutputToHistory(sessionId, data.content || '');
|
|
211
|
+
|
|
212
|
+
// Clear the restoration flag on first successful output
|
|
213
|
+
// This ensures we don't show "restored session" message on interrupt
|
|
214
|
+
if (typeof window !== 'undefined' && sessionStorage.getItem('terminal-restored-' + sessionId) === 'true') {
|
|
215
|
+
sessionStorage.removeItem('terminal-restored-' + sessionId);
|
|
216
|
+
}
|
|
217
|
+
break;
|
|
218
|
+
|
|
219
|
+
case 'directory':
|
|
220
|
+
// Update working directory
|
|
221
|
+
if (data.newDirectory) {
|
|
222
|
+
terminalSessionManager.updateWorkingDirectory(sessionId, data.newDirectory);
|
|
223
|
+
terminalStore.updateWorkingDirectory(sessionId, data.newDirectory);
|
|
224
|
+
}
|
|
225
|
+
break;
|
|
226
|
+
|
|
227
|
+
case 'exit':
|
|
228
|
+
case 'complete':
|
|
229
|
+
// Command completed
|
|
230
|
+
this.handleStreamCompletion(sessionId);
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Clean up all streams
|
|
237
|
+
*/
|
|
238
|
+
cleanup(): void {
|
|
239
|
+
// Clear all timers
|
|
240
|
+
for (const timer of this.reconnectTimers.values()) {
|
|
241
|
+
clearTimeout(timer);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Clear maps
|
|
245
|
+
this.streams.clear();
|
|
246
|
+
this.reconnectTimers.clear();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Get all streams
|
|
251
|
+
*/
|
|
252
|
+
getAllStreams(): Map<string, StreamInfo> {
|
|
253
|
+
return this.streams;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Create stream info
|
|
258
|
+
*/
|
|
259
|
+
createStreamInfo(
|
|
260
|
+
streamId: string,
|
|
261
|
+
sessionId: string,
|
|
262
|
+
command: string,
|
|
263
|
+
status: StreamInfo['status'] = 'reconnecting',
|
|
264
|
+
attemptNumber: number = 1
|
|
265
|
+
): StreamInfo {
|
|
266
|
+
return {
|
|
267
|
+
streamId,
|
|
268
|
+
sessionId,
|
|
269
|
+
command,
|
|
270
|
+
status,
|
|
271
|
+
reconnectAttempts: attemptNumber,
|
|
272
|
+
maxReconnectAttempts: this.MAX_RECONNECT_ATTEMPTS,
|
|
273
|
+
outputIndex: 0
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Add or update stream
|
|
279
|
+
*/
|
|
280
|
+
setStream(sessionId: string, streamInfo: StreamInfo): void {
|
|
281
|
+
this.streams.set(sessionId, streamInfo);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Export singleton instance
|
|
286
|
+
export const streamManager = new StreamManager();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal Services Module
|
|
3
|
+
*
|
|
4
|
+
* Centralized exports for all terminal-related services
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { terminalService } from './terminal.service';
|
|
8
|
+
export { terminalPersistenceManager } from './persistence.service';
|
|
9
|
+
export { terminalProjectManager } from './project.service';
|
|
10
|
+
export { terminalSessionManager } from './session.service';
|
|
11
|
+
|
|
12
|
+
// Export types if needed
|
|
13
|
+
export type { TerminalSessionState } from './session.service';
|
|
14
|
+
export type { StreamingResponse, TerminalConnectOptions } from './terminal.service';
|