@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,320 @@
1
+ /**
2
+ * Helper utilities for visualizing tree hierarchy structure
3
+ * Used for debugging and analyzing checkpoint/message tree structure
4
+ */
5
+
6
+ import type { DatabaseMessage } from '$shared/types/database/schema';
7
+ import { debug } from '$shared/utils/logger';
8
+
9
+ export interface TreeNode {
10
+ id: string;
11
+ messageText: string;
12
+ timestamp: string;
13
+ branchId: string | null;
14
+ parentId: string | null;
15
+ children: TreeNode[];
16
+ level: number; // Tree level (0 = main, 1 = branch from main, 2 = branch from branch, etc.)
17
+ }
18
+
19
+ /**
20
+ * Build tree structure from messages
21
+ */
22
+ export function buildTreeFromMessages(messages: DatabaseMessage[]): TreeNode[] {
23
+ const nodeMap = new Map<string, TreeNode>();
24
+ const roots: TreeNode[] = [];
25
+
26
+ // Create nodes
27
+ messages.forEach(msg => {
28
+ const sdkMessage = JSON.parse(msg.sdk_message);
29
+
30
+ // Only process user messages (checkpoints)
31
+ if (sdkMessage.type !== 'user') return;
32
+
33
+ const messageText = extractMessageText(sdkMessage);
34
+ if (!messageText.trim()) return;
35
+
36
+ nodeMap.set(msg.id, {
37
+ id: msg.id,
38
+ messageText: messageText.trim().slice(0, 50),
39
+ timestamp: msg.timestamp,
40
+ branchId: msg.branch_id || null,
41
+ parentId: msg.parent_message_id || null,
42
+ children: [],
43
+ level: 0
44
+ });
45
+ });
46
+
47
+ // Build tree structure
48
+ nodeMap.forEach(node => {
49
+ if (node.parentId && nodeMap.has(node.parentId)) {
50
+ const parent = nodeMap.get(node.parentId)!;
51
+ parent.children.push(node);
52
+ node.level = parent.level + (node.branchId ? 1 : 0);
53
+ } else {
54
+ roots.push(node);
55
+ }
56
+ });
57
+
58
+ // Sort children by timestamp
59
+ nodeMap.forEach(node => {
60
+ node.children.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
61
+ });
62
+
63
+ roots.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
64
+
65
+ return roots;
66
+ }
67
+
68
+ /**
69
+ * Extract message text from SDK message
70
+ */
71
+ function extractMessageText(sdkMessage: any): string {
72
+ if ('message' in sdkMessage && sdkMessage.message?.content) {
73
+ const content = sdkMessage.message.content;
74
+ if (typeof content === 'string') {
75
+ return content;
76
+ } else if (Array.isArray(content)) {
77
+ const textBlock = content.find((item: any) => typeof item === 'object' && 'text' in item);
78
+ if (textBlock && 'text' in textBlock) {
79
+ return textBlock.text;
80
+ }
81
+ }
82
+ }
83
+ return '';
84
+ }
85
+
86
+ /**
87
+ * Generate ASCII tree visualization
88
+ */
89
+ export function generateTreeASCII(roots: TreeNode[]): string {
90
+ const lines: string[] = [];
91
+
92
+ function traverse(node: TreeNode, prefix: string = '', isLast: boolean = true) {
93
+ // Node line
94
+ const connector = isLast ? '└─' : '├─';
95
+ const branchTag = node.branchId ? ` [branch:${node.branchId}]` : '';
96
+ const levelTag = ` (level ${node.level})`;
97
+ lines.push(`${prefix}${connector} ${node.messageText}${branchTag}${levelTag}`);
98
+
99
+ // Children
100
+ const childPrefix = prefix + (isLast ? ' ' : '│ ');
101
+ node.children.forEach((child, index) => {
102
+ const isLastChild = index === node.children.length - 1;
103
+ traverse(child, childPrefix, isLastChild);
104
+ });
105
+ }
106
+
107
+ roots.forEach((root, index) => {
108
+ const isLast = index === roots.length - 1;
109
+ traverse(root, '', isLast);
110
+ });
111
+
112
+ return lines.join('\n');
113
+ }
114
+
115
+ /**
116
+ * Generate compact list format (like your expected structure)
117
+ */
118
+ export function generateTreeList(roots: TreeNode[]): string {
119
+ const lines: string[] = [];
120
+
121
+ function traverse(node: TreeNode, indent: number = 0) {
122
+ const indentStr = ' '.repeat(indent);
123
+ const branchTag = node.branchId ? ` [branch:${node.branchId}]` : '';
124
+ lines.push(`${indentStr}- ${node.messageText}${branchTag}`);
125
+
126
+ node.children.forEach(child => {
127
+ // Increase indent if child has different branchId (is a branch)
128
+ const childIndent = child.branchId && child.branchId !== node.branchId
129
+ ? indent + 1
130
+ : indent;
131
+ traverse(child, childIndent);
132
+ });
133
+ }
134
+
135
+ roots.forEach(root => {
136
+ traverse(root, 0);
137
+ });
138
+
139
+ return lines.join('\n');
140
+ }
141
+
142
+ /**
143
+ * Log tree structure with detailed analysis
144
+ */
145
+ export function logTreeStructure(
146
+ sessionId: string,
147
+ messages: DatabaseMessage[],
148
+ currentHead: string | null,
149
+ label: string = 'Tree Structure'
150
+ ) {
151
+ debug.log('checkpoint', `${label} - Session: ${sessionId}`);
152
+ debug.log('checkpoint', `Current HEAD: ${currentHead || 'none'}`);
153
+ debug.log('checkpoint', `Total messages: ${messages.length}`);
154
+
155
+ const roots = buildTreeFromMessages(messages);
156
+
157
+ debug.log('checkpoint', 'Tree Structure (ASCII):');
158
+ debug.log('checkpoint', generateTreeASCII(roots));
159
+
160
+ debug.log('checkpoint', '\nTree Structure (List format):');
161
+ debug.log('checkpoint', generateTreeList(roots));
162
+
163
+ // Additional analysis
164
+ const mainTimelineCount = roots.length;
165
+ const branchCount = messages.filter(m => m.branch_id && m.branch_id !== '').length;
166
+ const uniqueBranches = new Set(messages.map(m => m.branch_id).filter(Boolean)).size;
167
+
168
+ debug.log('checkpoint', '\nTree Statistics:');
169
+ debug.log('checkpoint', `- Main timeline nodes: ${mainTimelineCount}`);
170
+ debug.log('checkpoint', `- Total branch messages: ${branchCount}`);
171
+ debug.log('checkpoint', `- Unique branches: ${uniqueBranches}`);
172
+ }
173
+
174
+ /**
175
+ * Log parent-child relationships
176
+ */
177
+ export function logParentChildRelationships(messages: DatabaseMessage[]) {
178
+ debug.log('checkpoint', '\nParent-Child Relationships:');
179
+
180
+ messages.forEach(msg => {
181
+ const sdkMessage = JSON.parse(msg.sdk_message);
182
+ if (sdkMessage.type !== 'user') return;
183
+
184
+ const messageText = extractMessageText(sdkMessage).trim().slice(0, 30);
185
+ const parentId = msg.parent_message_id || 'none';
186
+ const branchId = msg.branch_id || 'none';
187
+
188
+ debug.log('checkpoint', `${messageText}`);
189
+ debug.log('checkpoint', ` ID: ${msg.id}`);
190
+ debug.log('checkpoint', ` Parent: ${parentId}`);
191
+ debug.log('checkpoint', ` Branch: ${branchId}`);
192
+ debug.log('checkpoint', ` Timestamp: ${msg.timestamp}`);
193
+ debug.log('checkpoint', '');
194
+ });
195
+
196
+ debug.log('checkpoint', '-'.repeat(80) + '\n');
197
+ }
198
+
199
+ /**
200
+ * Validate tree structure and report issues
201
+ */
202
+ export function validateTreeStructure(
203
+ messages: DatabaseMessage[],
204
+ expectedStructure?: string
205
+ ): { valid: boolean; issues: string[] } {
206
+ const issues: string[] = [];
207
+ const messageMap = new Map(messages.map(m => [m.id, m]));
208
+
209
+ // Check for orphaned nodes (parent_id points to non-existent message)
210
+ messages.forEach(msg => {
211
+ if (msg.parent_message_id && !messageMap.has(msg.parent_message_id)) {
212
+ issues.push(`Message ${msg.id} has non-existent parent ${msg.parent_message_id}`);
213
+ }
214
+ });
215
+
216
+ // Check for circular references
217
+ const visited = new Set<string>();
218
+ const recursionStack = new Set<string>();
219
+
220
+ function detectCycle(msgId: string): boolean {
221
+ if (recursionStack.has(msgId)) {
222
+ issues.push(`Circular reference detected at message ${msgId}`);
223
+ return true;
224
+ }
225
+ if (visited.has(msgId)) return false;
226
+
227
+ visited.add(msgId);
228
+ recursionStack.add(msgId);
229
+
230
+ const msg = messageMap.get(msgId);
231
+ if (msg && msg.parent_message_id) {
232
+ detectCycle(msg.parent_message_id);
233
+ }
234
+
235
+ recursionStack.delete(msgId);
236
+ return false;
237
+ }
238
+
239
+ messages.forEach(msg => {
240
+ if (!visited.has(msg.id)) {
241
+ detectCycle(msg.id);
242
+ }
243
+ });
244
+
245
+ // Compare with expected structure if provided
246
+ if (expectedStructure) {
247
+ const roots = buildTreeFromMessages(messages);
248
+ const actualStructure = generateTreeList(roots);
249
+
250
+ // Normalize whitespace for comparison
251
+ const normalizedExpected = expectedStructure.trim().replace(/\s+/g, ' ');
252
+ const normalizedActual = actualStructure.trim().replace(/\s+/g, ' ');
253
+
254
+ if (normalizedExpected !== normalizedActual) {
255
+ issues.push('Tree structure does not match expected structure');
256
+ debug.log('checkpoint', '\nExpected structure:');
257
+ debug.log('checkpoint', expectedStructure);
258
+ debug.log('checkpoint', '\nActual structure:');
259
+ debug.log('checkpoint', actualStructure);
260
+ }
261
+ }
262
+
263
+ return {
264
+ valid: issues.length === 0,
265
+ issues
266
+ };
267
+ }
268
+
269
+ /**
270
+ * Compare two tree states and report differences
271
+ */
272
+ export function compareTreeStates(
273
+ beforeMessages: DatabaseMessage[],
274
+ afterMessages: DatabaseMessage[],
275
+ operationLabel: string
276
+ ) {
277
+ debug.log('checkpoint', `Tree State Comparison - ${operationLabel}`);
278
+
279
+ debug.log('checkpoint', 'BEFORE:');
280
+ const beforeRoots = buildTreeFromMessages(beforeMessages);
281
+ debug.log('checkpoint', generateTreeList(beforeRoots));
282
+
283
+ debug.log('checkpoint', '\nAFTER:');
284
+ const afterRoots = buildTreeFromMessages(afterMessages);
285
+ debug.log('checkpoint', generateTreeList(afterRoots));
286
+
287
+ // Analyze changes
288
+ const beforeIds = new Set(beforeMessages.map(m => m.id));
289
+ const afterIds = new Set(afterMessages.map(m => m.id));
290
+
291
+ const added = afterMessages.filter(m => !beforeIds.has(m.id));
292
+ const removed = beforeMessages.filter(m => !afterIds.has(m.id));
293
+
294
+ const modified = afterMessages.filter(m => {
295
+ const before = beforeMessages.find(bm => bm.id === m.id);
296
+ if (!before) return false;
297
+ return before.branch_id !== m.branch_id || before.parent_message_id !== m.parent_message_id;
298
+ });
299
+
300
+ debug.log('checkpoint', '\nChanges:');
301
+ debug.log('checkpoint', `- Added: ${added.length}`);
302
+ debug.log('checkpoint', `- Removed: ${removed.length}`);
303
+ debug.log('checkpoint', `- Modified: ${modified.length}`);
304
+
305
+ if (modified.length > 0) {
306
+ debug.log('checkpoint', '\nModified messages:');
307
+ modified.forEach(m => {
308
+ const before = beforeMessages.find(bm => bm.id === m.id)!;
309
+ debug.log('checkpoint', ` ${m.id}:`);
310
+ if (before.parent_message_id !== m.parent_message_id) {
311
+ debug.log('checkpoint', ` Parent: ${before.parent_message_id} → ${m.parent_message_id}`);
312
+ }
313
+ if (before.branch_id !== m.branch_id) {
314
+ debug.log('checkpoint', ` Branch: ${before.branch_id || 'none'} → ${m.branch_id || 'none'}`);
315
+ }
316
+ });
317
+ }
318
+
319
+ debug.log('checkpoint', `${'='.repeat(80)}\n`);
320
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * WebSocket Client Instance
3
+ * Provides a singleton WebSocket client for real-time communication
4
+ * with automatic user/project context synchronization
5
+ */
6
+
7
+ import { WSClient } from '$shared/utils/ws-client';
8
+ import type { WSAPI } from '$backend/ws';
9
+
10
+ /**
11
+ * Get WebSocket URL based on environment
12
+ */
13
+ function getWebSocketUrl(): string {
14
+ // Both dev and production: Use current host (Vite proxies /ws to backend in dev)
15
+ const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
16
+ const host = window.location.host;
17
+ return `${protocol}//${host}/ws`;
18
+ }
19
+
20
+ const ws = new WSClient<WSAPI>(getWebSocketUrl(), {
21
+ autoReconnect: true,
22
+ maxReconnectAttempts: 0, // Infinite reconnect
23
+ reconnectDelay: 1000,
24
+ maxReconnectDelay: 30000
25
+ });
26
+
27
+ // CRITICAL: Handle Vite HMR to prevent WebSocket connection accumulation
28
+ // Without this, each HMR update creates a new WSClient+connection without
29
+ // closing the old one, causing duplicate connections on the server
30
+ if (import.meta.hot) {
31
+ import.meta.hot.dispose(() => {
32
+ ws.disconnect();
33
+ });
34
+ }
35
+
36
+ // Close WebSocket cleanly on page unload (refresh, tab close, navigate away).
37
+ // Without this, the browser may keep the old connection's HTTP upgrade request
38
+ // as "pending" during the page transition, causing the loading indicator to
39
+ // spin indefinitely after a refresh.
40
+ window.addEventListener('beforeunload', () => {
41
+ ws.disconnect();
42
+ });
43
+
44
+ export default ws;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Clopen - SPA Entry Point
3
+ * Mounts the Svelte application to the DOM (Svelte 5)
4
+ */
5
+ import { mount } from 'svelte';
6
+ import './app.css';
7
+ import App from './App.svelte';
8
+
9
+ const app = mount(App, {
10
+ target: document.getElementById('app')!
11
+ });
12
+
13
+ export default app;
package/index.html ADDED
@@ -0,0 +1,70 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <link rel="icon" href="/favicon.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ <meta
8
+ name="description"
9
+ content="Clopen - Modern web UI for Claude Code & OpenCode with real browser preview, git management, multi-account support, file management, checkpoints, collaboration, and integrated terminal. Built with Bun and Svelte 5."
10
+ />
11
+ <meta name="theme-color" content="#0a0a0a" />
12
+ <title>Clopen</title>
13
+
14
+ <!-- DM Sans - Local self-hosted font -->
15
+ <link rel="stylesheet" href="/fonts/dm-sans.css">
16
+
17
+ <!-- Prevent FOUC (Flash of Unstyled Content) for theme -->
18
+ <script>
19
+ (function() {
20
+ // Check for saved theme preference
21
+ try {
22
+ const savedTheme = localStorage.getItem('claude-theme');
23
+ const isManualTheme = localStorage.getItem('claude-theme-manual') === 'true';
24
+
25
+ let isDark = false;
26
+
27
+ if (savedTheme && isManualTheme) {
28
+ // Use saved manual theme preference
29
+ const theme = JSON.parse(savedTheme);
30
+ isDark = theme.mode === 'dark';
31
+ } else {
32
+ // Follow system preference
33
+ isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
34
+ }
35
+
36
+ // Apply dark class immediately to prevent flash
37
+ if (isDark) {
38
+ document.documentElement.classList.add('dark');
39
+ } else {
40
+ document.documentElement.classList.remove('dark');
41
+ }
42
+
43
+ // Set color scheme for browser integration
44
+ document.documentElement.style.colorScheme = isDark ? 'dark' : 'light';
45
+
46
+ // Update meta theme-color for mobile browsers
47
+ const metaThemeColor = document.querySelector('meta[name="theme-color"]');
48
+ if (metaThemeColor) {
49
+ metaThemeColor.setAttribute('content', isDark ? '#0a0a0a' : '#ffffff');
50
+ }
51
+ } catch (e) {
52
+ // Fallback to system preference if anything fails
53
+ if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
54
+ document.documentElement.classList.add('dark');
55
+ document.documentElement.style.colorScheme = 'dark';
56
+ }
57
+ }
58
+ })();
59
+ </script>
60
+ </head>
61
+ <body
62
+ class="min-h-screen bg-white text-slate-900 dark:bg-slate-950 dark:text-slate-100 transition-colors duration-200"
63
+ >
64
+ <!-- App mount point -->
65
+ <div id="app"></div>
66
+
67
+ <!-- Vite entry point -->
68
+ <script type="module" src="/frontend/main.ts"></script>
69
+ </body>
70
+ </html>
package/package.json ADDED
@@ -0,0 +1,111 @@
1
+ {
2
+ "name": "@myrialabs/clopen",
3
+ "version": "0.0.1",
4
+ "description": "All-in-one web workspace for Claude Code & OpenCode — chat, terminal, git, browser preview, checkpoints, and real-time collaboration",
5
+ "author": "Myria Labs",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "bin": {
9
+ "clopen": "./bin/clopen.ts"
10
+ },
11
+ "main": "./bin/clopen.ts",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/myrialabs/clopen.git"
15
+ },
16
+ "homepage": "https://github.com/myrialabs/clopen#readme",
17
+ "bugs": {
18
+ "url": "https://github.com/myrialabs/clopen/issues"
19
+ },
20
+ "keywords": [
21
+ "claude",
22
+ "claude-code",
23
+ "opencode",
24
+ "ai",
25
+ "assistant",
26
+ "web-ui",
27
+ "bun",
28
+ "svelte",
29
+ "puppeteer",
30
+ "collaboration",
31
+ "terminal",
32
+ "browser-preview",
33
+ "file-management",
34
+ "file-editor",
35
+ "git",
36
+ "source-control",
37
+ "multi-account",
38
+ "anthropic",
39
+ "checkpoint",
40
+ "workspace",
41
+ "cloudflare-tunnel",
42
+ "mcp"
43
+ ],
44
+ "engines": {
45
+ "bun": ">=1.2.12"
46
+ },
47
+ "scripts": {
48
+ "dev": "bun --watch backend/index.ts",
49
+ "build": "vite build",
50
+ "start": "bun backend/index.ts",
51
+ "check": "svelte-check --tsconfig ./tsconfig.json",
52
+ "lint": "eslint .",
53
+ "lint:fix": "eslint . --fix",
54
+ "generate-icons": "bun scripts/generate-icons.ts"
55
+ },
56
+ "devDependencies": {
57
+ "@eslint/js": "^9.31.0",
58
+ "@sveltejs/vite-plugin-svelte": "^6.0.0",
59
+ "@tailwindcss/vite": "^4.1.11",
60
+ "@types/bun": "^1.2.18",
61
+ "@types/qrcode": "^1.5.6",
62
+ "@types/xterm": "^3.0.0",
63
+ "eslint": "^9.31.0",
64
+ "eslint-plugin-svelte": "^3.10.1",
65
+ "globals": "^16.3.0",
66
+ "svelte": "^5.0.0",
67
+ "svelte-check": "^4.0.0",
68
+ "tailwindcss": "^4.1.11",
69
+ "typescript": "^5.0.0",
70
+ "typescript-eslint": "^8.37.0",
71
+ "vite": "^7.0.4"
72
+ },
73
+ "dependencies": {
74
+ "@anthropic-ai/claude-agent-sdk": "^0.2.7",
75
+ "@anthropic-ai/sdk": "^0.62.0",
76
+ "@elysiajs/cors": "^1.4.0",
77
+ "@elysiajs/static": "^1.4.7",
78
+ "@iconify-json/lucide": "^1.2.57",
79
+ "@iconify-json/material-icon-theme": "^1.2.16",
80
+ "@modelcontextprotocol/sdk": "^1.26.0",
81
+ "@monaco-editor/loader": "^1.5.0",
82
+ "@opencode-ai/sdk": "^1.2.4",
83
+ "@tailwindcss/typography": "^0.5.16",
84
+ "@types/marked": "^5.0.2",
85
+ "@types/node": "^24.0.14",
86
+ "@xterm/addon-fit": "^0.10.0",
87
+ "@xterm/addon-web-links": "^0.11.0",
88
+ "bun-pty": "^0.4.2",
89
+ "canvas": "^3.1.2",
90
+ "chokidar": "^4.0.3",
91
+ "cloudflared": "^0.7.1",
92
+ "devtools-detector": "^2.0.23",
93
+ "elysia": "^1.4.19",
94
+ "eruda": "^3.4.3",
95
+ "file-type": "^21.0.0",
96
+ "is-text-path": "^3.0.0",
97
+ "marked": "^16.1.1",
98
+ "monaco-editor": "^0.52.2",
99
+ "nanoid": "^5.1.6",
100
+ "puppeteer": "^24.33.0",
101
+ "puppeteer-cluster": "^0.25.0",
102
+ "qrcode": "^1.5.4",
103
+ "sharp": "^0.34.3",
104
+ "werift": "^0.22.2",
105
+ "xterm": "^5.3.0"
106
+ },
107
+ "trustedDependencies": [
108
+ "cloudflared",
109
+ "puppeteer"
110
+ ]
111
+ }
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { join } from 'path';
4
+
5
+ async function generateLucideIcons() {
6
+ console.log('Generating Lucide icons...');
7
+
8
+ // Read all lucide icons data using Bun.file
9
+ const lucideJsonFile = Bun.file(join(process.cwd(), 'node_modules/@iconify-json/lucide/icons.json'));
10
+ const lucideData = await lucideJsonFile.json() as { icons: Record<string, any> };
11
+ const iconNames = Object.keys(lucideData.icons);
12
+
13
+ // Generate import statement
14
+ const imports = `import lucideIcons from '@iconify-json/lucide/icons.json';`;
15
+
16
+ // Generate registry entries for ALL icons
17
+ const registryEntries = iconNames.map(iconName => {
18
+ return `\t'lucide:${iconName}': icons['${iconName}'],`;
19
+ }).join('\n');
20
+
21
+ // Create the lucide-icons.ts file
22
+ const lucideIconsContent = `// AUTO-GENERATED FILE: All Lucide Icons (${iconNames.length} icons)
23
+ // Generated by generate-icons.ts
24
+ // DO NOT EDIT MANUALLY
25
+
26
+ ${imports}
27
+
28
+ // Type the icons object properly
29
+ const icons = lucideIcons.icons as Record<string, { body: string; width?: number; height?: number; top?: number }>;
30
+
31
+ export const lucideIconRegistry = {
32
+ ${registryEntries}
33
+ } as const;
34
+
35
+ export type LucideIconName = keyof typeof lucideIconRegistry;
36
+ `;
37
+
38
+ // Write the file using Bun.write
39
+ await Bun.write('src/lib/components/common/lucide-icons.ts', lucideIconsContent);
40
+ console.log(`Generated lucide-icons.ts with ${iconNames.length} icons`);
41
+ }
42
+
43
+ async function generateMaterialIcons() {
44
+ console.log('Generating Material Icon Theme icons...');
45
+
46
+ // Read all Material Icon Theme icons from the icons.json file using Bun.file
47
+ const iconsJsonFile = Bun.file(join(process.cwd(), 'node_modules/@iconify-json/material-icon-theme/icons.json'));
48
+ const iconsData = await iconsJsonFile.json() as { icons: Record<string, any> };
49
+ const iconNames = Object.keys(iconsData.icons);
50
+
51
+ // Generate import statements
52
+ const imports = `import materialIcons from '@iconify-json/material-icon-theme/icons.json';`;
53
+
54
+ // Generate registry entries
55
+ const registryEntries = iconNames.map(iconName => {
56
+ return `\t'material:${iconName}': icons['${iconName}'],`;
57
+ }).join('\n');
58
+
59
+ // Create the material-icons.ts file
60
+ const materialIconsContent = `// AUTO-GENERATED FILE: All Material Icon Theme Icons (${iconNames.length} icons)
61
+ // Generated by generate-icons.ts
62
+ // DO NOT EDIT MANUALLY
63
+
64
+ ${imports}
65
+
66
+ // Type the icons object properly
67
+ const icons = materialIcons.icons as Record<string, { body: string; width?: number; height?: number; top?: number }>;
68
+
69
+ // Registry mapping for Icon.svelte
70
+ export const materialIconRegistry = {
71
+ ${registryEntries}
72
+ } as const;
73
+
74
+ export type MaterialIconName = keyof typeof materialIconRegistry;
75
+ `;
76
+
77
+ // Write the file using Bun.write
78
+ await Bun.write('src/lib/components/common/material-icons.ts', materialIconsContent);
79
+ console.log(`Generated material-icons.ts with ${iconNames.length} icons`);
80
+ }
81
+
82
+ // Generate both icon sets
83
+ console.log('Starting icon generation...\n');
84
+ await generateLucideIcons();
85
+ console.log('');
86
+ await generateMaterialIcons();
87
+ console.log('\nIcon generation complete!');