@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,68 @@
1
+ /**
2
+ * Shared git status utilities for label and color mapping.
3
+ * Used by FileChangeItem, DiffViewer, and GitPanel tab bar.
4
+ *
5
+ * Status codes (from git status --porcelain=v1):
6
+ * M = Modified, A = Added, D = Deleted, R = Renamed,
7
+ * C = Copied, U = Unmerged, ? = Untracked, T = Type changed
8
+ */
9
+
10
+ /** Maps a raw git status code to a single-letter display label */
11
+ export function getGitStatusLabel(status: string): string {
12
+ switch (status) {
13
+ case '?': return 'U';
14
+ case 'A': return 'A';
15
+ case 'D': return 'D';
16
+ case 'M': return 'M';
17
+ case 'R': return 'R';
18
+ case 'C': return 'C';
19
+ case 'U': return 'U';
20
+ case 'T': return 'T';
21
+ default: return status || '';
22
+ }
23
+ }
24
+
25
+ /** Maps a raw git status code to a Tailwind text color class */
26
+ export function getGitStatusColor(status: string): string {
27
+ switch (status) {
28
+ case '?': return 'text-emerald-500';
29
+ case 'A': return 'text-emerald-500';
30
+ case 'D': return 'text-red-500';
31
+ case 'M': return 'text-amber-500';
32
+ case 'R': return 'text-blue-500';
33
+ case 'C': return 'text-teal-500';
34
+ case 'U': return 'text-orange-500';
35
+ case 'T': return 'text-violet-500';
36
+ default: return 'text-slate-500';
37
+ }
38
+ }
39
+
40
+ /** Maps a raw git status code to a full-word label (for badges/headers) */
41
+ export function getGitStatusBadgeLabel(status: string): string {
42
+ switch (status) {
43
+ case '?': return 'Untracked';
44
+ case 'A': return 'Added';
45
+ case 'D': return 'Deleted';
46
+ case 'M': return 'Modified';
47
+ case 'R': return 'Renamed';
48
+ case 'C': return 'Copied';
49
+ case 'U': return 'Unmerged';
50
+ case 'T': return 'Type Changed';
51
+ default: return status || '';
52
+ }
53
+ }
54
+
55
+ /** Maps a raw git status code to Tailwind badge bg+text color classes */
56
+ export function getGitStatusBadgeColor(status: string): string {
57
+ switch (status) {
58
+ case '?': return 'bg-emerald-500/15 text-emerald-600 dark:text-emerald-400';
59
+ case 'A': return 'bg-emerald-500/15 text-emerald-600 dark:text-emerald-400';
60
+ case 'D': return 'bg-red-500/15 text-red-600 dark:text-red-400';
61
+ case 'M': return 'bg-amber-500/15 text-amber-600 dark:text-amber-400';
62
+ case 'R': return 'bg-blue-500/15 text-blue-600 dark:text-blue-400';
63
+ case 'C': return 'bg-teal-500/15 text-teal-600 dark:text-teal-400';
64
+ case 'U': return 'bg-orange-500/15 text-orange-600 dark:text-orange-400';
65
+ case 'T': return 'bg-violet-500/15 text-violet-600 dark:text-violet-400';
66
+ default: return 'bg-slate-500/15 text-slate-600 dark:text-slate-400';
67
+ }
68
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Cross-platform keyboard shortcut and platform detection utilities
3
+ */
4
+
5
+ export type Platform = 'mac' | 'windows' | 'linux' | 'unknown';
6
+
7
+ /**
8
+ * Detect the current platform
9
+ */
10
+ export function detectPlatform(): Platform {
11
+ if (typeof window === 'undefined') {
12
+ // Server-side fallback
13
+ return 'unknown';
14
+ }
15
+
16
+ const userAgent = window.navigator.userAgent.toLowerCase();
17
+ const platform = window.navigator.platform.toLowerCase();
18
+
19
+ if (platform.includes('mac') || userAgent.includes('mac')) {
20
+ return 'mac';
21
+ }
22
+
23
+ if (platform.includes('win') || userAgent.includes('win')) {
24
+ return 'windows';
25
+ }
26
+
27
+ if (platform.includes('linux') || userAgent.includes('linux')) {
28
+ return 'linux';
29
+ }
30
+
31
+ return 'unknown';
32
+ }
33
+
34
+ /**
35
+ * Check if the given keyboard event matches the cancel command (Ctrl+C or Cmd+C)
36
+ */
37
+ export function isCancelKeyCombo(event: KeyboardEvent): boolean {
38
+ const platform = detectPlatform();
39
+
40
+ // Check for 'c' key
41
+ if (event.key.toLowerCase() !== 'c') {
42
+ return false;
43
+ }
44
+
45
+ // Mac uses Cmd+C, others use Ctrl+C
46
+ if (platform === 'mac') {
47
+ return event.metaKey && !event.ctrlKey && !event.altKey && !event.shiftKey;
48
+ } else {
49
+ return event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey;
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Check if the given keyboard event matches the clear command (Ctrl+L or Cmd+L)
55
+ */
56
+ export function isClearKeyCombo(event: KeyboardEvent): boolean {
57
+ const platform = detectPlatform();
58
+
59
+ // Check for 'l' key
60
+ if (event.key.toLowerCase() !== 'l') {
61
+ return false;
62
+ }
63
+
64
+ // Mac uses Cmd+L, others use Ctrl+L
65
+ if (platform === 'mac') {
66
+ return event.metaKey && !event.ctrlKey && !event.altKey && !event.shiftKey;
67
+ } else {
68
+ return event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey;
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Get the display name for keyboard shortcuts based on platform
74
+ */
75
+ export function getShortcutLabels() {
76
+ const platform = detectPlatform();
77
+ const modifier = platform === 'mac' ? '⌘' : 'Ctrl';
78
+
79
+ return {
80
+ cancel: `${modifier}+C`,
81
+ clear: `${modifier}+L`,
82
+ modifier: modifier
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Get platform-specific modifier key display
88
+ */
89
+ export function getModifierKey(): string {
90
+ const platform = detectPlatform();
91
+ return platform === 'mac' ? '⌘' : 'Ctrl';
92
+ }
93
+
94
+ /**
95
+ * Check if we're on macOS
96
+ */
97
+ export function isMac(): boolean {
98
+ return detectPlatform() === 'mac';
99
+ }
100
+
101
+ /**
102
+ * Check if we're on Windows
103
+ */
104
+ export function isWindows(): boolean {
105
+ return detectPlatform() === 'windows';
106
+ }
107
+
108
+ /**
109
+ * Check if we're on Linux
110
+ */
111
+ export function isLinux(): boolean {
112
+ return detectPlatform() === 'linux';
113
+ }
@@ -0,0 +1,65 @@
1
+ import { createServer } from 'http';
2
+
3
+ import { debug } from '$shared/utils/logger';
4
+ /**
5
+ * Check if a specific port is available
6
+ */
7
+ export function checkPortAvailability(port: number): Promise<boolean> {
8
+ return new Promise((resolve) => {
9
+ const server = createServer();
10
+
11
+ server.listen(port, () => {
12
+ server.close(() => {
13
+ resolve(true); // Port is available
14
+ });
15
+ });
16
+
17
+ server.on('error', (err: NodeJS.ErrnoException) => {
18
+ if (err.code === 'EADDRINUSE') {
19
+ resolve(false); // Port is in use
20
+ } else {
21
+ resolve(false); // Other error, consider as unavailable
22
+ }
23
+ });
24
+ });
25
+ }
26
+
27
+ /**
28
+ * Strictly check if port 5678 is available and fail if not
29
+ */
30
+ export async function ensurePort5678Available(): Promise<void> {
31
+ const isAvailable = await checkPortAvailability(5678);
32
+
33
+ if (!isAvailable) {
34
+ debug.error('server', '❌ FATAL ERROR: Port 5678 is required but not available!');
35
+ debug.error('server', '❌ Please stop any service using port 5678 and try again.');
36
+ debug.error('server', '❌ This application strictly requires port 5678 to be available.');
37
+ debug.error('server', '❌ Use the following command to find what is using port 5678:');
38
+ debug.error('server', '❌ Windows: netstat -ano | findstr :5678');
39
+ debug.error('server', '❌ Linux/Mac: lsof -i :5678');
40
+ process.exit(1);
41
+ }
42
+
43
+ debug.log('server', '✅ Port 5678 is available');
44
+ }
45
+
46
+ /**
47
+ * Get process info using a specific port (Windows only)
48
+ */
49
+ export async function getPortProcessInfo(port: number): Promise<void> {
50
+ try {
51
+ const proc = Bun.spawn(['netstat', '-ano'], {
52
+ stdout: 'pipe',
53
+ stderr: 'ignore'
54
+ });
55
+ const output = await new Response(proc.stdout).text();
56
+ const filteredOutput = output.split('\n').filter((line: string) => line.includes(`:${port}`)).join('\n');
57
+
58
+ if (filteredOutput.trim()) {
59
+ debug.error('server', `❌ Port ${port} is being used by:`);
60
+ debug.error('server', filteredOutput);
61
+ }
62
+ } catch (error) {
63
+ debug.error('server', '❌ Could not check port usage:', error instanceof Error ? error.message : 'Unknown error');
64
+ }
65
+ }
@@ -0,0 +1,207 @@
1
+ // Terminal output detection and ANSI code processing utilities
2
+
3
+ export interface TerminalSegment {
4
+ type: 'terminal' | 'text';
5
+ content: string;
6
+ }
7
+
8
+ // Check if content looks like terminal output
9
+ export function isTerminalOutput(text: string): boolean {
10
+ // Exclude git diff output - should not be treated as terminal
11
+ if (/^diff --git /m.test(text) || /^@@\s+-\d+.*\+\d+.*@@/m.test(text)) {
12
+ return false;
13
+ }
14
+
15
+ // Strong indicators - any of these alone means it's terminal output
16
+
17
+ // 1. ANSI escape codes - definitive terminal indicator
18
+ if (/\u001b\[[\d;]*m/.test(text)) {
19
+ return true;
20
+ }
21
+
22
+ // 2. Shell prompt at the beginning of a line
23
+ if (/^[\s]*[$>#%]\s+/m.test(text)) {
24
+ return true;
25
+ }
26
+
27
+ // 3. Command execution pattern ($ command or > command)
28
+ if (/^[\s]*[$>]\s+\S+/m.test(text)) {
29
+ return true;
30
+ }
31
+
32
+ // Weak indicators - need multiple to be considered terminal
33
+ let weakIndicators = 0;
34
+
35
+ // Terminal-specific formatting
36
+ if (/^[\s]*[│├└─┬┴┤┌┐]+/m.test(text)) weakIndicators++; // Box drawing
37
+ if (/^\s*\d+\s*│/m.test(text)) weakIndicators++; // Line numbers with pipe
38
+ if (/^[\s]*\[[\d:]+\]/m.test(text)) weakIndicators++; // [timestamp] format
39
+ if (/^[\s]*(?:✓|✔|✗|✖|⚠|➜|→|▶|•)\s+/m.test(text)) weakIndicators++; // Terminal symbols at line start
40
+
41
+ // Terminal-specific output patterns
42
+ if (/^(?:error|ERROR|warn|WARN|info|INFO|debug|DEBUG):/m.test(text)) weakIndicators++;
43
+ if (/^\s*at\s+\S+\s+\([^)]+:\d+:\d+\)/m.test(text)) weakIndicators++; // Stack traces
44
+ if (/^[\s]*\+\s+\d+ms/m.test(text)) weakIndicators++; // Timing info
45
+
46
+ // Need at least 3 weak indicators for terminal detection
47
+ // This prevents normal text about packages from being detected as terminal
48
+ return weakIndicators >= 3;
49
+ }
50
+
51
+ // ANSI color mappings to CSS classes with improved visibility for both modes
52
+ const ansiToClass: Record<string, string> = {
53
+ '0': '', // reset
54
+ '1': 'font-bold', // bold
55
+ '2': 'opacity-60', // dim
56
+ '3': 'italic', // italic
57
+ '4': 'underline', // underline
58
+ '22': '', // normal intensity
59
+ '23': '', // not italic
60
+ '30': 'text-slate-800 dark:text-slate-200', // black - improved contrast
61
+ '31': 'text-red-600 dark:text-red-400', // red
62
+ '32': 'text-green-600 dark:text-green-400', // green
63
+ '33': 'text-yellow-700 dark:text-yellow-300', // yellow - better visibility
64
+ '34': 'text-blue-600 dark:text-blue-400', // blue
65
+ '35': 'text-purple-600 dark:text-purple-400', // magenta
66
+ '36': 'text-cyan-600 dark:text-cyan-400', // cyan
67
+ '37': 'text-slate-600 dark:text-slate-200', // white - improved contrast
68
+ '90': 'text-slate-500 dark:text-slate-500', // bright black (gray)
69
+ '91': 'text-red-500 dark:text-red-300', // bright red
70
+ '92': 'text-green-500 dark:text-green-300', // bright green
71
+ '93': 'text-yellow-600 dark:text-yellow-200', // bright yellow
72
+ '94': 'text-blue-500 dark:text-blue-300', // bright blue
73
+ '95': 'text-purple-500 dark:text-purple-300', // bright magenta
74
+ '96': 'text-cyan-500 dark:text-cyan-300', // bright cyan
75
+ '97': 'text-slate-900 dark:text-slate-100', // bright white
76
+ '39': 'text-slate-900 dark:text-slate-100' // default foreground
77
+ };
78
+
79
+ // Process ANSI escape codes in terminal output
80
+ export function processAnsiCodes(text: string): string {
81
+ const ansiRegex = /\u001b\[([0-9;]*)m/g;
82
+ // Escape HTML first to prevent content (e.g. HTML tags in diffs) from being
83
+ // rendered as actual DOM elements when using {@html}
84
+ let processedText = escapeHtml(text);
85
+ let currentStyles: string[] = [];
86
+
87
+ // Replace ANSI codes with HTML spans (ANSI escape char \u001b is not affected by escapeHtml)
88
+ processedText = processedText.replace(ansiRegex, (match, codes) => {
89
+ const codeArray = codes.split(';');
90
+
91
+ for (const code of codeArray) {
92
+ if (code === '0' || code === '') {
93
+ // Reset all styles
94
+ currentStyles = [];
95
+ return '</span>';
96
+ } else if (ansiToClass[code]) {
97
+ const cssClass = ansiToClass[code];
98
+ if (cssClass) {
99
+ // Remove conflicting styles and add new one
100
+ if (code.startsWith('3') || code === '39' || code === '90') {
101
+ // Color codes - remove existing colors
102
+ currentStyles = currentStyles.filter(s => !s.includes('text-'));
103
+ }
104
+ if (!currentStyles.includes(cssClass)) {
105
+ currentStyles.push(cssClass);
106
+ }
107
+ }
108
+ }
109
+ }
110
+
111
+ return `<span class="${currentStyles.join(' ')}">`;
112
+ });
113
+
114
+ // Clean up any unclosed spans
115
+ const openSpans = (processedText.match(/<span/g) || []).length;
116
+ const closeSpans = (processedText.match(/<\/span>/g) || []).length;
117
+ if (openSpans > closeSpans) {
118
+ processedText += '</span>'.repeat(openSpans - closeSpans);
119
+ }
120
+
121
+ return processedText;
122
+ }
123
+
124
+ // Split content into segments (terminal vs regular text)
125
+ export function splitContentIntoSegments(text: string): TerminalSegment[] {
126
+ const segments: TerminalSegment[] = [];
127
+
128
+ // First check if the entire text has ANSI codes - if so, it's all terminal
129
+ if (/\u001b\[[\d;]*m/.test(text)) {
130
+ return [{ type: 'terminal', content: text }];
131
+ }
132
+
133
+ // For text without ANSI codes, we need to be more careful
134
+ // Split by code blocks first to preserve them
135
+ const codeBlockRegex = /```[\s\S]*?```/g;
136
+ const codeBlocks: {start: number, end: number, content: string}[] = [];
137
+ let match;
138
+
139
+ // Find all code blocks
140
+ while ((match = codeBlockRegex.exec(text)) !== null) {
141
+ codeBlocks.push({
142
+ start: match.index,
143
+ end: match.index + match[0].length,
144
+ content: match[0]
145
+ });
146
+ }
147
+
148
+ // Process text in chunks, avoiding code blocks
149
+ let lastIndex = 0;
150
+ for (let i = 0; i <= codeBlocks.length; i++) {
151
+ const startIndex = lastIndex;
152
+ const endIndex = i < codeBlocks.length ? codeBlocks[i].start : text.length;
153
+
154
+ if (startIndex < endIndex) {
155
+ const chunk = text.slice(startIndex, endIndex);
156
+
157
+ // Split chunk by double newlines
158
+ const blocks = chunk.split(/\n\n+/);
159
+
160
+ for (const block of blocks) {
161
+ if (!block.trim()) continue;
162
+
163
+ const blockType = isTerminalOutput(block) ? 'terminal' : 'text';
164
+
165
+ // Merge with previous segment if same type
166
+ if (segments.length > 0 && segments[segments.length - 1].type === blockType) {
167
+ segments[segments.length - 1].content += '\n\n' + block;
168
+ } else {
169
+ segments.push({ type: blockType, content: block });
170
+ }
171
+ }
172
+ }
173
+
174
+ // Add code block as text (not terminal)
175
+ if (i < codeBlocks.length) {
176
+ if (segments.length > 0 && segments[segments.length - 1].type === 'text') {
177
+ segments[segments.length - 1].content += '\n\n' + codeBlocks[i].content;
178
+ } else {
179
+ segments.push({ type: 'text', content: codeBlocks[i].content });
180
+ }
181
+ lastIndex = codeBlocks[i].end;
182
+ }
183
+ }
184
+
185
+ // If no segments, treat as text
186
+ if (segments.length === 0 && text.trim()) {
187
+ segments.push({ type: 'text', content: text });
188
+ }
189
+
190
+ return segments;
191
+ }
192
+
193
+ // Format terminal output with proper styling
194
+ export function formatTerminalOutput(text: string): string {
195
+ const processedAnsi = processAnsiCodes(text);
196
+ return `<div class="font-mono text-sm whitespace-pre-wrap terminal-output bg-slate-100 dark:bg-slate-900 text-slate-900 dark:text-slate-100 p-4 rounded-lg overflow-x-auto border border-slate-300 dark:border-slate-700">${processedAnsi}</div>`;
197
+ }
198
+
199
+ // Escape HTML entities for security
200
+ export function escapeHtml(text: string): string {
201
+ return text
202
+ .replace(/&/g, '&amp;')
203
+ .replace(/</g, '&lt;')
204
+ .replace(/>/g, '&gt;')
205
+ .replace(/"/g, '&quot;')
206
+ .replace(/'/g, '&#39;');
207
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Theme Utils Module
3
+ * Re-exports theme functions from the store for convenience
4
+ */
5
+
6
+ export { initializeTheme, setTheme, toggleDarkMode, isDarkMode, currentTheme } from '$frontend/lib/stores/ui/theme.svelte';