@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,293 @@
1
+ /**
2
+ * Preview Streaming Handlers
3
+ *
4
+ * Handles video/audio streaming for ultra low-latency, low-bandwidth preview.
5
+ * Currently implemented using WebCodecs with DataChannel delivery.
6
+ * **PROJECT ISOLATION**: Uses project-specific BrowserPreviewService instances
7
+ */
8
+
9
+ import { createRouter } from '$shared/utils/ws-server';
10
+ import { t } from 'elysia';
11
+ import { browserPreviewServiceManager } from '$backend/lib/preview';
12
+ import { ws } from '$backend/lib/utils/ws';
13
+
14
+ export const streamPreviewHandler = createRouter()
15
+ // Start streaming
16
+ .http(
17
+ 'preview:browser-stream-start',
18
+ {
19
+ data: t.Object({}),
20
+ response: t.Object({
21
+ success: t.Boolean(),
22
+ message: t.Optional(t.String()),
23
+ offer: t.Optional(
24
+ t.Object({
25
+ type: t.String(),
26
+ sdp: t.Optional(t.String())
27
+ })
28
+ )
29
+ })
30
+ },
31
+ async ({ data, conn }) => {
32
+ const projectId = ws.getProjectId(conn);
33
+
34
+ // Get project-specific preview service
35
+ const previewService = browserPreviewServiceManager.getService(projectId);
36
+
37
+ const tab = previewService.getActiveTab();
38
+ if (!tab) {
39
+ throw new Error('No active tab');
40
+ }
41
+
42
+ const sessionId = tab.id;
43
+
44
+ // Verify session exists
45
+ if (!previewService.isValidTab(sessionId)) {
46
+ throw new Error('Preview session not found or invalid');
47
+ }
48
+
49
+ // Start WebCodecs streaming
50
+ const started = await previewService.startWebCodecsStreaming(sessionId);
51
+
52
+ if (!started) {
53
+ throw new Error('Failed to start WebCodecs streaming');
54
+ }
55
+
56
+ // Get offer from headless browser
57
+ const offer = await previewService.getWebCodecsOffer(sessionId);
58
+
59
+ return {
60
+ success: true,
61
+ message: 'WebCodecs streaming started',
62
+ offer: offer
63
+ ? {
64
+ type: offer.type as string,
65
+ sdp: offer.sdp
66
+ }
67
+ : undefined
68
+ };
69
+ }
70
+ )
71
+
72
+ // Get SDP offer from headless browser
73
+ .http(
74
+ 'preview:browser-stream-offer',
75
+ {
76
+ data: t.Object({}),
77
+ response: t.Object({
78
+ success: t.Boolean(),
79
+ offer: t.Optional(
80
+ t.Object({
81
+ type: t.String(),
82
+ sdp: t.Optional(t.String())
83
+ })
84
+ )
85
+ })
86
+ },
87
+ async ({ data, conn }) => {
88
+ const projectId = ws.getProjectId(conn);
89
+
90
+ // Get project-specific preview service
91
+ const previewService = browserPreviewServiceManager.getService(projectId);
92
+
93
+ const tab = previewService.getActiveTab();
94
+ if (!tab) {
95
+ throw new Error('No active tab');
96
+ }
97
+
98
+ const offer = await previewService.getWebCodecsOffer(tab.id);
99
+
100
+ return {
101
+ success: !!offer,
102
+ offer: offer
103
+ ? {
104
+ type: offer.type as string,
105
+ sdp: offer.sdp
106
+ }
107
+ : undefined
108
+ };
109
+ }
110
+ )
111
+
112
+ // Handle SDP answer from client
113
+ .http(
114
+ 'preview:browser-stream-answer',
115
+ {
116
+ data: t.Object({
117
+ answer: t.Object({
118
+ type: t.String(),
119
+ sdp: t.Optional(t.String())
120
+ })
121
+ }),
122
+ response: t.Object({
123
+ success: t.Boolean()
124
+ })
125
+ },
126
+ async ({ data, conn }) => {
127
+ const projectId = ws.getProjectId(conn);
128
+
129
+ // Get project-specific preview service
130
+ const previewService = browserPreviewServiceManager.getService(projectId);
131
+
132
+ const tab = previewService.getActiveTab();
133
+ if (!tab) {
134
+ throw new Error('No active tab');
135
+ }
136
+
137
+ const { answer } = data;
138
+ const success = await previewService.handleWebCodecsAnswer(tab.id, answer as RTCSessionDescriptionInit);
139
+
140
+ return { success };
141
+ }
142
+ )
143
+
144
+ // Exchange ICE candidates
145
+ .http(
146
+ 'preview:browser-stream-ice',
147
+ {
148
+ data: t.Object({
149
+ candidate: t.Object({
150
+ candidate: t.Optional(t.String()),
151
+ sdpMid: t.Optional(t.Union([t.String(), t.Null()])),
152
+ sdpMLineIndex: t.Optional(t.Union([t.Number(), t.Null()]))
153
+ })
154
+ }),
155
+ response: t.Object({
156
+ success: t.Boolean()
157
+ })
158
+ },
159
+ async ({ data, conn }) => {
160
+ const projectId = ws.getProjectId(conn);
161
+
162
+ // Get project-specific preview service
163
+ const previewService = browserPreviewServiceManager.getService(projectId);
164
+
165
+ const tab = previewService.getActiveTab();
166
+ if (!tab) {
167
+ throw new Error('No active tab');
168
+ }
169
+
170
+ const { candidate } = data;
171
+ const success = await previewService.addWebCodecsIceCandidate(tab.id, candidate as RTCIceCandidateInit);
172
+
173
+ return { success };
174
+ }
175
+ )
176
+
177
+ // Stop streaming
178
+ .http(
179
+ 'preview:browser-stream-stop',
180
+ {
181
+ data: t.Object({}),
182
+ response: t.Object({
183
+ success: t.Boolean()
184
+ })
185
+ },
186
+ async ({ data, conn }) => {
187
+ const projectId = ws.getProjectId(conn);
188
+
189
+ // Get project-specific preview service
190
+ const previewService = browserPreviewServiceManager.getService(projectId);
191
+
192
+ const tab = previewService.getActiveTab();
193
+ if (!tab) {
194
+ throw new Error('No active tab');
195
+ }
196
+
197
+ await previewService.stopWebCodecsStreaming(tab.id);
198
+
199
+ return { success: true };
200
+ }
201
+ )
202
+
203
+ // Server → Client: ICE candidate from headless browser
204
+ .emit(
205
+ 'preview:browser-stream-ice',
206
+ t.Object({
207
+ sessionId: t.String(), // Internal session ID (kept for routing)
208
+ candidate: t.Object({
209
+ candidate: t.Optional(t.String()),
210
+ sdpMid: t.Optional(t.Union([t.String(), t.Null()])),
211
+ sdpMLineIndex: t.Optional(t.Union([t.Number(), t.Null()]))
212
+ }),
213
+ from: t.String() // 'headless' or 'client'
214
+ })
215
+ )
216
+
217
+ // Server → Client: Connection state update
218
+ .emit(
219
+ 'preview:browser-stream-state',
220
+ t.Object({
221
+ sessionId: t.String(), // Internal session ID (kept for routing)
222
+ state: t.String()
223
+ })
224
+ )
225
+
226
+ // Server → Client: Cursor style update
227
+ .emit(
228
+ 'preview:browser-cursor-change',
229
+ t.Object({
230
+ sessionId: t.String(), // Internal session ID (kept for routing)
231
+ cursor: t.String()
232
+ })
233
+ )
234
+
235
+ // Server → Client: Navigation started (loading)
236
+ .emit(
237
+ 'preview:browser-navigation-loading',
238
+ t.Object({
239
+ sessionId: t.String(),
240
+ type: t.String(),
241
+ url: t.String(),
242
+ timestamp: t.Number()
243
+ })
244
+ )
245
+
246
+ // Server → Client: Navigation completed
247
+ .emit(
248
+ 'preview:browser-navigation',
249
+ t.Object({
250
+ sessionId: t.String(),
251
+ type: t.String(),
252
+ url: t.String(),
253
+ timestamp: t.Number()
254
+ })
255
+ );
256
+
257
+ // Setup event forwarding from preview service to WebSocket
258
+ // This needs to be done per-project service instance
259
+ // We'll set up a helper function that the service manager can call
260
+
261
+ /**
262
+ * Setup event forwarding for a preview service instance
263
+ * Should be called when a new service is created
264
+ */
265
+ export function setupEventForwarding(previewService: any, projectId: string) {
266
+ previewService.on('webcodecs-ice-candidate', (data: { sessionId: string; candidate: RTCIceCandidateInit; from: string }) => {
267
+ ws.emit.project(projectId, 'preview:browser-stream-ice', {
268
+ sessionId: data.sessionId,
269
+ candidate: data.candidate,
270
+ from: data.from
271
+ });
272
+ });
273
+
274
+ previewService.on('webcodecs-connection-state', (data: { sessionId: string; state: string }) => {
275
+ ws.emit.project(projectId, 'preview:browser-stream-state', data);
276
+ });
277
+
278
+ previewService.on('cursor-change', (data: { sessionId: string; cursor: string }) => {
279
+ ws.emit.project(projectId, 'preview:browser-cursor-change', data);
280
+ });
281
+
282
+ // Forward navigation events
283
+ previewService.on('preview:browser-navigation-loading', (data: { sessionId: string; type: string; url: string; timestamp: number }) => {
284
+ ws.emit.project(projectId, 'preview:browser-navigation-loading', data);
285
+ });
286
+
287
+ previewService.on('preview:browser-navigation', (data: { sessionId: string; type: string; url: string; timestamp: number }) => {
288
+ ws.emit.project(projectId, 'preview:browser-navigation', data);
289
+ });
290
+ }
291
+
292
+ // Note: Event forwarding is now set up per-project in BrowserPreviewService constructor
293
+ // via the setupProjectEventForwarding method
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Preview Router
3
+ *
4
+ * Combines all preview WebSocket handlers into a single router.
5
+ *
6
+ * Tab-centric architecture - all operations work with browser tabs.
7
+ *
8
+ * Structure:
9
+ * - tab.ts: Tab lifecycle operations (open, navigate, close)
10
+ * - interact.ts: Mouse/keyboard interaction handlers
11
+ * - tab-info.ts: Tab information endpoints
12
+ * - stats.ts: Streaming statistics endpoints
13
+ * - console.ts: Console operations (get, clear, execute, toggle)
14
+ * - cleanup.ts: Admin cleanup endpoints (status, perform)
15
+ * - webcodecs.ts: WebCodecs streaming handlers
16
+ * - native-ui.ts: Native UI handlers (dialogs, print, select, context menu)
17
+ * - mcp.ts: MCP tab coordination response handlers
18
+ *
19
+ * Available endpoints:
20
+ * - preview:browser-tab-open - Open new browser tab (with optional URL)
21
+ * - preview:browser-tab-close - Close browser tab
22
+ * - preview:browser-tab-navigate - Navigate tab to new URL
23
+ * - preview:browser-interact - Execute mouse/keyboard interactions
24
+ * - preview:browser-tab-info - Get tab information
25
+ * - preview:browser-tab-stats - Get streaming statistics
26
+ * - preview:browser-console-get - Get console logs
27
+ * - preview:browser-console-clear - Clear console logs
28
+ * - preview:browser-console-execute - Execute console command
29
+ * - preview:browser-console-toggle - Toggle console logging
30
+ * - preview:browser-cleanup-status - Get cleanup status
31
+ * - preview:browser-cleanup-perform - Perform cleanup
32
+ * - preview:browser-stream-start - Start streaming
33
+ * - preview:browser-stream-offer - Get stream offer
34
+ * - preview:browser-stream-answer - Send stream answer
35
+ * - preview:browser-stream-ice - Exchange ICE candidates
36
+ * - preview:browser-stream-stop - Stop streaming
37
+ */
38
+
39
+ import { t } from 'elysia';
40
+ import { createRouter } from '$shared/utils/ws-server';
41
+ import { tabPreviewHandler } from './browser/tab';
42
+ import { interactPreviewHandler } from './browser/interact';
43
+ import { tabInfoPreviewHandler } from './browser/tab-info';
44
+ import { statsPreviewHandler } from './browser/stats';
45
+ import { consolePreviewHandler } from './browser/console';
46
+ import { cleanupPreviewHandler } from './browser/cleanup';
47
+ import { streamPreviewHandler } from './browser/webcodecs';
48
+ import { nativeUIPreviewHandler } from './browser/native-ui';
49
+ import { mcpPreviewHandler } from './browser/mcp';
50
+
51
+ export const previewRouter = createRouter()
52
+ .merge(tabPreviewHandler)
53
+ .merge(interactPreviewHandler)
54
+ .merge(tabInfoPreviewHandler)
55
+ .merge(statsPreviewHandler)
56
+ .merge(consolePreviewHandler)
57
+ .merge(cleanupPreviewHandler)
58
+ .merge(streamPreviewHandler)
59
+ .merge(nativeUIPreviewHandler)
60
+ .merge(mcpPreviewHandler)
61
+ // Server-emitted events (for type safety)
62
+ .emit('preview:browser-tab-opened', t.Object({
63
+ tabId: t.String(),
64
+ url: t.String(),
65
+ title: t.String(),
66
+ isActive: t.Boolean(),
67
+ timestamp: t.Number()
68
+ }))
69
+ .emit('preview:browser-tab-closed', t.Object({
70
+ tabId: t.String(),
71
+ newActiveTabId: t.Union([t.String(), t.Null()]),
72
+ timestamp: t.Number()
73
+ }))
74
+ .emit('preview:browser-tab-switched', t.Object({
75
+ previousTabId: t.String(),
76
+ newTabId: t.String(),
77
+ timestamp: t.Number()
78
+ }))
79
+ .emit('preview:browser-tab-navigated', t.Object({
80
+ tabId: t.String(),
81
+ url: t.String(),
82
+ title: t.String(),
83
+ timestamp: t.Number()
84
+ }))
85
+ .emit('preview:browser-console-message', t.Object({
86
+ sessionId: t.String(),
87
+ message: t.Object({
88
+ id: t.String(),
89
+ type: t.Union([
90
+ t.Literal('log'),
91
+ t.Literal('info'),
92
+ t.Literal('warn'),
93
+ t.Literal('error'),
94
+ t.Literal('debug'),
95
+ t.Literal('trace'),
96
+ t.Literal('clear')
97
+ ]),
98
+ text: t.String(),
99
+ args: t.Optional(t.Array(t.Any())),
100
+ location: t.Optional(t.Object({
101
+ url: t.String(),
102
+ lineNumber: t.Number(),
103
+ columnNumber: t.Number()
104
+ })),
105
+ stackTrace: t.Optional(t.String()),
106
+ timestamp: t.Number()
107
+ })
108
+ }))
109
+ .emit('preview:browser-console-clear', t.Object({
110
+ sessionId: t.String(),
111
+ timestamp: t.Number()
112
+ }))
113
+ .emit('preview:browser-new-window', t.Object({
114
+ tabId: t.String(),
115
+ url: t.String(),
116
+ timestamp: t.Number()
117
+ }))
118
+ // MCP control events
119
+ .emit('preview:browser-mcp-control-start', t.Object({
120
+ browserSessionId: t.String(),
121
+ mcpSessionId: t.Optional(t.String()),
122
+ timestamp: t.Number()
123
+ }))
124
+ .emit('preview:browser-mcp-control-end', t.Object({
125
+ browserSessionId: t.String(),
126
+ timestamp: t.Number()
127
+ }))
128
+ .emit('preview:browser-mcp-cursor-position', t.Object({
129
+ sessionId: t.String(),
130
+ x: t.Number(),
131
+ y: t.Number(),
132
+ timestamp: t.Number(),
133
+ source: t.Literal('mcp')
134
+ }))
135
+ .emit('preview:browser-mcp-cursor-click', t.Object({
136
+ sessionId: t.String(),
137
+ x: t.Number(),
138
+ y: t.Number(),
139
+ timestamp: t.Number(),
140
+ source: t.Literal('mcp')
141
+ }))
142
+ .emit('preview:browser-mcp-test-completed', t.Object({
143
+ sessionId: t.String(),
144
+ timestamp: t.Number(),
145
+ source: t.Literal('mcp')
146
+ }));
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Projects CRUD Operations
3
+ *
4
+ * HTTP endpoints for project management:
5
+ * - List all projects (per-user)
6
+ * - Create new project (or join existing)
7
+ * - Get project by ID
8
+ * - Update project info
9
+ * - Delete project (remove user association, cleanup if orphaned)
10
+ */
11
+
12
+ import { t } from 'elysia';
13
+ import { createRouter } from '$shared/utils/ws-server';
14
+ import { initializeDatabase } from '../../lib/database';
15
+ import { projectQueries } from '../../lib/database/queries';
16
+ import { ws } from '$backend/lib/utils/ws';
17
+
18
+ export const crudHandler = createRouter()
19
+ // List all projects for the current user
20
+ .http('projects:list', {
21
+ data: t.Object({}),
22
+ response: t.Array(t.Any())
23
+ }, async ({ conn }) => {
24
+ await initializeDatabase();
25
+ const userId = ws.getUserId(conn);
26
+ const projects = projectQueries.getAllForUser(userId);
27
+ return projects;
28
+ })
29
+
30
+ // Create new project (or join existing by path)
31
+ .http('projects:create', {
32
+ data: t.Object({
33
+ name: t.String({ minLength: 1 }),
34
+ path: t.String({ minLength: 1 })
35
+ }),
36
+ response: t.Any()
37
+ }, async ({ data, conn }) => {
38
+ await initializeDatabase();
39
+ const userId = ws.getUserId(conn);
40
+ const { name, path } = data;
41
+
42
+ // Check if project with this path already exists
43
+ const existing = projectQueries.getByPath(path);
44
+ if (existing) {
45
+ // Project exists - just add user association (join)
46
+ projectQueries.addUserProject(userId, existing.id);
47
+ return existing;
48
+ }
49
+
50
+ const now = new Date().toISOString();
51
+ const project = projectQueries.create({
52
+ name,
53
+ path,
54
+ created_at: now,
55
+ last_opened_at: now
56
+ });
57
+
58
+ // Associate the project with the creating user
59
+ projectQueries.addUserProject(userId, project.id);
60
+
61
+ return project;
62
+ })
63
+
64
+ // Get project by ID
65
+ .http('projects:get', {
66
+ data: t.Object({
67
+ id: t.String({ minLength: 1 })
68
+ }),
69
+ response: t.Any()
70
+ }, async ({ data }) => {
71
+ const project = projectQueries.getById(data.id);
72
+
73
+ if (!project) {
74
+ throw new Error('Project not found');
75
+ }
76
+
77
+ // Update last_opened_at when getting project
78
+ projectQueries.updateLastOpened(data.id);
79
+ const updatedProject = projectQueries.getById(data.id);
80
+
81
+ return updatedProject;
82
+ })
83
+
84
+ // Delete project (remove user association, cleanup if orphaned)
85
+ .http('projects:delete', {
86
+ data: t.Object({
87
+ id: t.String({ minLength: 1 })
88
+ }),
89
+ response: t.Object({
90
+ id: t.String(),
91
+ deleted: t.Boolean()
92
+ })
93
+ }, async ({ data, conn }) => {
94
+ const userId = ws.getUserId(conn);
95
+ const project = projectQueries.getById(data.id);
96
+ if (!project) {
97
+ throw new Error('Project not found');
98
+ }
99
+
100
+ // Remove user's association with the project
101
+ projectQueries.removeUserProject(userId, data.id);
102
+
103
+ // If no more users are associated, delete the project entirely
104
+ const remainingUsers = projectQueries.getUserCountForProject(data.id);
105
+ if (remainingUsers === 0) {
106
+ projectQueries.delete(data.id);
107
+ }
108
+
109
+ return {
110
+ id: data.id,
111
+ deleted: true
112
+ };
113
+ });
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Projects Router
3
+ *
4
+ * Combines all project WebSocket handlers into a single router.
5
+ *
6
+ * Structure:
7
+ * - crud.ts: HTTP endpoints for CRUD operations (list, create, get, update, delete)
8
+ * - status.ts: Real-time status updates and watching (get-status, watch, unwatch, events)
9
+ * - presence.ts: User presence management (update-presence with broadcast)
10
+ */
11
+
12
+ import { createRouter } from '$shared/utils/ws-server';
13
+ import { crudHandler } from './crud';
14
+ import { statusHandler } from './status';
15
+ import { presenceHandler } from './presence';
16
+
17
+ export const projectsRouter = createRouter()
18
+ // CRUD Operations (HTTP)
19
+ .merge(crudHandler)
20
+
21
+ // Status & Watching (HTTP + Events)
22
+ .merge(statusHandler)
23
+
24
+ // Presence Management (HTTP + Broadcast)
25
+ .merge(presenceHandler);
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Projects Presence Management
3
+ *
4
+ * Handles user presence updates:
5
+ * - projects:update-presence (HTTP) - Update user presence with broadcast
6
+ *
7
+ * Uses `projects:presence-updated` event (declared in status.ts)
8
+ */
9
+
10
+ import { t } from 'elysia';
11
+ import { createRouter } from '$shared/utils/ws-server';
12
+ import { updateUserPresence, getProjectStatusData } from '../../lib/project/status-manager';
13
+ import { streamManager } from '../../lib/chat/stream-manager';
14
+ import { ws } from '$backend/lib/utils/ws';
15
+ import { debug } from '$shared/utils/logger';
16
+
17
+ export const presenceHandler = createRouter()
18
+ .http('projects:update-presence', {
19
+ data: t.Object({
20
+ userName: t.String({ minLength: 1 }),
21
+ action: t.Optional(t.String())
22
+ }),
23
+ response: t.Any()
24
+ }, async ({ data, conn }) => {
25
+ const projectId = ws.getProjectId(conn);
26
+ const userId = ws.getUserId(conn);
27
+ const { userName, action } = data;
28
+
29
+ updateUserPresence(projectId, userId, userName, action || 'join');
30
+
31
+ try {
32
+ streamManager.cleanupProjectStreams(projectId);
33
+ } catch (cleanupError) {
34
+ debug.error('project', 'Error cleaning up project streams:', cleanupError);
35
+ }
36
+
37
+ // Broadcast full presence to all clients
38
+ const allStatuses = await getProjectStatusData();
39
+ ws.emit.global('projects:presence-updated', {
40
+ type: 'presence-updated',
41
+ timestamp: Date.now(),
42
+ data: allStatuses
43
+ });
44
+
45
+ return await getProjectStatusData(projectId);
46
+ });