@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,326 @@
1
+ /**
2
+ * Database queries for message snapshots and session relationships
3
+ * Used for time travel feature
4
+ */
5
+
6
+ import type { MessageSnapshot, SessionRelationship } from '$shared/types/database/schema';
7
+ import { getDatabase } from '../index';
8
+
9
+ import { debug } from '$shared/utils/logger';
10
+ export const snapshotQueries = {
11
+ /**
12
+ * Create a new message snapshot
13
+ * Supports both full and delta snapshots
14
+ */
15
+ createSnapshot(data: {
16
+ id?: string; // Optional: allow caller to provide ID (for blob store tree naming)
17
+ message_id: string;
18
+ session_id: string;
19
+ project_id: string;
20
+ files_snapshot: Record<string, string> | {}; // Will be JSON.stringified
21
+ project_metadata?: any;
22
+ snapshot_type?: 'full' | 'delta';
23
+ parent_snapshot_id?: string;
24
+ delta_changes?: any; // DeltaChanges object
25
+ files_changed?: number;
26
+ insertions?: number;
27
+ deletions?: number;
28
+ branch_id?: string;
29
+ tree_hash?: string; // Blob store tree hash (new format)
30
+ }): MessageSnapshot {
31
+ const db = getDatabase();
32
+ const id = data.id || `snapshot_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
33
+ const now = new Date().toISOString();
34
+
35
+ const snapshot: MessageSnapshot = {
36
+ id,
37
+ message_id: data.message_id,
38
+ session_id: data.session_id,
39
+ project_id: data.project_id,
40
+ files_snapshot: JSON.stringify(data.files_snapshot),
41
+ project_metadata: data.project_metadata ? JSON.stringify(data.project_metadata) : undefined,
42
+ created_at: now,
43
+ snapshot_type: data.snapshot_type || 'full',
44
+ parent_snapshot_id: data.parent_snapshot_id,
45
+ delta_changes: data.delta_changes ? JSON.stringify(data.delta_changes) : undefined,
46
+ files_changed: data.files_changed || 0,
47
+ insertions: data.insertions || 0,
48
+ deletions: data.deletions || 0,
49
+ is_deleted: 0,
50
+ branch_id: data.branch_id || null,
51
+ tree_hash: data.tree_hash || null
52
+ };
53
+
54
+ db.prepare(`
55
+ INSERT INTO message_snapshots (
56
+ id, message_id, session_id, project_id,
57
+ files_snapshot, project_metadata, created_at,
58
+ snapshot_type, parent_snapshot_id, delta_changes,
59
+ files_changed, insertions, deletions,
60
+ is_deleted, branch_id, tree_hash
61
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?)
62
+ `).run(
63
+ snapshot.id,
64
+ snapshot.message_id,
65
+ snapshot.session_id,
66
+ snapshot.project_id,
67
+ snapshot.files_snapshot,
68
+ snapshot.project_metadata || null,
69
+ snapshot.created_at,
70
+ snapshot.snapshot_type,
71
+ snapshot.parent_snapshot_id || null,
72
+ snapshot.delta_changes || null,
73
+ snapshot.files_changed,
74
+ snapshot.insertions,
75
+ snapshot.deletions,
76
+ snapshot.branch_id || null,
77
+ snapshot.tree_hash || null
78
+ );
79
+
80
+ return snapshot;
81
+ },
82
+
83
+ /**
84
+ * Get snapshot by ID
85
+ */
86
+ getById(snapshotId: string): MessageSnapshot | null {
87
+ const db = getDatabase();
88
+ const snapshot = db.prepare(`
89
+ SELECT * FROM message_snapshots WHERE id = ?
90
+ `).get(snapshotId) as MessageSnapshot | null;
91
+
92
+ return snapshot;
93
+ },
94
+
95
+ /**
96
+ * Get snapshot by message ID
97
+ */
98
+ getByMessageId(messageId: string): MessageSnapshot | null {
99
+ const db = getDatabase();
100
+ const snapshot = db.prepare(`
101
+ SELECT * FROM message_snapshots WHERE message_id = ?
102
+ `).get(messageId) as MessageSnapshot | null;
103
+
104
+ return snapshot;
105
+ },
106
+
107
+ /**
108
+ * Get all snapshots for a session
109
+ */
110
+ getBySessionId(sessionId: string): MessageSnapshot[] {
111
+ const db = getDatabase();
112
+ const snapshots = db.prepare(`
113
+ SELECT * FROM message_snapshots
114
+ WHERE session_id = ?
115
+ ORDER BY created_at ASC
116
+ `).all(sessionId) as MessageSnapshot[];
117
+
118
+ return snapshots;
119
+ },
120
+
121
+ /**
122
+ * Get latest snapshot for a project
123
+ */
124
+ getLatestByProjectId(projectId: string): MessageSnapshot | null {
125
+ const db = getDatabase();
126
+ const snapshot = db.prepare(`
127
+ SELECT * FROM message_snapshots
128
+ WHERE project_id = ?
129
+ ORDER BY created_at DESC
130
+ LIMIT 1
131
+ `).get(projectId) as MessageSnapshot | null;
132
+
133
+ return snapshot;
134
+ },
135
+
136
+ /**
137
+ * Delete snapshots after a certain message in a session
138
+ * Used when restoring to a previous state (hard delete - deprecated)
139
+ */
140
+ deleteAfterMessage(sessionId: string, messageId: string, messageTimestamp: string): void {
141
+ const db = getDatabase();
142
+
143
+ // Delete snapshots created at and after this message
144
+ db.prepare(`
145
+ DELETE FROM message_snapshots
146
+ WHERE session_id = ?
147
+ AND created_at >= ?
148
+ `).run(sessionId, messageTimestamp);
149
+ },
150
+
151
+ /**
152
+ * Soft delete snapshots after a certain checkpoint message (for undo with branch support)
153
+ * Deletes snapshots from next user message onward, preserving checkpoint conversation snapshots
154
+ */
155
+ softDeleteAfterMessage(sessionId: string, checkpointTimestamp: string, branchId: string): void {
156
+ const db = getDatabase();
157
+
158
+ // Get snapshots with their associated messages to determine type
159
+ const allSnapshots = db.prepare(`
160
+ SELECT ms.id, ms.created_at, ms.message_id, m.sdk_message
161
+ FROM message_snapshots ms
162
+ JOIN messages m ON ms.message_id = m.id
163
+ WHERE ms.session_id = ?
164
+ ORDER BY ms.created_at ASC
165
+ `).all(sessionId) as { id: string; created_at: string; message_id: string; sdk_message: string }[];
166
+
167
+ // Find the checkpoint snapshot index
168
+ const checkpointIndex = allSnapshots.findIndex(snap => snap.created_at === checkpointTimestamp);
169
+
170
+ if (checkpointIndex === -1) {
171
+ debug.warn('database', `Checkpoint snapshot with timestamp ${checkpointTimestamp} not found`);
172
+ return;
173
+ }
174
+
175
+ // Find next USER message snapshot after checkpoint
176
+ let deleteFromIndex = -1;
177
+ for (let i = checkpointIndex + 1; i < allSnapshots.length; i++) {
178
+ const sdkMessage = JSON.parse(allSnapshots[i].sdk_message);
179
+ if (sdkMessage.type === 'user') {
180
+ deleteFromIndex = i;
181
+ break;
182
+ }
183
+ }
184
+
185
+ // If no user message snapshot found after checkpoint, nothing to delete
186
+ if (deleteFromIndex === -1) {
187
+ debug.log('database', 'No user message snapshots to soft delete after checkpoint');
188
+ return;
189
+ }
190
+
191
+ // Get IDs of snapshots from next user message onward
192
+ const snapshotsToDelete = allSnapshots
193
+ .slice(deleteFromIndex)
194
+ .map(snap => snap.id);
195
+
196
+ if (snapshotsToDelete.length === 0) {
197
+ debug.log('database', 'No snapshots to soft delete after checkpoint');
198
+ return;
199
+ }
200
+
201
+ // Soft delete snapshots
202
+ const placeholders = snapshotsToDelete.map(() => '?').join(',');
203
+ db.prepare(`
204
+ UPDATE message_snapshots
205
+ SET is_deleted = 1, branch_id = ?
206
+ WHERE id IN (${placeholders}) AND (is_deleted IS NULL OR is_deleted = 0)
207
+ `).run(branchId, ...snapshotsToDelete);
208
+
209
+ debug.log('database', `Soft deleted ${snapshotsToDelete.length} snapshots from next user message after checkpoint`);
210
+ },
211
+
212
+ /**
213
+ * Restore snapshots from a specific branch
214
+ */
215
+ restoreBranchSnapshots(sessionId: string, branchId: string): void {
216
+ const db = getDatabase();
217
+
218
+ // Mark all current active snapshots as deleted
219
+ db.prepare(`
220
+ UPDATE message_snapshots
221
+ SET is_deleted = 1
222
+ WHERE session_id = ? AND (is_deleted IS NULL OR is_deleted = 0)
223
+ `).run(sessionId);
224
+
225
+ // Restore snapshots from target branch
226
+ db.prepare(`
227
+ UPDATE message_snapshots
228
+ SET is_deleted = 0
229
+ WHERE session_id = ? AND branch_id = ?
230
+ `).run(sessionId, branchId);
231
+
232
+ // Restore snapshots on main branch up to branching point
233
+ const firstBranchSnapshot = db.prepare(`
234
+ SELECT MIN(created_at) as min_timestamp
235
+ FROM message_snapshots
236
+ WHERE session_id = ? AND branch_id = ?
237
+ `).get(sessionId, branchId) as { min_timestamp: string } | undefined;
238
+
239
+ if (firstBranchSnapshot?.min_timestamp) {
240
+ db.prepare(`
241
+ UPDATE message_snapshots
242
+ SET is_deleted = 0
243
+ WHERE session_id = ? AND (branch_id IS NULL OR branch_id = '') AND created_at < ?
244
+ `).run(sessionId, firstBranchSnapshot.min_timestamp);
245
+ }
246
+ },
247
+
248
+ /**
249
+ * Create session relationship
250
+ */
251
+ createRelationship(data: {
252
+ parent_session_id: string;
253
+ child_session_id: string;
254
+ branched_from_message_id?: string;
255
+ }): SessionRelationship {
256
+ const db = getDatabase();
257
+ const id = `rel_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
258
+ const now = new Date().toISOString();
259
+
260
+ const relationship: SessionRelationship = {
261
+ id,
262
+ parent_session_id: data.parent_session_id,
263
+ child_session_id: data.child_session_id,
264
+ branched_from_message_id: data.branched_from_message_id,
265
+ created_at: now
266
+ };
267
+
268
+ db.prepare(`
269
+ INSERT INTO session_relationships (
270
+ id, parent_session_id, child_session_id,
271
+ branched_from_message_id, created_at
272
+ ) VALUES (?, ?, ?, ?, ?)
273
+ `).run(
274
+ relationship.id,
275
+ relationship.parent_session_id,
276
+ relationship.child_session_id,
277
+ relationship.branched_from_message_id || null,
278
+ relationship.created_at
279
+ );
280
+
281
+ return relationship;
282
+ },
283
+
284
+ /**
285
+ * Get relationship by child session ID
286
+ */
287
+ getRelationshipByChildId(childSessionId: string): SessionRelationship | null {
288
+ const db = getDatabase();
289
+ const relationship = db.prepare(`
290
+ SELECT * FROM session_relationships WHERE child_session_id = ?
291
+ `).get(childSessionId) as SessionRelationship | null;
292
+
293
+ return relationship;
294
+ },
295
+
296
+ /**
297
+ * Get all child sessions of a parent
298
+ */
299
+ getChildSessions(parentSessionId: string): SessionRelationship[] {
300
+ const db = getDatabase();
301
+ const relationships = db.prepare(`
302
+ SELECT * FROM session_relationships
303
+ WHERE parent_session_id = ?
304
+ ORDER BY created_at ASC
305
+ `).all(parentSessionId) as SessionRelationship[];
306
+
307
+ return relationships;
308
+ },
309
+
310
+ /**
311
+ * Get complete session tree for a project
312
+ * Returns all relationships for building a timeline
313
+ */
314
+ getSessionTree(projectId: string): SessionRelationship[] {
315
+ const db = getDatabase();
316
+ const relationships = db.prepare(`
317
+ SELECT sr.*
318
+ FROM session_relationships sr
319
+ INNER JOIN chat_sessions cs ON sr.parent_session_id = cs.id
320
+ WHERE cs.project_id = ?
321
+ ORDER BY sr.created_at ASC
322
+ `).all(projectId) as SessionRelationship[];
323
+
324
+ return relationships;
325
+ }
326
+ };
@@ -0,0 +1,59 @@
1
+ import { getDatabase } from '../index';
2
+ import type { DatabaseMessage } from '$shared/types/database/schema';
3
+
4
+ import { debug } from '$shared/utils/logger';
5
+ export const dbUtils = {
6
+ // Get dashboard statistics
7
+ getStats(): {
8
+ totalProjects: number;
9
+ totalSessions: number;
10
+ totalMessages: number;
11
+ } {
12
+ const db = getDatabase();
13
+
14
+ const totalProjects = (db.prepare('SELECT COUNT(*) as count FROM projects').get() as { count: number }).count;
15
+ const totalSessions = (db.prepare('SELECT COUNT(*) as count FROM chat_sessions').get() as { count: number }).count;
16
+ const totalMessages = (db.prepare('SELECT COUNT(*) as count FROM messages').get() as { count: number }).count;
17
+
18
+ return {
19
+ totalProjects,
20
+ totalSessions,
21
+ totalMessages
22
+ };
23
+ },
24
+
25
+ // Search across messages
26
+ searchMessages(query: string, limit: number = 50): (DatabaseMessage & { project_name: string })[] {
27
+ const db = getDatabase();
28
+ return db.prepare(`
29
+ SELECT m.*, p.name as project_name
30
+ FROM messages m
31
+ JOIN chat_sessions cs ON m.session_id = cs.id
32
+ JOIN projects p ON cs.project_id = p.id
33
+ WHERE m.content LIKE ?
34
+ ORDER BY m.timestamp DESC
35
+ LIMIT ?
36
+ `).all(`%${query}%`, limit) as (DatabaseMessage & { project_name: string })[];
37
+ },
38
+
39
+ // Clean up old data
40
+ cleanupOldData(daysOld: number = 30): void {
41
+ const db = getDatabase();
42
+ const cutoffDate = new Date();
43
+ cutoffDate.setDate(cutoffDate.getDate() - daysOld);
44
+ const cutoff = cutoffDate.toISOString();
45
+
46
+ // Delete old ended sessions and their messages
47
+ const oldSessions = db.prepare(`
48
+ SELECT id FROM chat_sessions
49
+ WHERE ended_at IS NOT NULL AND ended_at < ?
50
+ `).all(cutoff) as { id: string }[];
51
+
52
+ for (const session of oldSessions) {
53
+ db.prepare('DELETE FROM messages WHERE session_id = ?').run(session.id);
54
+ db.prepare('DELETE FROM chat_sessions WHERE id = ?').run(session.id);
55
+ }
56
+
57
+ debug.log('database', `โœ… Cleaned up ${oldSessions.length} old sessions`);
58
+ }
59
+ };
@@ -0,0 +1,13 @@
1
+ // Import all seeders
2
+ import * as settingsSeeder from './settings_seeder';
3
+
4
+ // Export all seeders
5
+ export const seeders = [
6
+ {
7
+ name: 'settings',
8
+ description: settingsSeeder.description,
9
+ seed: settingsSeeder.seed
10
+ }
11
+ ];
12
+
13
+ export default seeders;
@@ -0,0 +1,84 @@
1
+ import type { DatabaseConnection } from '$shared/types/database/connection';
2
+
3
+ import { debug } from '$shared/utils/logger';
4
+ export const seed = (db: DatabaseConnection): void => {
5
+ debug.log('seeder', '๐ŸŒฑ Seeding default settings...');
6
+
7
+ const now = new Date().toISOString();
8
+
9
+ // Insert default settings
10
+ const insertSetting = db.prepare(`
11
+ INSERT INTO settings (key, value, updated_at)
12
+ VALUES (?, ?, ?)
13
+ `);
14
+
15
+ const defaultSettings = [
16
+ {
17
+ key: 'claude_model',
18
+ value: 'sonnet',
19
+ description: 'Default Claude model for chat'
20
+ },
21
+ {
22
+ key: 'max_tokens',
23
+ value: '4000',
24
+ description: 'Maximum tokens per response'
25
+ },
26
+ {
27
+ key: 'temperature',
28
+ value: '0.3',
29
+ description: 'AI response creativity (0.0 - 1.0)'
30
+ },
31
+ {
32
+ key: 'auto_save_sessions',
33
+ value: 'true',
34
+ description: 'Automatically save chat sessions'
35
+ },
36
+ {
37
+ key: 'file_watch_enabled',
38
+ value: 'true',
39
+ description: 'Enable file system watching'
40
+ },
41
+ {
42
+ key: 'theme',
43
+ value: 'system',
44
+ description: 'UI theme preference (light/dark/system)'
45
+ },
46
+ {
47
+ key: 'session_timeout',
48
+ value: '3600000',
49
+ description: 'Session timeout in milliseconds (1 hour)'
50
+ },
51
+ {
52
+ key: 'enable_notifications',
53
+ value: 'true',
54
+ description: 'Enable desktop notifications'
55
+ },
56
+ {
57
+ key: 'auto_cleanup_old_sessions',
58
+ value: 'false',
59
+ description: 'Automatically clean up old chat sessions'
60
+ },
61
+ {
62
+ key: 'default_project_template',
63
+ value: 'svelte',
64
+ description: 'Default template for new projects'
65
+ }
66
+ ];
67
+
68
+ for (const setting of defaultSettings) {
69
+ try {
70
+ insertSetting.run(setting.key, setting.value, now);
71
+ } catch (error) {
72
+ // Skip if setting already exists
73
+ if (error instanceof Error && error.message.includes('UNIQUE constraint failed')) {
74
+ debug.log('seeder', `โ„น๏ธ Setting ${setting.key} already exists, skipping`);
75
+ } else {
76
+ throw error;
77
+ }
78
+ }
79
+ }
80
+
81
+ debug.log('seeder', `โœ… Seeded ${defaultSettings.length} default settings`);
82
+ };
83
+
84
+ export const description = 'Seed default application settings and configuration';
@@ -0,0 +1,174 @@
1
+ import { join } from 'path';
2
+ import { homedir } from 'os';
3
+ import { Database } from 'bun:sqlite';
4
+ import type { DatabaseConnection } from '$shared/types/database/connection';
5
+
6
+ import { debug } from '$shared/utils/logger';
7
+ export class DatabaseManager {
8
+ private static instance: DatabaseManager | null = null;
9
+ private db: DatabaseConnection | null = null;
10
+ private readonly dbPath: string;
11
+
12
+ private constructor() {
13
+ const clopenDir = join(homedir(), '.clopen');
14
+ this.dbPath = join(clopenDir, 'app.db');
15
+ }
16
+
17
+ static getInstance(): DatabaseManager {
18
+ if (!DatabaseManager.instance) {
19
+ DatabaseManager.instance = new DatabaseManager();
20
+ }
21
+ return DatabaseManager.instance;
22
+ }
23
+
24
+ async connect(): Promise<DatabaseConnection> {
25
+ if (this.db) {
26
+ return this.db;
27
+ }
28
+
29
+ debug.log('database', '๐Ÿ”— Connecting to database...');
30
+
31
+ try {
32
+ // Create ~/.clopen directory if it doesn't exist
33
+ const clopenDir = join(homedir(), '.clopen');
34
+ const dirFile = Bun.file(clopenDir);
35
+
36
+ // Check if directory exists, if not create it
37
+ try {
38
+ await dirFile.stat();
39
+ } catch {
40
+ // Directory doesn't exist, create using Bun.write workaround
41
+ const tempFile = join(clopenDir, '.init');
42
+ await Bun.write(tempFile, '');
43
+ // Remove the temp file
44
+ try {
45
+ const tempFileHandle = Bun.file(tempFile);
46
+ if (await tempFileHandle.exists()) {
47
+ if (process.platform === 'win32') {
48
+ await Bun.spawn(['cmd', '/c', 'del', '/f', '/q', tempFile.replace(/\//g, '\\')], {
49
+ stdout: 'ignore',
50
+ stderr: 'ignore'
51
+ }).exited;
52
+ } else {
53
+ await Bun.spawn(['rm', '-f', tempFile], {
54
+ stdout: 'ignore',
55
+ stderr: 'ignore'
56
+ }).exited;
57
+ }
58
+ }
59
+ } catch {
60
+ // Ignore cleanup errors
61
+ }
62
+ }
63
+
64
+ // Use Bun's native SQLite exclusively
65
+ this.db = new Database(this.dbPath);
66
+
67
+ // Configure database for optimal performance
68
+ this.configurePragmas();
69
+
70
+ debug.log('database', `โœ… Connected to database at: ${this.dbPath}`);
71
+ return this.db;
72
+
73
+ } catch (error) {
74
+ debug.error('database', 'โŒ Failed to connect to database:', error);
75
+ throw error;
76
+ }
77
+ }
78
+
79
+ private configurePragmas(): void {
80
+ if (!this.db) return;
81
+
82
+ debug.log('database', 'โš™๏ธ Configuring database pragmas...');
83
+
84
+ // Bun SQLite uses exec for pragmas
85
+ this.db.exec('PRAGMA journal_mode = WAL');
86
+ this.db.exec('PRAGMA synchronous = NORMAL');
87
+ this.db.exec('PRAGMA cache_size = 1000000');
88
+ this.db.exec('PRAGMA temp_store = memory');
89
+ this.db.exec('PRAGMA foreign_keys = ON');
90
+
91
+ debug.log('database', 'โœ… Database pragmas configured');
92
+ }
93
+
94
+ getConnection(): DatabaseConnection {
95
+ if (!this.db) {
96
+ throw new Error('Database not connected. Call connect() first.');
97
+ }
98
+ return this.db;
99
+ }
100
+
101
+ isConnected(): boolean {
102
+ return this.db !== null;
103
+ }
104
+
105
+ close(): void {
106
+ if (this.db) {
107
+ debug.log('database', '๐Ÿ”— Closing database connection...');
108
+ this.db.close();
109
+ this.db = null;
110
+ debug.log('database', 'โœ… Database connection closed');
111
+ }
112
+ }
113
+
114
+ getPath(): string {
115
+ return this.dbPath;
116
+ }
117
+
118
+ async resetDatabase(): Promise<void> {
119
+ debug.log('database', 'โš ๏ธ Resetting database (dropping all tables)...');
120
+
121
+ if (!this.db) {
122
+ throw new Error('Database not connected');
123
+ }
124
+
125
+ // Drop all tables
126
+ const tables = this.db.prepare(`
127
+ SELECT name FROM sqlite_master
128
+ WHERE type='table' AND name NOT LIKE 'sqlite_%'
129
+ `).all() as { name: string }[];
130
+
131
+ for (const table of tables) {
132
+ debug.log('database', `๐Ÿ—‘๏ธ Dropping table: ${table.name}`);
133
+ this.db.exec(`DROP TABLE IF EXISTS ${table.name}`);
134
+ }
135
+
136
+ debug.log('database', 'โœ… Database reset completed');
137
+ }
138
+
139
+ async vacuum(): Promise<void> {
140
+ debug.log('database', '๐Ÿงน Running database vacuum...');
141
+
142
+ if (!this.db) {
143
+ throw new Error('Database not connected');
144
+ }
145
+
146
+ this.db.exec('VACUUM');
147
+ debug.log('database', 'โœ… Database vacuum completed');
148
+ }
149
+
150
+ getDatabaseInfo(): object {
151
+ if (!this.db) {
152
+ throw new Error('Database not connected');
153
+ }
154
+
155
+ // Helper to get pragma values with Bun SQLite
156
+ const getPragma = (name: string) => {
157
+ const result = this.db!.query(`PRAGMA ${name}`).get() as any;
158
+ return result ? Object.values(result)[0] : null;
159
+ };
160
+
161
+ return {
162
+ path: this.dbPath,
163
+ journalMode: getPragma('journal_mode'),
164
+ synchronous: getPragma('synchronous'),
165
+ cacheSize: getPragma('cache_size'),
166
+ tempStore: getPragma('temp_store'),
167
+ foreignKeys: getPragma('foreign_keys'),
168
+ userVersion: getPragma('user_version'),
169
+ pageSize: getPragma('page_size'),
170
+ pageCount: getPragma('page_count'),
171
+ freelistCount: getPragma('freelist_count')
172
+ };
173
+ }
174
+ }
@@ -0,0 +1,4 @@
1
+ // Export all database utilities
2
+ export { DatabaseManager } from './connection';
3
+ export { MigrationRunner } from './migration-runner';
4
+ export { SeederRunner } from './seeder-runner';