@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,169 @@
1
+ <script lang="ts">
2
+ import { onMount, onDestroy } from 'svelte';
3
+ import { fade } from 'svelte/transition';
4
+ import { browser } from '$frontend/lib/app-environment';
5
+
6
+ // Stores
7
+ import {
8
+ workspaceState,
9
+ initializeWorkspace,
10
+ } from '$frontend/lib/stores/ui/workspace.svelte';
11
+ import { appState, setAppLoading, setAppInitialized, restoreLastView } from '$frontend/lib/stores/core/app.svelte';
12
+ import { projectState } from '$frontend/lib/stores/core/projects.svelte';
13
+ import { sessionState } from '$frontend/lib/stores/core/sessions.svelte';
14
+
15
+ // Components
16
+ import DesktopLayout from './layout/DesktopLayout.svelte';
17
+ import MobileLayout from './layout/MobileLayout.svelte';
18
+ import LoadingScreen from '$frontend/lib/components/common/LoadingScreen.svelte';
19
+ import ModalProvider from '$frontend/lib/components/common/ModalProvider.svelte';
20
+ import SettingsModal from '$frontend/lib/components/settings/SettingsModal.svelte';
21
+ import HistoryModal from '$frontend/lib/components/history/HistoryModal.svelte';
22
+
23
+ // Services
24
+ import { initializeTheme } from '$frontend/lib/utils/theme';
25
+ import { initializeStore } from '$frontend/lib/stores/core/app.svelte';
26
+ import { initializeProjects } from '$frontend/lib/stores/core/projects.svelte';
27
+ import { initializeSessions } from '$frontend/lib/stores/core/sessions.svelte';
28
+ import { initializeNotifications } from '$frontend/lib/stores/ui/notification.svelte';
29
+ import { applyServerSettings } from '$frontend/lib/stores/features/settings.svelte';
30
+ import { userStore } from '$frontend/lib/stores/features/user.svelte';
31
+ import { initPresence } from '$frontend/lib/stores/core/presence.svelte';
32
+ import ws from '$frontend/lib/utils/ws';
33
+ import { debug } from '$shared/utils/logger';
34
+
35
+ const { children } = $props();
36
+
37
+ // Responsive state
38
+ let isMobile = $state(false);
39
+ let windowWidth = $state(0);
40
+
41
+ // Chat History modal state
42
+ let showHistoryModal = $state(false);
43
+
44
+ function closeHistoryModal() {
45
+ showHistoryModal = false;
46
+ }
47
+
48
+ // Loading state
49
+ let loadingProgress = $state(0);
50
+ let loadingText = $state('Initializing Workspace...');
51
+
52
+ // Set progress directly — CSS transition in LoadingScreen handles smooth animation
53
+ function setProgress(value: number, text?: string) {
54
+ loadingProgress = value;
55
+ if (text) loadingText = text;
56
+ }
57
+
58
+ // Responsive handler
59
+ function handleResize() {
60
+ if (browser) {
61
+ windowWidth = window.innerWidth;
62
+ isMobile = windowWidth < 1024;
63
+ }
64
+ }
65
+
66
+ // Initialize
67
+ onMount(async () => {
68
+ handleResize();
69
+ window.addEventListener('resize', handleResize);
70
+
71
+ setAppLoading(true);
72
+
73
+ try {
74
+ // Step 1: Core initialization (theme, workspace, notifications — all sync/localStorage)
75
+ setProgress(10, 'Initializing core systems...');
76
+ initializeTheme();
77
+ initializeStore();
78
+ initializeNotifications();
79
+ initializeWorkspace();
80
+
81
+ // Step 2: Initialize user + wait for WebSocket in parallel
82
+ // userStore.initialize() reads localStorage (fast) and sets WS context locally.
83
+ // waitUntilConnected() waits for WS to connect and sync any pending context.
84
+ setProgress(20, 'Connecting...');
85
+ await Promise.all([
86
+ userStore.initialize(),
87
+ ws.waitUntilConnected(10000)
88
+ ]);
89
+
90
+ // Step 3: Restore user state from server
91
+ setProgress(30, 'Restoring state...');
92
+ let serverState: { currentProjectId: string | null; lastView: string | null; settings: any } | null = null;
93
+ try {
94
+ serverState = await ws.http('user:restore-state', {});
95
+ debug.log('workspace', 'Server state restored:', serverState);
96
+ } catch (err) {
97
+ debug.warn('workspace', 'Failed to restore server state, using defaults:', err);
98
+ }
99
+
100
+ // Step 4: Apply restored state + setup presence (sync operations)
101
+ setProgress(40);
102
+ if (serverState?.settings) {
103
+ applyServerSettings(serverState.settings);
104
+ }
105
+ restoreLastView(serverState?.lastView);
106
+ initPresence();
107
+
108
+ // Step 5: Load projects (with server-restored currentProjectId)
109
+ setProgress(50, 'Loading projects...');
110
+ await initializeProjects(serverState?.currentProjectId);
111
+
112
+ // Step 6: Load sessions
113
+ setProgress(70, 'Restoring sessions...');
114
+ await initializeSessions();
115
+
116
+ // Step 7: Ready
117
+ setProgress(100, 'Ready!');
118
+ } catch (error) {
119
+ debug.error('workspace', 'Initialization error:', error);
120
+ setProgress(100, 'Error during initialization');
121
+ } finally {
122
+ // Small delay for CSS transition to finish, then dismiss loading screen
123
+ setTimeout(() => {
124
+ setAppInitialized();
125
+ }, 100);
126
+ }
127
+ });
128
+
129
+ onDestroy(() => {
130
+ if (browser) {
131
+ window.removeEventListener('resize', handleResize);
132
+ }
133
+ });
134
+ </script>
135
+
136
+ <!-- Loading Screen -->
137
+ <LoadingScreen bind:isVisible={appState.isAppLoading} progress={loadingProgress} {loadingText} />
138
+
139
+ <!-- Main Workspace Layout -->
140
+ <div
141
+ class="h-screen w-screen overflow-hidden {isMobile ? 'bg-white/90 dark:bg-slate-900/98' : 'bg-slate-50 dark:bg-slate-900/70'} text-slate-900 dark:text-slate-100 font-sans"
142
+ >
143
+ <!-- Skip link for accessibility -->
144
+ <a
145
+ href="#main-content"
146
+ class="sr-only focus:not-sr-only focus:absolute focus:z-50 focus:p-4 focus:bg-violet-600 focus:text-white"
147
+ >
148
+ Skip to main content
149
+ </a>
150
+
151
+ {#if isMobile}
152
+ <!-- Mobile Layout -->
153
+ <div class="flex flex-col h-full w-full" in:fade={{ duration: 200 }}>
154
+ <MobileLayout />
155
+ </div>
156
+ {:else}
157
+ <!-- Desktop Layout -->
158
+ <DesktopLayout />
159
+ {/if}
160
+ </div>
161
+
162
+ <!-- Modal Provider -->
163
+ <ModalProvider />
164
+
165
+ <!-- Settings Modal -->
166
+ <SettingsModal />
167
+
168
+ <!-- History Modal -->
169
+ <HistoryModal bind:isOpen={showHistoryModal} onClose={closeHistoryModal} />
@@ -0,0 +1,15 @@
1
+ <script lang="ts">
2
+ import { workspaceState } from '$frontend/lib/stores/ui/workspace.svelte';
3
+ import DesktopNavigator from '../DesktopNavigator.svelte';
4
+ import Layout from './split-pane/Layout.svelte';
5
+ </script>
6
+
7
+ <div class="flex h-full w-full">
8
+ <!-- Desktop Navigator -->
9
+ <DesktopNavigator />
10
+
11
+ <!-- Main Workspace with Split Pane Layout -->
12
+ <main id="workspace-main" class="flex-1 h-full min-w-0 relative overflow-hidden p-3 box-border">
13
+ <Layout node={workspaceState.layout} />
14
+ </main>
15
+ </div>
@@ -0,0 +1,17 @@
1
+ <script lang="ts">
2
+ import { workspaceState } from '$frontend/lib/stores/ui/workspace.svelte';
3
+ import PanelContainer from '../PanelContainer.svelte';
4
+ import MobileNavigator from '../MobileNavigator.svelte';
5
+
6
+ const activePanelId = $derived(workspaceState.activeMobilePanel);
7
+ </script>
8
+
9
+ <div class="flex flex-col h-full w-full">
10
+ <MobileNavigator />
11
+
12
+ <main id="main-content" class="flex-1 overflow-hidden">
13
+ {#if activePanelId}
14
+ <PanelContainer panelId={activePanelId} />
15
+ {/if}
16
+ </main>
17
+ </div>
@@ -0,0 +1,42 @@
1
+ <script lang="ts">
2
+ import type { SplitDirection, SplitNode } from '$frontend/lib/stores/ui/workspace.svelte';
3
+ import Layout from './Layout.svelte';
4
+ import Handle from './Handle.svelte';
5
+
6
+ interface Props {
7
+ direction: SplitDirection;
8
+ ratio: number;
9
+ path: number[];
10
+ child1: SplitNode;
11
+ child2: SplitNode;
12
+ }
13
+
14
+ const { direction, ratio, path, child1, child2 }: Props = $props();
15
+
16
+ // Calculate sizes for flex basis
17
+ const child1Size = $derived(`${ratio}%`);
18
+ const child2Size = $derived(`${100 - ratio}%`);
19
+
20
+ // Calculate sizes for container
21
+ const size = 'calc(100% - (var(--spacing) * 3))';
22
+ const width = $derived(direction === 'horizontal' ? '100%' : size);
23
+ const height = $derived(direction === 'horizontal' ? size : '100%');
24
+
25
+ // Flex direction based on split direction
26
+ const flexDirection = $derived(direction === 'horizontal' ? 'flex-col' : 'flex-row');
27
+ </script>
28
+
29
+ <div class="split-pane-container flex {flexDirection} gap-0" style="width: {width}; height: {height};">
30
+ <!-- Child 1 -->
31
+ <div class="split-pane-child overflow-hidden min-w-0" style="flex: 0 0 {child1Size};">
32
+ <Layout node={child1} path={[...path, 0]} />
33
+ </div>
34
+
35
+ <!-- Resize Handle -->
36
+ <Handle {direction} {path} currentRatio={ratio} />
37
+
38
+ <!-- Child 2 -->
39
+ <div class="split-pane-child overflow-hidden min-w-0" style="flex: 0 0 {child2Size};">
40
+ <Layout node={child2} path={[...path, 1]} />
41
+ </div>
42
+ </div>
@@ -0,0 +1,85 @@
1
+ <script lang="ts">
2
+ import type { SplitDirection } from '$frontend/lib/stores/ui/workspace.svelte';
3
+ import { setSplitRatio, workspaceState } from '$frontend/lib/stores/ui/workspace.svelte';
4
+
5
+ interface Props {
6
+ direction: SplitDirection;
7
+ path: number[];
8
+ currentRatio: number; // Get from parent
9
+ onResize?: (newRatio: number) => void;
10
+ }
11
+
12
+ const { direction, path, currentRatio, onResize }: Props = $props();
13
+
14
+ // Drag state
15
+ let isDragging = $state(false);
16
+ let dragStartPos = $state(0);
17
+ let dragStartRatio = $state(0);
18
+ let containerRect = $state<DOMRect | null>(null);
19
+
20
+ function handleResizeStart(event: MouseEvent) {
21
+ event.preventDefault();
22
+
23
+ isDragging = true;
24
+ dragStartPos = direction === 'horizontal' ? event.clientY : event.clientX;
25
+ dragStartRatio = currentRatio; // Save current ratio at drag start
26
+
27
+ // Get container dimensions
28
+ const container = (event.target as HTMLElement).closest('.split-pane-container');
29
+ if (container) {
30
+ containerRect = container.getBoundingClientRect();
31
+ }
32
+
33
+ document.addEventListener('mousemove', handleDragMove);
34
+ document.addEventListener('mouseup', handleDragEnd);
35
+ document.body.style.cursor = direction === 'horizontal' ? 'row-resize' : 'col-resize';
36
+ document.body.style.userSelect = 'none';
37
+ }
38
+
39
+ function handleDragMove(event: MouseEvent) {
40
+ if (!isDragging || !containerRect) return;
41
+
42
+ const currentPos = direction === 'horizontal' ? event.clientY : event.clientX;
43
+ const delta = currentPos - dragStartPos;
44
+
45
+ // Calculate delta as percentage of container size
46
+ const containerSize =
47
+ direction === 'horizontal' ? containerRect.height : containerRect.width;
48
+ const deltaPercent = (delta / containerSize) * 100;
49
+
50
+ // Calculate new ratio (clamped between 10% and 90%)
51
+ const newRatio = Math.max(10, Math.min(90, dragStartRatio + deltaPercent));
52
+
53
+ // Update ratio via store
54
+ setSplitRatio(path, newRatio);
55
+
56
+ // Call optional callback
57
+ if (onResize) {
58
+ onResize(newRatio);
59
+ }
60
+ }
61
+
62
+ function handleDragEnd() {
63
+ isDragging = false;
64
+ containerRect = null;
65
+ document.removeEventListener('mousemove', handleDragMove);
66
+ document.removeEventListener('mouseup', handleDragEnd);
67
+ document.body.style.cursor = '';
68
+ document.body.style.userSelect = '';
69
+ }
70
+ </script>
71
+
72
+ <button
73
+ type="button"
74
+ class="shrink-0 relative z-10 transition-colors duration-150
75
+ {direction === 'horizontal' ? 'h-3 w-full cursor-row-resize' : 'w-3 h-full cursor-col-resize'}
76
+ {isDragging ? 'bg-violet-500/10' : 'hover:bg-violet-500/5'}"
77
+ aria-label="Resize panels"
78
+ onmousedown={handleResizeStart}
79
+ >
80
+ <div
81
+ class="transition-all duration-150 bg-violet-500/20 rounded
82
+ {direction === 'horizontal' ? 'h-0.5 w-12 mx-auto' : 'w-0.5 h-12 my-auto mx-auto'}
83
+ {isDragging ? 'bg-violet-600 scale-110' : ''}"
84
+ ></div>
85
+ </button>
@@ -0,0 +1,37 @@
1
+ <script lang="ts">
2
+ import type { SplitNode } from '$frontend/lib/stores/ui/workspace.svelte';
3
+ import PanelContainer from '../../PanelContainer.svelte';
4
+ import Container from './Container.svelte';
5
+
6
+ interface Props {
7
+ node: SplitNode;
8
+ path?: number[]; // Path in tree for resize updates
9
+ }
10
+
11
+ const { node, path = [] }: Props = $props();
12
+ </script>
13
+
14
+ {#if node.type === 'panel'}
15
+ <!-- Panel Leaf: Render panel wrapper -->
16
+ {#if node.panelId}
17
+ <div class="split-pane-panel h-full w-full overflow-hidden">
18
+ <PanelContainer panelId={node.panelId} />
19
+ </div>
20
+ {:else}
21
+ <!-- Empty slot -->
22
+ <div
23
+ class="split-pane-empty flex items-center justify-center h-full w-full bg-slate-100 dark:bg-slate-900/50 border-2 border-dashed border-slate-300 dark:border-slate-600 rounded-lg"
24
+ >
25
+ <span class="text-sm text-slate-400 dark:text-slate-500">Empty Panel</span>
26
+ </div>
27
+ {/if}
28
+ {:else if node.type === 'split'}
29
+ <!-- Split Container: Render split with two children -->
30
+ <Container
31
+ direction={node.direction}
32
+ ratio={node.ratio}
33
+ path={path}
34
+ child1={node.children[0]}
35
+ child2={node.children[1]}
36
+ />
37
+ {/if}
@@ -0,0 +1,274 @@
1
+ <script lang="ts">
2
+ import { sessionState, setCurrentSession, createNewChatSession, clearMessages, loadMessagesForSession } from '$frontend/lib/stores/core/sessions.svelte';
3
+ import { projectState } from '$frontend/lib/stores/core/projects.svelte';
4
+ import { appState } from '$frontend/lib/stores/core/app.svelte';
5
+ import { addNotification } from '$frontend/lib/stores/ui/notification.svelte';
6
+ import { onMount } from 'svelte';
7
+ import { fade } from 'svelte/transition';
8
+ import ChatMessages from '$frontend/lib/components/chat/message/ChatMessages.svelte';
9
+ import ChatInput from '$frontend/lib/components/chat/input/ChatInput.svelte';
10
+ import FloatingTodoList from '$frontend/lib/components/chat/widgets/FloatingTodoList.svelte';
11
+ import TimelineModal from '$frontend/lib/components/checkpoint/TimelineModal.svelte';
12
+ import Icon from '$frontend/lib/components/common/Icon.svelte';
13
+ import Button from '$frontend/lib/components/common/Button.svelte';
14
+ import { debug } from '$shared/utils/logger';
15
+ import ws from '$frontend/lib/utils/ws';
16
+ import { chatService } from '$frontend/lib/services/chat/chat.service';
17
+ import { setSkipNextRestore } from '$frontend/lib/stores/ui/chat-input.svelte';
18
+ import { userStore } from '$frontend/lib/stores/features/user.svelte';
19
+
20
+ // Props
21
+ interface Props {
22
+ showMobileHeader?: boolean;
23
+ }
24
+
25
+ const { showMobileHeader = false }: Props = $props();
26
+
27
+ // Welcome state - don't show during restoration
28
+ const isWelcomeState = $derived(
29
+ sessionState.messages.length === 0 &&
30
+ !appState.isRestoring
31
+ );
32
+
33
+ // Check if we should show input (not during restoration)
34
+ const showInput = $derived(!appState.isRestoring);
35
+
36
+ // Project-aware state
37
+ const hasActiveProject = $derived(projectState.currentProject !== null);
38
+
39
+ // Scroll container
40
+ const scrollContainer: HTMLElement | undefined = $state();
41
+
42
+ // Checkpoints modal state
43
+ let showCheckpoints = $state(false);
44
+
45
+ function openCheckpoints() {
46
+ showCheckpoints = true;
47
+ }
48
+
49
+ function closeCheckpoints() {
50
+ showCheckpoints = false;
51
+ }
52
+
53
+ // Extract text from message content
54
+ function extractMessageText(message: any): string {
55
+ if (!('message' in message) || !message.message?.content) {
56
+ return '';
57
+ }
58
+ const content = message.message.content;
59
+
60
+ if (typeof content === 'string') {
61
+ return content;
62
+ } else if (Array.isArray(content)) {
63
+ // Find text content in array
64
+ for (const item of content) {
65
+ if (typeof item === 'string') {
66
+ return item;
67
+ } else if (typeof item === 'object' && item !== null) {
68
+ if ('text' in item && typeof (item as any).text === 'string') {
69
+ return (item as any).text;
70
+ }
71
+ }
72
+ }
73
+ }
74
+ return '';
75
+ }
76
+
77
+ // Process timeline messages with all necessary data
78
+ const timelineMessages = $derived(
79
+ sessionState.messages
80
+ .filter(m => {
81
+ if (m.type !== 'user') return false;
82
+ const text = extractMessageText(m);
83
+ return text.length > 0;
84
+ })
85
+ .map(msg => ({
86
+ id: msg.metadata?.message_id,
87
+ timestamp: msg.metadata?.created_at || '',
88
+ date: msg.metadata?.created_at ? new Date(msg.metadata.created_at).toLocaleDateString() : 'Unknown',
89
+ time: msg.metadata?.created_at ? new Date(msg.metadata.created_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) : 'Unknown',
90
+ text: extractMessageText(msg)
91
+ }))
92
+ );
93
+
94
+ // Handle restore from timeline
95
+ async function handleTimelineRestore(messageId: string | undefined, messageTimestamp: string) {
96
+ if (!messageId) {
97
+ addNotification({
98
+ type: 'error',
99
+ title: 'Restore Failed',
100
+ message: 'Message ID not found',
101
+ duration: 3000
102
+ });
103
+ return;
104
+ }
105
+
106
+ try {
107
+ // Send restore request via WebSocket HTTP
108
+ await ws.http('snapshot:restore', {
109
+ messageId: messageId,
110
+ sessionId: sessionState.currentSession?.id || ''
111
+ });
112
+
113
+ // Close modal
114
+ showCheckpoints = false;
115
+
116
+ // Reload messages from database to update UI
117
+ if (sessionState.currentSession?.id) {
118
+ await loadMessagesForSession(sessionState.currentSession.id);
119
+ }
120
+
121
+ addNotification({
122
+ type: 'success',
123
+ title: 'Project Restored',
124
+ message: `Successfully restored to checkpoint at ${new Date(messageTimestamp).toLocaleTimeString()}`,
125
+ duration: 5000
126
+ });
127
+ } catch (error) {
128
+ debug.error('chat', 'Restore error:', error);
129
+ addNotification({
130
+ type: 'error',
131
+ title: 'Restore Failed',
132
+ message: error instanceof Error ? error.message : 'Unknown error',
133
+ duration: 5000
134
+ });
135
+ }
136
+ }
137
+
138
+ async function startNewChat() {
139
+ if (!hasActiveProject || !projectState.currentProject) {
140
+ addNotification({
141
+ type: 'warning',
142
+ title: 'No Project Selected',
143
+ message: 'Please select a project first',
144
+ duration: 3000
145
+ });
146
+ return;
147
+ }
148
+
149
+ // Cancel active stream if running
150
+ if (appState.isLoading) {
151
+ chatService.cancelRequest();
152
+ }
153
+
154
+ // Clear server input state and prevent stale restore on ChatInput remount
155
+ setSkipNextRestore(true);
156
+ const currentUserId = userStore.currentUser?.id;
157
+ const currentChatSessionId = sessionState.currentSession?.id;
158
+ if (currentUserId && currentChatSessionId) {
159
+ ws.emit('chat:input-sync', {
160
+ text: '',
161
+ senderId: currentUserId,
162
+ chatSessionId: currentChatSessionId,
163
+ attachments: []
164
+ });
165
+ }
166
+
167
+ // Clear messages for local view
168
+ clearMessages();
169
+
170
+ // Create a new session (existing sessions stay active for other users)
171
+ const newSession = await createNewChatSession(projectState.currentProject.id);
172
+
173
+ if (newSession) {
174
+ await setCurrentSession(newSession);
175
+ } else {
176
+ addNotification({
177
+ type: 'error',
178
+ title: 'Failed to Create Session',
179
+ message: 'Could not create a new chat session',
180
+ duration: 3000
181
+ });
182
+ }
183
+ }
184
+
185
+ // Check for active stream on mount only if needed
186
+ onMount(async () => {
187
+ debug.log('chat', 'Component mounted');
188
+ // WebSocket reconnection is handled automatically by ws client
189
+ });
190
+
191
+ // Export actions for DesktopPanel header
192
+ export const panelActions = {
193
+ checkpoints: openCheckpoints,
194
+ newChat: startNewChat,
195
+ hasMessages: () => sessionState.messages.length > 0
196
+ };
197
+ </script>
198
+
199
+ <div class="h-full flex flex-col bg-transparent">
200
+ {#if !hasActiveProject}
201
+ <div
202
+ class="flex-1 flex flex-col items-center justify-center gap-3 text-slate-600 dark:text-slate-500 text-sm"
203
+ >
204
+ <Icon name="lucide:bot" class="w-10 h-10 opacity-30" />
205
+ <span>No project selected</span>
206
+ </div>
207
+ {:else}
208
+ <div class="flex-1 flex flex-col overflow-hidden {showMobileHeader ? '' : '-m-3'}">
209
+ {#if isWelcomeState && !appState.isRestoring}
210
+ <!-- Welcome state with modern design -->
211
+ <div class="flex-1 overflow-y-auto overflow-x-hidden">
212
+ <div class="min-h-full flex items-center justify-center p-4">
213
+ <div class="w-full max-w-4xl space-y-6 md:space-y-8 lg:space-y-10">
214
+ <!-- Modern hero section -->
215
+ <div class="text-center space-y-3 md:space-y-4 px-6">
216
+ <div class="space-y-3 md:space-y-4">
217
+ <h1 class="text-3xl md:text-4xl font-semibold text-slate-900 dark:text-slate-100">
218
+ Build apps & websites with AI
219
+ </h1>
220
+ <p class="md:text-lg text-slate-600 dark:text-slate-400 max-w-2xl mx-auto">
221
+ Describe your idea. Get production-ready code.
222
+ </p>
223
+ </div>
224
+ </div>
225
+
226
+ <!-- Input area integrated in welcome state -->
227
+ {#if showInput}
228
+ <div class="w-full px-4 space-y-4" in:fade={{ duration: 200, delay: 100 }}>
229
+ <ChatInput />
230
+ </div>
231
+ {/if}
232
+ </div>
233
+ </div>
234
+ </div>
235
+ {:else}
236
+ <!-- Enhanced chat interface -->
237
+ <div class="flex-1 flex flex-col overflow-hidden">
238
+ <div class="flex-1 flex justify-center overflow-hidden">
239
+ <div class="w-full flex flex-col overflow-hidden">
240
+ <div class="flex-1 overflow-y-auto overflow-x-hidden">
241
+ <ChatMessages {scrollContainer} />
242
+ </div>
243
+ </div>
244
+ </div>
245
+ </div>
246
+
247
+ <!-- Input area with SDK integration -->
248
+ {#if showInput}
249
+ <div
250
+ class="sticky bottom-0 flex-shrink-0 bg-gradient-to-t from-slate-50 via-slate-50 dark:from-slate-900 dark:via-slate-900 to-transparent"
251
+ in:fade={{ duration: 200, delay: 100 }}
252
+ >
253
+ <div class="flex justify-center">
254
+ <div class="w-full max-w-5xl px-4 pb-4 pt-2">
255
+ <ChatInput />
256
+ </div>
257
+ </div>
258
+ </div>
259
+ {/if}
260
+ {/if}
261
+ </div>
262
+
263
+ <!-- Floating TodoList (only shown when there's an active session with todos) -->
264
+ {#if sessionState.currentSession}
265
+ <FloatingTodoList />
266
+ {/if}
267
+
268
+ <!-- Checkpoint Modal -->
269
+ <TimelineModal
270
+ bind:isOpen={showCheckpoints}
271
+ onClose={closeCheckpoints}
272
+ />
273
+ {/if}
274
+ </div>