@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.
Files changed (456) hide show
  1. package/.env.example +6 -0
  2. package/.github/workflows/release.yml +60 -0
  3. package/.github/workflows/test.yml +40 -0
  4. package/CONTRIBUTING.md +499 -0
  5. package/LICENSE +21 -0
  6. package/README.md +209 -0
  7. package/backend/index.ts +156 -0
  8. package/backend/lib/chat/helpers.ts +42 -0
  9. package/backend/lib/chat/index.ts +2 -0
  10. package/backend/lib/chat/stream-manager.ts +1126 -0
  11. package/backend/lib/database/README.md +77 -0
  12. package/backend/lib/database/index.ts +119 -0
  13. package/backend/lib/database/migrations/001_create_projects_table.ts +31 -0
  14. package/backend/lib/database/migrations/002_create_chat_sessions_table.ts +33 -0
  15. package/backend/lib/database/migrations/003_create_messages_table.ts +32 -0
  16. package/backend/lib/database/migrations/004_create_prompt_templates_table.ts +34 -0
  17. package/backend/lib/database/migrations/005_create_settings_table.ts +24 -0
  18. package/backend/lib/database/migrations/006_add_user_to_messages.ts +58 -0
  19. package/backend/lib/database/migrations/007_create_stream_states_table.ts +41 -0
  20. package/backend/lib/database/migrations/008_create_message_snapshots_table.ts +62 -0
  21. package/backend/lib/database/migrations/009_add_delta_snapshot_fields.ts +41 -0
  22. package/backend/lib/database/migrations/010_add_soft_delete_and_branch_support.ts +70 -0
  23. package/backend/lib/database/migrations/011_git_like_commit_graph.ts +156 -0
  24. package/backend/lib/database/migrations/012_add_file_change_statistics.ts +41 -0
  25. package/backend/lib/database/migrations/013_checkpoint_tree_state.ts +118 -0
  26. package/backend/lib/database/migrations/014_add_engine_to_sessions.ts +18 -0
  27. package/backend/lib/database/migrations/015_add_model_to_sessions.ts +18 -0
  28. package/backend/lib/database/migrations/016_create_user_projects_table.ts +34 -0
  29. package/backend/lib/database/migrations/017_add_current_session_to_user_projects.ts +32 -0
  30. package/backend/lib/database/migrations/018_create_claude_accounts_table.ts +24 -0
  31. package/backend/lib/database/migrations/019_add_claude_account_to_sessions.ts +18 -0
  32. package/backend/lib/database/migrations/020_add_snapshot_tree_hash.ts +32 -0
  33. package/backend/lib/database/migrations/021_drop_prompt_templates_table.ts +33 -0
  34. package/backend/lib/database/migrations/index.ts +154 -0
  35. package/backend/lib/database/queries/checkpoint-queries.ts +87 -0
  36. package/backend/lib/database/queries/engine-queries.ts +75 -0
  37. package/backend/lib/database/queries/index.ts +9 -0
  38. package/backend/lib/database/queries/message-queries.ts +472 -0
  39. package/backend/lib/database/queries/project-queries.ts +117 -0
  40. package/backend/lib/database/queries/session-queries.ts +271 -0
  41. package/backend/lib/database/queries/settings-queries.ts +34 -0
  42. package/backend/lib/database/queries/snapshot-queries.ts +326 -0
  43. package/backend/lib/database/queries/utils-queries.ts +59 -0
  44. package/backend/lib/database/seeders/index.ts +13 -0
  45. package/backend/lib/database/seeders/settings_seeder.ts +84 -0
  46. package/backend/lib/database/utils/connection.ts +174 -0
  47. package/backend/lib/database/utils/index.ts +4 -0
  48. package/backend/lib/database/utils/migration-runner.ts +118 -0
  49. package/backend/lib/database/utils/seeder-runner.ts +121 -0
  50. package/backend/lib/engine/adapters/claude/environment.ts +164 -0
  51. package/backend/lib/engine/adapters/claude/error-handler.ts +60 -0
  52. package/backend/lib/engine/adapters/claude/index.ts +1 -0
  53. package/backend/lib/engine/adapters/claude/path-utils.ts +38 -0
  54. package/backend/lib/engine/adapters/claude/stream.ts +177 -0
  55. package/backend/lib/engine/adapters/opencode/index.ts +2 -0
  56. package/backend/lib/engine/adapters/opencode/message-converter.ts +862 -0
  57. package/backend/lib/engine/adapters/opencode/server.ts +104 -0
  58. package/backend/lib/engine/adapters/opencode/stream.ts +755 -0
  59. package/backend/lib/engine/index.ts +196 -0
  60. package/backend/lib/engine/types.ts +58 -0
  61. package/backend/lib/files/file-operations.ts +478 -0
  62. package/backend/lib/files/file-reading.ts +308 -0
  63. package/backend/lib/files/file-watcher.ts +383 -0
  64. package/backend/lib/files/path-browsing.ts +382 -0
  65. package/backend/lib/git/git-executor.ts +88 -0
  66. package/backend/lib/git/git-parser.ts +411 -0
  67. package/backend/lib/git/git-service.ts +505 -0
  68. package/backend/lib/mcp/README.md +1144 -0
  69. package/backend/lib/mcp/config.ts +316 -0
  70. package/backend/lib/mcp/index.ts +35 -0
  71. package/backend/lib/mcp/project-context.ts +236 -0
  72. package/backend/lib/mcp/servers/browser-automation/actions.ts +156 -0
  73. package/backend/lib/mcp/servers/browser-automation/browser.ts +419 -0
  74. package/backend/lib/mcp/servers/browser-automation/index.ts +791 -0
  75. package/backend/lib/mcp/servers/browser-automation/inspection.ts +501 -0
  76. package/backend/lib/mcp/servers/helper.ts +143 -0
  77. package/backend/lib/mcp/servers/index.ts +45 -0
  78. package/backend/lib/mcp/servers/weather/get-temperature.ts +56 -0
  79. package/backend/lib/mcp/servers/weather/index.ts +31 -0
  80. package/backend/lib/mcp/stdio-server.ts +103 -0
  81. package/backend/lib/mcp/types.ts +65 -0
  82. package/backend/lib/preview/browser/browser-audio-capture.ts +86 -0
  83. package/backend/lib/preview/browser/browser-console-manager.ts +263 -0
  84. package/backend/lib/preview/browser/browser-dialog-handler.ts +222 -0
  85. package/backend/lib/preview/browser/browser-interaction-handler.ts +421 -0
  86. package/backend/lib/preview/browser/browser-mcp-control.ts +415 -0
  87. package/backend/lib/preview/browser/browser-native-ui-handler.ts +512 -0
  88. package/backend/lib/preview/browser/browser-navigation-tracker.ts +104 -0
  89. package/backend/lib/preview/browser/browser-pool.ts +357 -0
  90. package/backend/lib/preview/browser/browser-preview-service.ts +882 -0
  91. package/backend/lib/preview/browser/browser-tab-manager.ts +935 -0
  92. package/backend/lib/preview/browser/browser-video-capture.ts +695 -0
  93. package/backend/lib/preview/browser/scripts/audio-stream.ts +292 -0
  94. package/backend/lib/preview/browser/scripts/cursor-tracking.ts +85 -0
  95. package/backend/lib/preview/browser/scripts/video-stream.ts +438 -0
  96. package/backend/lib/preview/browser/types.ts +359 -0
  97. package/backend/lib/preview/index.ts +24 -0
  98. package/backend/lib/project/index.ts +2 -0
  99. package/backend/lib/project/status-manager.ts +182 -0
  100. package/backend/lib/shared/index.ts +2 -0
  101. package/backend/lib/shared/port-utils.ts +25 -0
  102. package/backend/lib/shared/process-manager.ts +281 -0
  103. package/backend/lib/snapshot/blob-store.ts +227 -0
  104. package/backend/lib/snapshot/gitignore.ts +307 -0
  105. package/backend/lib/snapshot/helpers.ts +397 -0
  106. package/backend/lib/snapshot/snapshot-service.ts +483 -0
  107. package/backend/lib/terminal/helpers.ts +14 -0
  108. package/backend/lib/terminal/index.ts +8 -0
  109. package/backend/lib/terminal/pty-manager.ts +4 -0
  110. package/backend/lib/terminal/pty-session-manager.ts +387 -0
  111. package/backend/lib/terminal/shell-utils.ts +313 -0
  112. package/backend/lib/terminal/stream-manager.ts +293 -0
  113. package/backend/lib/tunnel/global-tunnel-manager.ts +243 -0
  114. package/backend/lib/tunnel/project-tunnel-manager.ts +311 -0
  115. package/backend/lib/user/helpers.ts +87 -0
  116. package/backend/lib/utils/ws.ts +944 -0
  117. package/backend/lib/vite-dev.ts +353 -0
  118. package/backend/middleware/cors.ts +15 -0
  119. package/backend/middleware/error-handler.ts +49 -0
  120. package/backend/middleware/logger.ts +9 -0
  121. package/backend/types/api.ts +24 -0
  122. package/backend/ws/README.md +1505 -0
  123. package/backend/ws/chat/background.ts +198 -0
  124. package/backend/ws/chat/index.ts +21 -0
  125. package/backend/ws/chat/stream.ts +707 -0
  126. package/backend/ws/engine/claude/accounts.ts +401 -0
  127. package/backend/ws/engine/claude/index.ts +13 -0
  128. package/backend/ws/engine/claude/status.ts +43 -0
  129. package/backend/ws/engine/index.ts +14 -0
  130. package/backend/ws/engine/opencode/index.ts +11 -0
  131. package/backend/ws/engine/opencode/status.ts +30 -0
  132. package/backend/ws/engine/utils.ts +36 -0
  133. package/backend/ws/files/index.ts +30 -0
  134. package/backend/ws/files/read.ts +189 -0
  135. package/backend/ws/files/search.ts +453 -0
  136. package/backend/ws/files/watch.ts +124 -0
  137. package/backend/ws/files/write.ts +143 -0
  138. package/backend/ws/git/branch.ts +106 -0
  139. package/backend/ws/git/commit.ts +39 -0
  140. package/backend/ws/git/conflict.ts +68 -0
  141. package/backend/ws/git/diff.ts +69 -0
  142. package/backend/ws/git/index.ts +24 -0
  143. package/backend/ws/git/log.ts +41 -0
  144. package/backend/ws/git/remote.ts +214 -0
  145. package/backend/ws/git/staging.ts +84 -0
  146. package/backend/ws/git/status.ts +90 -0
  147. package/backend/ws/index.ts +69 -0
  148. package/backend/ws/mcp/index.ts +61 -0
  149. package/backend/ws/messages/crud.ts +74 -0
  150. package/backend/ws/messages/index.ts +14 -0
  151. package/backend/ws/preview/browser/cleanup.ts +129 -0
  152. package/backend/ws/preview/browser/console.ts +114 -0
  153. package/backend/ws/preview/browser/interact.ts +513 -0
  154. package/backend/ws/preview/browser/mcp.ts +129 -0
  155. package/backend/ws/preview/browser/native-ui.ts +235 -0
  156. package/backend/ws/preview/browser/stats.ts +55 -0
  157. package/backend/ws/preview/browser/tab-info.ts +126 -0
  158. package/backend/ws/preview/browser/tab.ts +166 -0
  159. package/backend/ws/preview/browser/webcodecs.ts +293 -0
  160. package/backend/ws/preview/index.ts +146 -0
  161. package/backend/ws/projects/crud.ts +113 -0
  162. package/backend/ws/projects/index.ts +25 -0
  163. package/backend/ws/projects/presence.ts +46 -0
  164. package/backend/ws/projects/status.ts +116 -0
  165. package/backend/ws/sessions/crud.ts +327 -0
  166. package/backend/ws/sessions/index.ts +33 -0
  167. package/backend/ws/settings/crud.ts +112 -0
  168. package/backend/ws/settings/index.ts +14 -0
  169. package/backend/ws/snapshot/index.ts +17 -0
  170. package/backend/ws/snapshot/restore.ts +173 -0
  171. package/backend/ws/snapshot/timeline.ts +141 -0
  172. package/backend/ws/system/index.ts +14 -0
  173. package/backend/ws/system/operations.ts +49 -0
  174. package/backend/ws/terminal/index.ts +40 -0
  175. package/backend/ws/terminal/persistence.ts +153 -0
  176. package/backend/ws/terminal/session.ts +382 -0
  177. package/backend/ws/terminal/stream.ts +79 -0
  178. package/backend/ws/tunnel/index.ts +14 -0
  179. package/backend/ws/tunnel/operations.ts +91 -0
  180. package/backend/ws/types.ts +20 -0
  181. package/backend/ws/user/crud.ts +156 -0
  182. package/backend/ws/user/index.ts +14 -0
  183. package/bin/clopen.ts +307 -0
  184. package/bun.lock +1352 -0
  185. package/frontend/App.svelte +34 -0
  186. package/frontend/app.css +313 -0
  187. package/frontend/lib/app-environment.ts +10 -0
  188. package/frontend/lib/components/chat/ChatInterface.svelte +407 -0
  189. package/frontend/lib/components/chat/formatters/ErrorMessage.svelte +57 -0
  190. package/frontend/lib/components/chat/formatters/MessageFormatter.svelte +224 -0
  191. package/frontend/lib/components/chat/formatters/TextMessage.svelte +395 -0
  192. package/frontend/lib/components/chat/formatters/Tools.svelte +70 -0
  193. package/frontend/lib/components/chat/formatters/index.ts +3 -0
  194. package/frontend/lib/components/chat/input/ChatInput.svelte +421 -0
  195. package/frontend/lib/components/chat/input/components/ChatInputActions.svelte +78 -0
  196. package/frontend/lib/components/chat/input/components/DragDropOverlay.svelte +30 -0
  197. package/frontend/lib/components/chat/input/components/EditModeIndicator.svelte +33 -0
  198. package/frontend/lib/components/chat/input/components/EngineModelPicker.svelte +619 -0
  199. package/frontend/lib/components/chat/input/components/FileAttachmentPreview.svelte +48 -0
  200. package/frontend/lib/components/chat/input/components/LoadingIndicator.svelte +31 -0
  201. package/frontend/lib/components/chat/input/composables/use-animations.svelte.ts +201 -0
  202. package/frontend/lib/components/chat/input/composables/use-chat-actions.svelte.ts +148 -0
  203. package/frontend/lib/components/chat/input/composables/use-file-handling.svelte.ts +216 -0
  204. package/frontend/lib/components/chat/input/composables/use-input-state.svelte.ts +357 -0
  205. package/frontend/lib/components/chat/input/composables/use-textarea-resize.svelte.ts +57 -0
  206. package/frontend/lib/components/chat/message/ChatMessage.svelte +478 -0
  207. package/frontend/lib/components/chat/message/ChatMessages.svelte +541 -0
  208. package/frontend/lib/components/chat/message/DateSeparator.svelte +86 -0
  209. package/frontend/lib/components/chat/message/MessageBubble.svelte +86 -0
  210. package/frontend/lib/components/chat/message/MessageHeader.svelte +157 -0
  211. package/frontend/lib/components/chat/modal/DebugModal.svelte +59 -0
  212. package/frontend/lib/components/chat/modal/TokenUsageModal.svelte +124 -0
  213. package/frontend/lib/components/chat/shared/index.ts +2 -0
  214. package/frontend/lib/components/chat/shared/utils.ts +116 -0
  215. package/frontend/lib/components/chat/tools/BashOutputTool.svelte +35 -0
  216. package/frontend/lib/components/chat/tools/BashTool.svelte +46 -0
  217. package/frontend/lib/components/chat/tools/CustomMcpTool.svelte +139 -0
  218. package/frontend/lib/components/chat/tools/EditTool.svelte +48 -0
  219. package/frontend/lib/components/chat/tools/ExitPlanModeTool.svelte +32 -0
  220. package/frontend/lib/components/chat/tools/GlobTool.svelte +51 -0
  221. package/frontend/lib/components/chat/tools/GrepTool.svelte +90 -0
  222. package/frontend/lib/components/chat/tools/KillShellTool.svelte +26 -0
  223. package/frontend/lib/components/chat/tools/ListMcpResourcesTool.svelte +31 -0
  224. package/frontend/lib/components/chat/tools/NotebookEditTool.svelte +38 -0
  225. package/frontend/lib/components/chat/tools/ReadMcpResourceTool.svelte +34 -0
  226. package/frontend/lib/components/chat/tools/ReadTool.svelte +41 -0
  227. package/frontend/lib/components/chat/tools/TaskTool.svelte +64 -0
  228. package/frontend/lib/components/chat/tools/TodoWriteTool.svelte +75 -0
  229. package/frontend/lib/components/chat/tools/WebFetchTool.svelte +35 -0
  230. package/frontend/lib/components/chat/tools/WebSearchTool.svelte +84 -0
  231. package/frontend/lib/components/chat/tools/WriteTool.svelte +33 -0
  232. package/frontend/lib/components/chat/tools/components/CodeBlock.svelte +79 -0
  233. package/frontend/lib/components/chat/tools/components/DiffBlock.svelte +408 -0
  234. package/frontend/lib/components/chat/tools/components/FileHeader.svelte +45 -0
  235. package/frontend/lib/components/chat/tools/components/InfoLine.svelte +19 -0
  236. package/frontend/lib/components/chat/tools/components/StatsBadges.svelte +27 -0
  237. package/frontend/lib/components/chat/tools/components/TerminalCommand.svelte +54 -0
  238. package/frontend/lib/components/chat/tools/components/index.ts +7 -0
  239. package/frontend/lib/components/chat/tools/index.ts +26 -0
  240. package/frontend/lib/components/chat/widgets/FloatingTodoList.svelte +249 -0
  241. package/frontend/lib/components/chat/widgets/TokenUsage.svelte +78 -0
  242. package/frontend/lib/components/checkpoint/TimelineModal.svelte +391 -0
  243. package/frontend/lib/components/checkpoint/timeline/TimelineEdge.svelte +26 -0
  244. package/frontend/lib/components/checkpoint/timeline/TimelineGraph.svelte +87 -0
  245. package/frontend/lib/components/checkpoint/timeline/TimelineNode.svelte +108 -0
  246. package/frontend/lib/components/checkpoint/timeline/TimelineVersionGroup.svelte +59 -0
  247. package/frontend/lib/components/checkpoint/timeline/animation.ts +168 -0
  248. package/frontend/lib/components/checkpoint/timeline/config.ts +44 -0
  249. package/frontend/lib/components/checkpoint/timeline/graph-builder.ts +304 -0
  250. package/frontend/lib/components/checkpoint/timeline/types.ts +65 -0
  251. package/frontend/lib/components/checkpoint/timeline/utils.ts +53 -0
  252. package/frontend/lib/components/common/Alert.svelte +139 -0
  253. package/frontend/lib/components/common/AvatarBubble.svelte +56 -0
  254. package/frontend/lib/components/common/Button.svelte +71 -0
  255. package/frontend/lib/components/common/Card.svelte +102 -0
  256. package/frontend/lib/components/common/Checkbox.svelte +48 -0
  257. package/frontend/lib/components/common/Dialog.svelte +249 -0
  258. package/frontend/lib/components/common/FolderBrowser.svelte +843 -0
  259. package/frontend/lib/components/common/Icon.svelte +58 -0
  260. package/frontend/lib/components/common/Input.svelte +72 -0
  261. package/frontend/lib/components/common/Lightbox.svelte +233 -0
  262. package/frontend/lib/components/common/LoadingScreen.svelte +52 -0
  263. package/frontend/lib/components/common/LoadingSpinner.svelte +48 -0
  264. package/frontend/lib/components/common/Modal.svelte +177 -0
  265. package/frontend/lib/components/common/ModalProvider.svelte +28 -0
  266. package/frontend/lib/components/common/ModelSelector.svelte +110 -0
  267. package/frontend/lib/components/common/MonacoEditor.svelte +569 -0
  268. package/frontend/lib/components/common/NotificationToast.svelte +113 -0
  269. package/frontend/lib/components/common/PageTemplate.svelte +76 -0
  270. package/frontend/lib/components/common/ProjectUserAvatars.svelte +79 -0
  271. package/frontend/lib/components/common/Select.svelte +98 -0
  272. package/frontend/lib/components/common/Textarea.svelte +80 -0
  273. package/frontend/lib/components/common/ThemeToggle.svelte +44 -0
  274. package/frontend/lib/components/common/lucide-icons.ts +1642 -0
  275. package/frontend/lib/components/common/material-icons.ts +1082 -0
  276. package/frontend/lib/components/common/xterm/XTerm.svelte +796 -0
  277. package/frontend/lib/components/common/xterm/index.ts +16 -0
  278. package/frontend/lib/components/common/xterm/terminal-config.ts +68 -0
  279. package/frontend/lib/components/common/xterm/types.ts +31 -0
  280. package/frontend/lib/components/common/xterm/xterm-service.ts +353 -0
  281. package/frontend/lib/components/files/FileNode.svelte +384 -0
  282. package/frontend/lib/components/files/FileTree.svelte +681 -0
  283. package/frontend/lib/components/files/FileViewer.svelte +728 -0
  284. package/frontend/lib/components/files/SearchResults.svelte +303 -0
  285. package/frontend/lib/components/git/BranchManager.svelte +458 -0
  286. package/frontend/lib/components/git/ChangesSection.svelte +107 -0
  287. package/frontend/lib/components/git/CommitForm.svelte +76 -0
  288. package/frontend/lib/components/git/ConflictResolver.svelte +158 -0
  289. package/frontend/lib/components/git/DiffViewer.svelte +364 -0
  290. package/frontend/lib/components/git/FileChangeItem.svelte +97 -0
  291. package/frontend/lib/components/git/GitButton.svelte +33 -0
  292. package/frontend/lib/components/git/GitLog.svelte +361 -0
  293. package/frontend/lib/components/git/GitModal.svelte +80 -0
  294. package/frontend/lib/components/history/HistoryModal.svelte +563 -0
  295. package/frontend/lib/components/history/HistoryView.svelte +615 -0
  296. package/frontend/lib/components/index.ts +34 -0
  297. package/frontend/lib/components/preview/browser/BrowserPreview.svelte +549 -0
  298. package/frontend/lib/components/preview/browser/components/Canvas.svelte +1058 -0
  299. package/frontend/lib/components/preview/browser/components/ConsolePanel.svelte +757 -0
  300. package/frontend/lib/components/preview/browser/components/Container.svelte +450 -0
  301. package/frontend/lib/components/preview/browser/components/ContextMenu.svelte +236 -0
  302. package/frontend/lib/components/preview/browser/components/SelectDropdown.svelte +224 -0
  303. package/frontend/lib/components/preview/browser/components/Toolbar.svelte +339 -0
  304. package/frontend/lib/components/preview/browser/components/VirtualCursor.svelte +36 -0
  305. package/frontend/lib/components/preview/browser/core/cleanup.svelte.ts +155 -0
  306. package/frontend/lib/components/preview/browser/core/coordinator.svelte.ts +837 -0
  307. package/frontend/lib/components/preview/browser/core/interactions.svelte.ts +113 -0
  308. package/frontend/lib/components/preview/browser/core/mcp-handlers.svelte.ts +296 -0
  309. package/frontend/lib/components/preview/browser/core/native-ui-handlers.svelte.ts +391 -0
  310. package/frontend/lib/components/preview/browser/core/stream-handler.svelte.ts +231 -0
  311. package/frontend/lib/components/preview/browser/core/tab-manager.svelte.ts +210 -0
  312. package/frontend/lib/components/preview/browser/core/tab-operations.svelte.ts +239 -0
  313. package/frontend/lib/components/preview/index.ts +2 -0
  314. package/frontend/lib/components/settings/SettingsModal.svelte +235 -0
  315. package/frontend/lib/components/settings/SettingsView.svelte +36 -0
  316. package/frontend/lib/components/settings/appearance/AppearanceSettings.svelte +51 -0
  317. package/frontend/lib/components/settings/appearance/LayoutPresetSettings.svelte +160 -0
  318. package/frontend/lib/components/settings/appearance/LayoutPreview.svelte +76 -0
  319. package/frontend/lib/components/settings/engines/AIEnginesSettings.svelte +917 -0
  320. package/frontend/lib/components/settings/general/AdvancedSettings.svelte +187 -0
  321. package/frontend/lib/components/settings/general/DataManagementSettings.svelte +203 -0
  322. package/frontend/lib/components/settings/general/GeneralSettings.svelte +10 -0
  323. package/frontend/lib/components/settings/model/ModelSettings.svelte +357 -0
  324. package/frontend/lib/components/settings/notifications/NotificationSettings.svelte +205 -0
  325. package/frontend/lib/components/settings/user/UserSettings.svelte +197 -0
  326. package/frontend/lib/components/terminal/Terminal.svelte +368 -0
  327. package/frontend/lib/components/terminal/TerminalTabs.svelte +87 -0
  328. package/frontend/lib/components/terminal/TerminalView.svelte +55 -0
  329. package/frontend/lib/components/tunnel/TunnelActive.svelte +142 -0
  330. package/frontend/lib/components/tunnel/TunnelButton.svelte +54 -0
  331. package/frontend/lib/components/tunnel/TunnelInactive.svelte +284 -0
  332. package/frontend/lib/components/tunnel/TunnelModal.svelte +47 -0
  333. package/frontend/lib/components/tunnel/TunnelQRCode.svelte +49 -0
  334. package/frontend/lib/components/workspace/DesktopNavigator.svelte +382 -0
  335. package/frontend/lib/components/workspace/MobileNavigator.svelte +403 -0
  336. package/frontend/lib/components/workspace/PanelContainer.svelte +100 -0
  337. package/frontend/lib/components/workspace/PanelHeader.svelte +505 -0
  338. package/frontend/lib/components/workspace/ViewMenu.svelte +162 -0
  339. package/frontend/lib/components/workspace/WorkspaceLayout.svelte +169 -0
  340. package/frontend/lib/components/workspace/layout/DesktopLayout.svelte +15 -0
  341. package/frontend/lib/components/workspace/layout/MobileLayout.svelte +17 -0
  342. package/frontend/lib/components/workspace/layout/split-pane/Container.svelte +42 -0
  343. package/frontend/lib/components/workspace/layout/split-pane/Handle.svelte +85 -0
  344. package/frontend/lib/components/workspace/layout/split-pane/Layout.svelte +37 -0
  345. package/frontend/lib/components/workspace/panels/ChatPanel.svelte +274 -0
  346. package/frontend/lib/components/workspace/panels/FilesPanel.svelte +1261 -0
  347. package/frontend/lib/components/workspace/panels/GitPanel.svelte +1560 -0
  348. package/frontend/lib/components/workspace/panels/PreviewPanel.svelte +150 -0
  349. package/frontend/lib/components/workspace/panels/TerminalPanel.svelte +73 -0
  350. package/frontend/lib/constants/preview.ts +45 -0
  351. package/frontend/lib/services/chat/chat.service.ts +704 -0
  352. package/frontend/lib/services/chat/index.ts +7 -0
  353. package/frontend/lib/services/notification/global-stream-monitor.ts +86 -0
  354. package/frontend/lib/services/notification/index.ts +8 -0
  355. package/frontend/lib/services/notification/push.service.ts +144 -0
  356. package/frontend/lib/services/notification/sound.service.ts +127 -0
  357. package/frontend/lib/services/preview/browser/browser-console.service.ts +61 -0
  358. package/frontend/lib/services/preview/browser/browser-webcodecs.service.ts +1499 -0
  359. package/frontend/lib/services/preview/browser/mcp-integration.svelte.ts +67 -0
  360. package/frontend/lib/services/preview/index.ts +23 -0
  361. package/frontend/lib/services/project/index.ts +8 -0
  362. package/frontend/lib/services/project/status.service.ts +159 -0
  363. package/frontend/lib/services/snapshot/snapshot.service.ts +47 -0
  364. package/frontend/lib/services/terminal/background/index.ts +130 -0
  365. package/frontend/lib/services/terminal/background/session-restore.ts +274 -0
  366. package/frontend/lib/services/terminal/background/stream-manager.ts +286 -0
  367. package/frontend/lib/services/terminal/index.ts +14 -0
  368. package/frontend/lib/services/terminal/persistence.service.ts +260 -0
  369. package/frontend/lib/services/terminal/project.service.ts +953 -0
  370. package/frontend/lib/services/terminal/session.service.ts +364 -0
  371. package/frontend/lib/services/terminal/terminal.service.ts +369 -0
  372. package/frontend/lib/stores/core/app.svelte.ts +117 -0
  373. package/frontend/lib/stores/core/files.svelte.ts +73 -0
  374. package/frontend/lib/stores/core/presence.svelte.ts +48 -0
  375. package/frontend/lib/stores/core/projects.svelte.ts +317 -0
  376. package/frontend/lib/stores/core/sessions.svelte.ts +383 -0
  377. package/frontend/lib/stores/features/claude-accounts.svelte.ts +58 -0
  378. package/frontend/lib/stores/features/models.svelte.ts +89 -0
  379. package/frontend/lib/stores/features/settings.svelte.ts +87 -0
  380. package/frontend/lib/stores/features/terminal.svelte.ts +701 -0
  381. package/frontend/lib/stores/features/tunnel.svelte.ts +161 -0
  382. package/frontend/lib/stores/features/user.svelte.ts +96 -0
  383. package/frontend/lib/stores/ui/chat-input.svelte.ts +57 -0
  384. package/frontend/lib/stores/ui/chat-model.svelte.ts +61 -0
  385. package/frontend/lib/stores/ui/dialog.svelte.ts +59 -0
  386. package/frontend/lib/stores/ui/edit-mode.svelte.ts +214 -0
  387. package/frontend/lib/stores/ui/notification.svelte.ts +166 -0
  388. package/frontend/lib/stores/ui/settings-modal.svelte.ts +88 -0
  389. package/frontend/lib/stores/ui/theme.svelte.ts +179 -0
  390. package/frontend/lib/stores/ui/workspace.svelte.ts +754 -0
  391. package/frontend/lib/types/native-ui.ts +73 -0
  392. package/frontend/lib/utils/chat/date-separator.ts +39 -0
  393. package/frontend/lib/utils/chat/message-grouper.ts +219 -0
  394. package/frontend/lib/utils/chat/message-processor.ts +135 -0
  395. package/frontend/lib/utils/chat/tool-handler.ts +161 -0
  396. package/frontend/lib/utils/chat/virtual-scroll.svelte.ts +142 -0
  397. package/frontend/lib/utils/click-outside.ts +20 -0
  398. package/frontend/lib/utils/context-manager.ts +257 -0
  399. package/frontend/lib/utils/file-icon-mappings.ts +769 -0
  400. package/frontend/lib/utils/folder-icon-mappings.ts +1030 -0
  401. package/frontend/lib/utils/git-status.ts +68 -0
  402. package/frontend/lib/utils/platform.ts +113 -0
  403. package/frontend/lib/utils/port-check.ts +65 -0
  404. package/frontend/lib/utils/terminalFormatter.ts +207 -0
  405. package/frontend/lib/utils/theme.ts +6 -0
  406. package/frontend/lib/utils/tree-visualizer.ts +320 -0
  407. package/frontend/lib/utils/ws.ts +44 -0
  408. package/frontend/main.ts +13 -0
  409. package/index.html +70 -0
  410. package/package.json +111 -0
  411. package/scripts/generate-icons.ts +87 -0
  412. package/scripts/pre-publish-check.sh +142 -0
  413. package/scripts/setup-hooks.sh +134 -0
  414. package/scripts/validate-branch-name.sh +47 -0
  415. package/scripts/validate-commit-msg.sh +42 -0
  416. package/shared/constants/engines.ts +134 -0
  417. package/shared/types/database/connection.ts +16 -0
  418. package/shared/types/database/index.ts +6 -0
  419. package/shared/types/database/schema.ts +141 -0
  420. package/shared/types/engine/index.ts +45 -0
  421. package/shared/types/filesystem/index.ts +22 -0
  422. package/shared/types/git.ts +171 -0
  423. package/shared/types/messaging/index.ts +239 -0
  424. package/shared/types/messaging/tool.ts +526 -0
  425. package/shared/types/network/api.ts +18 -0
  426. package/shared/types/network/index.ts +5 -0
  427. package/shared/types/stores/app.ts +23 -0
  428. package/shared/types/stores/dialog.ts +21 -0
  429. package/shared/types/stores/index.ts +3 -0
  430. package/shared/types/stores/settings.ts +15 -0
  431. package/shared/types/terminal/index.ts +44 -0
  432. package/shared/types/ui/components.ts +61 -0
  433. package/shared/types/ui/icons.ts +23 -0
  434. package/shared/types/ui/index.ts +22 -0
  435. package/shared/types/ui/notifications.ts +14 -0
  436. package/shared/types/ui/theme.ts +12 -0
  437. package/shared/types/websocket/index.ts +43 -0
  438. package/shared/types/window.d.ts +13 -0
  439. package/shared/utils/anonymous-user.ts +168 -0
  440. package/shared/utils/async.ts +10 -0
  441. package/shared/utils/diff-calculator.ts +184 -0
  442. package/shared/utils/file-type-detection.ts +166 -0
  443. package/shared/utils/logger.ts +158 -0
  444. package/shared/utils/message-formatter.ts +79 -0
  445. package/shared/utils/path.ts +47 -0
  446. package/shared/utils/ws-client.ts +768 -0
  447. package/shared/utils/ws-server.ts +660 -0
  448. package/static/audio/notification.ogg +0 -0
  449. package/static/favicon.svg +8 -0
  450. package/static/fonts/dm-sans/dm-sans-italic-latin-ext.woff2 +0 -0
  451. package/static/fonts/dm-sans/dm-sans-italic-latin.woff2 +0 -0
  452. package/static/fonts/dm-sans/dm-sans-normal-latin-ext.woff2 +0 -0
  453. package/static/fonts/dm-sans/dm-sans-normal-latin.woff2 +0 -0
  454. package/static/fonts/dm-sans.css +96 -0
  455. package/svelte.config.js +20 -0
  456. 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';