@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,157 @@
1
+ <!--
2
+ Message Header Component
3
+
4
+ Features:
5
+ - Timestamp display
6
+ - Sender name and role badge
7
+ - Agent status indicator
8
+ - Action buttons (copy, undo, edit, token usage, debug)
9
+ -->
10
+
11
+ <script lang="ts">
12
+ import type { SDKMessageFormatter } from '$shared/types/database/schema';
13
+ import type { IconName } from '$shared/types/ui/icons';
14
+ import Icon from '$frontend/lib/components/common/Icon.svelte';
15
+ import { appState } from '$frontend/lib/stores/core/app.svelte';
16
+
17
+ const {
18
+ message,
19
+ messageTimestamp,
20
+ isLastUserMessage = false,
21
+ roleConfig,
22
+ roleCategory,
23
+ agentStatus,
24
+ senderName,
25
+ hasTokenUsageData,
26
+ formatTime,
27
+ onCopy,
28
+ onRestore,
29
+ onEdit,
30
+ onShowTokenUsage,
31
+ onShowDebug
32
+ }: {
33
+ message: SDKMessageFormatter;
34
+ messageTimestamp: string;
35
+ isLastUserMessage?: boolean;
36
+ roleConfig: { gradient: string; icon: IconName; name: string };
37
+ roleCategory: 'user' | 'assistant' | 'agent' | string;
38
+ agentStatus: 'processing' | 'success' | 'error' | null;
39
+ senderName: string | null;
40
+ hasTokenUsageData: any;
41
+ formatTime: (timestamp?: string) => string;
42
+ onCopy: () => void;
43
+ onRestore: () => void;
44
+ onEdit: () => void;
45
+ onShowTokenUsage: () => void;
46
+ onShowDebug: () => void;
47
+ } = $props();
48
+
49
+ // State untuk copy button
50
+ let isCopied = $state(false);
51
+
52
+ // Handle copy dengan perubahan icon
53
+ function handleCopy() {
54
+ onCopy();
55
+ isCopied = true;
56
+ setTimeout(() => {
57
+ isCopied = false;
58
+ }, 1000);
59
+ }
60
+ </script>
61
+
62
+ <div class="flex items-center justify-between gap-5 px-3 md:px-4 py-1 border-b border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800">
63
+ <!-- Timestamp and Type -->
64
+ <div class="flex items-center gap-2">
65
+ <span class="text-xs text-slate-500 dark:text-slate-400 font-medium">
66
+ {formatTime(messageTimestamp)}
67
+ </span>
68
+ <span class="w-1 h-1 bg-current rounded-full opacity-50"></span>
69
+ <div class="flex items-center gap-1.5">
70
+ <span class="text-xs text-slate-400 dark:text-slate-500 capitalize">
71
+ {roleCategory === 'user' && senderName ? senderName : roleConfig.name}
72
+ </span>
73
+ <!-- Agent Status Indicator -->
74
+ {#if agentStatus}
75
+ {#if agentStatus === 'processing'}
76
+ <span title="Agent is processing...">
77
+ <Icon name="lucide:loader" class="w-3 h-3 text-violet-500 dark:text-violet-400 animate-spin" />
78
+ </span>
79
+ {:else if agentStatus === 'success'}
80
+ <span title="Agent completed successfully">
81
+ <Icon name="lucide:check" class="w-3 h-3 text-green-500 dark:text-green-400" />
82
+ </span>
83
+ {:else if agentStatus === 'error'}
84
+ <span title="Agent encountered an error">
85
+ <Icon name="lucide:x" class="w-3 h-3 text-red-500 dark:text-red-400" />
86
+ </span>
87
+ {/if}
88
+ {/if}
89
+ </div>
90
+ </div>
91
+
92
+ <!-- Compact Actions - Always visible but subtle -->
93
+ <div class="flex items-center space-x-1 -mr-1">
94
+ <!-- Copy button - hanya untuk user dan assistant (tidak untuk agent) -->
95
+ {#if roleCategory === 'user' || roleCategory === 'assistant'}
96
+ <button
97
+ onclick={handleCopy}
98
+ class="inline-flex p-1.5 rounded-md hover:bg-slate-200 dark:hover:bg-slate-600 transition-colors opacity-60 hover:opacity-100"
99
+ aria-label="Copy message"
100
+ title="Copy message"
101
+ >
102
+ <Icon name={isCopied ? "lucide:check" : "lucide:copy"} class="w-3.5 h-3.5" />
103
+ </button>
104
+ {/if}
105
+
106
+ <!-- Undo and Edit buttons for user messages (disabled saat streaming) -->
107
+ {#if roleCategory === 'user'}
108
+ <!-- Undo button (not shown for last user message) -->
109
+ {#if !isLastUserMessage}
110
+ <button
111
+ onclick={onRestore}
112
+ disabled={appState.isLoading}
113
+ class="inline-flex p-1.5 rounded-md transition-colors {appState.isLoading ? 'cursor-not-allowed opacity-40' : 'hover:bg-slate-200 dark:hover:bg-slate-600 opacity-60 hover:opacity-100'}"
114
+ aria-label="Undo to this checkpoint"
115
+ title="Undo to this checkpoint"
116
+ >
117
+ <Icon name="lucide:undo-2" class="w-3.5 h-3.5" />
118
+ </button>
119
+ {/if}
120
+
121
+ <!-- Edit button for user messages -->
122
+ <button
123
+ onclick={onEdit}
124
+ disabled={appState.isLoading}
125
+ class="inline-flex p-1.5 rounded-md transition-colors {appState.isLoading ? 'cursor-not-allowed opacity-40' : 'hover:bg-slate-200 dark:hover:bg-slate-600 opacity-60 hover:opacity-100'}"
126
+ aria-label="Edit message"
127
+ title="Edit message"
128
+ >
129
+ <Icon name="lucide:pencil" class="w-3.5 h-3.5" />
130
+ </button>
131
+ {/if}
132
+
133
+ <!-- Token Usage button -->
134
+ {#if hasTokenUsageData}
135
+ <button
136
+ onclick={onShowTokenUsage}
137
+ class="inline-flex p-1.5 rounded-md hover:bg-slate-200 dark:hover:bg-slate-600 transition-colors opacity-60 hover:opacity-100"
138
+ aria-label="Show token usage info"
139
+ title="Token usage"
140
+ >
141
+ <Icon name="lucide:zap" class="w-3.5 h-3.5" />
142
+ </button>
143
+ {/if}
144
+
145
+ <!-- Debug toggle button -->
146
+ {#if 'parent_tool_use_id' in message}
147
+ <button
148
+ onclick={onShowDebug}
149
+ class="inline-flex p-1.5 rounded-md hover:bg-slate-200 dark:hover:bg-slate-600 transition-colors opacity-60 hover:opacity-100"
150
+ aria-label="Show debug info"
151
+ title="Debug info"
152
+ >
153
+ <Icon name="lucide:bug" class="w-3.5 h-3.5" />
154
+ </button>
155
+ {/if}
156
+ </div>
157
+ </div>
@@ -0,0 +1,59 @@
1
+ <!--
2
+ Debug Modal Component
3
+
4
+ Features:
5
+ - Display raw message data
6
+ - JSON formatting
7
+ - Copy to clipboard
8
+ -->
9
+
10
+ <script lang="ts">
11
+ import type { SDKMessageFormatter } from '$shared/types/database/schema';
12
+ import Modal from '$frontend/lib/components/common/Modal.svelte';
13
+ import Icon from '$frontend/lib/components/common/Icon.svelte';
14
+
15
+ let {
16
+ isOpen = $bindable(),
17
+ message,
18
+ onClose
19
+ }: {
20
+ isOpen: boolean;
21
+ message: SDKMessageFormatter;
22
+ onClose: () => void;
23
+ } = $props();
24
+
25
+ function copyToClipboard() {
26
+ navigator.clipboard.writeText(JSON.stringify(message, null, 2));
27
+ }
28
+ </script>
29
+
30
+ <Modal
31
+ bind:isOpen
32
+ title="Debug Information"
33
+ size="lg"
34
+ {onClose}
35
+ >
36
+ {#snippet children()}
37
+ <div class="space-y-6">
38
+ <!-- Raw Message Data -->
39
+ <div>
40
+ <h4 class="font-medium text-slate-900 dark:text-slate-100 mb-2 flex items-center gap-2">
41
+ <Icon name="lucide:code" class="w-4 h-4" />
42
+ Raw Message
43
+ </h4>
44
+ <div class="bg-slate-100 dark:bg-slate-800 rounded-lg p-3 border border-slate-200 dark:border-slate-700">
45
+ <pre class="text-xs font-mono text-slate-700 dark:text-slate-300 overflow-x-auto max-h-80 overflow-y-auto whitespace-pre-wrap break-words">{JSON.stringify(message, null, 2)}</pre>
46
+ </div>
47
+ <div class="mt-3 flex justify-end">
48
+ <button
49
+ onclick={copyToClipboard}
50
+ class="px-3 py-1.5 bg-violet-500 hover:bg-violet-600 text-white rounded-md text-xs font-medium transition-colors flex items-center gap-1"
51
+ >
52
+ <Icon name="lucide:copy" class="w-3 h-3" />
53
+ Copy JSON
54
+ </button>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ {/snippet}
59
+ </Modal>
@@ -0,0 +1,124 @@
1
+ <!--
2
+ Token Usage Modal Component
3
+
4
+ Features:
5
+ - Display token usage statistics
6
+ - Cache read and creation stats
7
+ - Request information
8
+ -->
9
+
10
+ <script lang="ts">
11
+ import Modal from '$frontend/lib/components/common/Modal.svelte';
12
+ import Icon from '$frontend/lib/components/common/Icon.svelte';
13
+
14
+ let {
15
+ isOpen = $bindable(),
16
+ tokenUsage,
17
+ timestamp,
18
+ onClose
19
+ }: {
20
+ isOpen: boolean;
21
+ tokenUsage: any;
22
+ timestamp: string;
23
+ onClose: () => void;
24
+ } = $props();
25
+
26
+ // Format timestamp
27
+ const formatTime = (timestamp?: string) => {
28
+ if (!timestamp) return 'Unknown';
29
+ const date = new Date(timestamp);
30
+ return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
31
+ };
32
+ </script>
33
+
34
+ <Modal
35
+ bind:isOpen
36
+ title="Token Usage"
37
+ size="md"
38
+ {onClose}
39
+ >
40
+ {#snippet children()}
41
+ {#if tokenUsage}
42
+ <div class="space-y-4">
43
+ <!-- Token Usage Stats -->
44
+ <div class="bg-violet-50 dark:bg-violet-900/20 rounded-lg p-4">
45
+ <h4 class="font-medium text-violet-900 dark:text-violet-100 mb-2 flex items-center gap-2">
46
+ <Icon name="lucide:zap" class="w-4 h-4" />
47
+ Token Usage
48
+ </h4>
49
+ <div class="space-y-3 text-slate-600 dark:text-slate-400">
50
+ <div class="flex justify-between items-center">
51
+ <span class="text-sm">Input Tokens:</span>
52
+ <span class="font-mono font-semibold text-violet-600 dark:text-violet-400">
53
+ {(tokenUsage.input_tokens ?? 0).toLocaleString()}
54
+ </span>
55
+ </div>
56
+ <div class="flex justify-between items-center">
57
+ <span class="text-sm">Output Tokens:</span>
58
+ <span class="font-mono font-semibold text-violet-600 dark:text-violet-400">
59
+ {(tokenUsage.output_tokens ?? 0).toLocaleString()}
60
+ </span>
61
+ </div>
62
+ <div class="flex justify-between items-center">
63
+ <span class="text-sm">Cache Read:</span>
64
+ <span class="font-mono font-semibold text-green-600 dark:text-green-400">
65
+ {(tokenUsage.cache_read_input_tokens ?? 0).toLocaleString()}
66
+ </span>
67
+ </div>
68
+ <div class="flex justify-between items-center">
69
+ <span class="text-sm">Cache Creation:</span>
70
+ <span class="font-mono font-semibold text-violet-600 dark:text-violet-400">
71
+ {(tokenUsage.cache_creation_input_tokens ?? 0).toLocaleString()}
72
+ </span>
73
+ </div>
74
+ <!-- Total -->
75
+ <div class="border-t border-violet-200/50 dark:border-violet-800/50 pt-3 mt-3">
76
+ <div class="flex justify-between items-center">
77
+ <span class="text-sm font-medium">Total Tokens:</span>
78
+ <span class="font-mono font-bold text-lg text-violet-600 dark:text-violet-400">
79
+ {((tokenUsage.input_tokens || 0) + (tokenUsage.output_tokens || 0)).toLocaleString()}
80
+ </span>
81
+ </div>
82
+ </div>
83
+ </div>
84
+ </div>
85
+
86
+ <!-- Request Info -->
87
+ <div class="bg-slate-50 dark:bg-slate-800 rounded-lg p-4 border border-slate-200 dark:border-slate-700">
88
+ <h4 class="font-medium text-slate-900 dark:text-slate-100 mb-2 flex items-center gap-2">
89
+ <Icon name="lucide:info" class="w-4 h-4" />
90
+ Request Info
91
+ </h4>
92
+ <div class="space-y-2">
93
+ <div class="flex justify-between items-center">
94
+ <span class="text-sm text-slate-600 dark:text-slate-400">Time:</span>
95
+ <span class="text-sm font-mono text-slate-900 dark:text-slate-100">
96
+ {formatTime(timestamp || new Date().toISOString())}
97
+ </span>
98
+ </div>
99
+ <div class="flex justify-between items-center">
100
+ <span class="text-sm text-slate-600 dark:text-slate-400">Date:</span>
101
+ <span class="text-sm font-mono text-slate-900 dark:text-slate-100">
102
+ {timestamp ? new Date(timestamp).toLocaleDateString() : 'Unknown'}
103
+ </span>
104
+ </div>
105
+ {#if tokenUsage.service_tier}
106
+ <div class="flex justify-between items-center">
107
+ <span class="text-sm text-slate-600 dark:text-slate-400">Service Tier:</span>
108
+ <span class="text-sm font-medium capitalize text-slate-900 dark:text-slate-100">
109
+ {tokenUsage.service_tier}
110
+ </span>
111
+ </div>
112
+ {/if}
113
+ </div>
114
+ </div>
115
+ </div>
116
+ {:else}
117
+ <div class="text-center py-8">
118
+ <Icon name="lucide:info" class="w-12 h-12 text-slate-400 mx-auto mb-2" />
119
+ <p class="text-slate-600 dark:text-slate-400">No token usage data available</p>
120
+ <p class="text-sm text-slate-500 dark:text-slate-500 mt-1">This message doesn't contain token usage information</p>
121
+ </div>
122
+ {/if}
123
+ {/snippet}
124
+ </Modal>
@@ -0,0 +1,2 @@
1
+ // Utility functions for chat components
2
+ export * from './utils';
@@ -0,0 +1,116 @@
1
+ // Utility functions for tool displays
2
+
3
+ /**
4
+ * Format file path for display by shortening long paths
5
+ */
6
+ export function formatPath(path: string): string {
7
+ if (path === 'current directory') return path;
8
+
9
+ if (path.length > 60) {
10
+ const parts = path.split(/[/\\]/);
11
+ if (parts.length > 3) {
12
+ return `.../${parts.slice(-3).join('/')}`;
13
+ }
14
+ }
15
+ return path;
16
+ }
17
+
18
+ /**
19
+ * Format content by truncating long text intelligently
20
+ */
21
+ export function formatContent(content: string, maxLength: number = 500): string {
22
+ if (content.length <= maxLength) {
23
+ return content;
24
+ }
25
+
26
+ const lines = content.split('\n');
27
+ if (lines.length > 10) {
28
+ return lines.slice(0, 5).join('\n') +
29
+ '\n... (' + (lines.length - 10) + ' more lines) ...\n' +
30
+ lines.slice(-5).join('\n');
31
+ }
32
+ return content.substring(0, maxLength) + '...';
33
+ }
34
+
35
+ /**
36
+ * Format file size in human readable format
37
+ */
38
+ export function formatFileSize(bytes: number): string {
39
+ if (bytes < 1024) return `${bytes} B`;
40
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
41
+ if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
42
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
43
+ }
44
+
45
+ /**
46
+ * Truncate text with ellipsis
47
+ */
48
+ export function truncateText(text: string, maxLength: number): string {
49
+ if (text.length > maxLength) {
50
+ return text.substring(0, maxLength - 3) + '...';
51
+ }
52
+ return text;
53
+ }
54
+
55
+ /**
56
+ * Remove common indentation from a string
57
+ */
58
+ export function removeCommonIndentation(input: string): string {
59
+ const lines = input.split('\n');
60
+
61
+ // Find minimum indentation across all non-empty lines
62
+ let minIndent = Infinity;
63
+
64
+ for (const line of lines) {
65
+ if (line.trim()) { // Skip empty lines
66
+ const match = line.match(/^(\s*)/);
67
+ if (match) {
68
+ minIndent = Math.min(minIndent, match[1].length);
69
+ }
70
+ }
71
+ }
72
+
73
+ // Remove common indentation from all lines
74
+ if (minIndent > 0 && minIndent < Infinity) {
75
+ return lines.map(line => {
76
+ if (line.trim()) {
77
+ return line.substring(minIndent);
78
+ }
79
+ return line;
80
+ }).join('\n');
81
+ }
82
+
83
+ return input;
84
+ }
85
+
86
+ /**
87
+ * Remove common indentation from an array of lines
88
+ */
89
+ export function removeCommonIndentationFromLines(lines: string[]): { lines: string[], commonIndent: string } {
90
+ // Find minimum indentation across all non-empty lines
91
+ let minIndent = Infinity;
92
+ let commonIndent = '';
93
+
94
+ for (const line of lines) {
95
+ if (line.trim()) { // Skip empty lines
96
+ const match = line.match(/^(\s*)/);
97
+ if (match) {
98
+ const indent = match[1].length;
99
+ if (indent < minIndent) {
100
+ minIndent = indent;
101
+ commonIndent = match[1].substring(0, minIndent);
102
+ }
103
+ }
104
+ }
105
+ }
106
+
107
+ // Remove common indentation from all lines
108
+ if (minIndent > 0 && minIndent < Infinity) {
109
+ return {
110
+ lines: lines.map(line => line.startsWith(commonIndent) ? line.substring(minIndent) : line),
111
+ commonIndent
112
+ };
113
+ }
114
+
115
+ return { lines, commonIndent: '' };
116
+ }
@@ -0,0 +1,35 @@
1
+ <script lang="ts">
2
+ import type { BashOutputToolInput } from '$shared/types/messaging';
3
+ import { InfoLine } from './components';
4
+ import TextMessage from '../formatters/TextMessage.svelte';
5
+
6
+ const { toolInput }: { toolInput: BashOutputToolInput } = $props();
7
+
8
+ const taskId = toolInput.input.task_id;
9
+ const block = toolInput.input.block;
10
+ const timeout = toolInput.input.timeout;
11
+ </script>
12
+
13
+ <div class="bg-white dark:bg-slate-800 rounded-md border border-slate-200/60 dark:border-slate-700/60 p-3">
14
+ <!-- Command Info -->
15
+ <div class="flex gap-3">
16
+ <InfoLine icon="lucide:terminal" text="Reading output from task: {taskId}" />
17
+ {#if block}
18
+ <InfoLine icon="lucide:clock" text="Blocking: {block}" />
19
+ {/if}
20
+ {#if timeout}
21
+ <InfoLine icon="lucide:timer" text="Timeout: {timeout}ms" />
22
+ {/if}
23
+ </div>
24
+ </div>
25
+
26
+ <!-- Tool Result -->
27
+ {#if toolInput.$result}
28
+ <div class="mt-4 bg-white dark:bg-slate-800 rounded-md border border-slate-200/60 dark:border-slate-700/60 p-3">
29
+ {#if typeof toolInput.$result.content === 'string'}
30
+ <TextMessage content={toolInput.$result.content} />
31
+ {:else}
32
+ <TextMessage content={JSON.stringify(toolInput.$result.content)} />
33
+ {/if}
34
+ </div>
35
+ {/if}
@@ -0,0 +1,46 @@
1
+ <script lang="ts">
2
+ import type { BashToolInput, BashOutputToolOutput } from '$shared/types/messaging';
3
+ import { TerminalCommand } from './components';
4
+ import CodeBlock from './components/CodeBlock.svelte';
5
+
6
+ const { toolInput }: { toolInput: BashToolInput } = $props();
7
+
8
+ const command = toolInput.input.command || '';
9
+ const description = toolInput.input.description;
10
+ const timeout = toolInput.input.timeout;
11
+ const isBackground = toolInput.input.run_in_background;
12
+
13
+ function parseBashOutputToolOutput(content: string): BashOutputToolOutput {
14
+ const statusMatch = content.match(/<status>(.*?)<\/status>/);
15
+ const stdoutMatch = content.match(/<stdout>(.*?)<\/stdout>/s);
16
+ const timestampMatch = content.match(/<timestamp>(.*?)<\/timestamp>/);
17
+
18
+ return {
19
+ status: statusMatch ? statusMatch[1] as BashOutputToolOutput['status'] : 'completed',
20
+ output: stdoutMatch ? stdoutMatch[1].trim() : ""
21
+ };
22
+ }
23
+
24
+ // Parse the output content if it's from BashOutput format
25
+ const outputContent = $derived.by(() => {
26
+ if (!toolInput.$result?.content) return '';
27
+
28
+ // Check if this is a background command that has been merged with BashOutput
29
+ if (isBackground && toolInput.$result.content.includes('<status>')) {
30
+ const parsed = parseBashOutputToolOutput(toolInput.$result.content);
31
+ return parsed.output;
32
+ }
33
+
34
+ return toolInput.$result.content;
35
+ });
36
+
37
+ </script>
38
+
39
+ <TerminalCommand {command} {description} {timeout} />
40
+
41
+ <!-- Tool Result -->
42
+ {#if outputContent}
43
+ <div class="mt-4 bg-white dark:bg-slate-800 rounded-md border border-slate-200/60 dark:border-slate-700/60 p-3">
44
+ <CodeBlock code={outputContent} type="neutral" label="Output" />
45
+ </div>
46
+ {/if}
@@ -0,0 +1,139 @@
1
+ <script lang="ts">
2
+ import { FileHeader, CodeBlock } from './components';
3
+ import Icon from '$frontend/lib/components/common/Icon.svelte';
4
+ import type { ToolInput } from '$shared/types/messaging';
5
+
6
+ const { toolInput }: { toolInput: ToolInput } = $props();
7
+
8
+ /**
9
+ * Parse MCP tool name
10
+ * Format: mcp__server-name__tool-name
11
+ */
12
+ interface ParsedToolName {
13
+ server: string;
14
+ tool: string;
15
+ }
16
+
17
+ function parseMcpToolName(fullName: string): ParsedToolName {
18
+ // Remove "mcp__" prefix
19
+ const withoutPrefix = fullName.replace('mcp__', '');
20
+ const parts = withoutPrefix.split('__');
21
+
22
+ return {
23
+ server: parts[0] || 'unknown',
24
+ tool: parts[1] || 'unknown'
25
+ };
26
+ }
27
+
28
+ const { server, tool } = parseMcpToolName(toolInput.name);
29
+
30
+ // Format server name for display (e.g., "weather-service" -> "Weather Service")
31
+ const serverDisplayName = $derived.by(() => {
32
+ return server
33
+ .split('-')
34
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
35
+ .join(' ');
36
+ });
37
+
38
+ // Format tool name for display (e.g., "get_temperature" -> "Get Temperature")
39
+ const toolDisplayName = $derived.by(() => {
40
+ return tool
41
+ .split('_')
42
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
43
+ .join(' ');
44
+ });
45
+
46
+ // Extract result content
47
+ const resultContent = $derived.by(() => {
48
+ if (!toolInput.$result?.content) return null;
49
+
50
+ const content = toolInput.$result.content;
51
+
52
+ // If content is already a string, return it
53
+ if (typeof content === 'string') {
54
+ return content;
55
+ }
56
+
57
+ // If content is an array (MCP format)
58
+ if (Array.isArray(content)) {
59
+ // Extract text from first text block
60
+ const textBlock = (content as any[]).find((block: any) => block.type === 'text');
61
+ if (textBlock && textBlock.text) {
62
+ return textBlock.text;
63
+ }
64
+ // Fallback: stringify the array
65
+ return JSON.stringify(content, null, 2);
66
+ }
67
+
68
+ // If content is an object, stringify it
69
+ if (typeof content === 'object' && content !== null) {
70
+ return JSON.stringify(content, null, 2);
71
+ }
72
+
73
+ // Fallback: convert to string
74
+ return String(content);
75
+ });
76
+
77
+ // Check if result is an error
78
+ const isError = $derived.by(() => {
79
+ if (!toolInput.$result?.content) return false;
80
+
81
+ const content = toolInput.$result.content;
82
+
83
+ // Check for error markers in string content
84
+ if (typeof content === 'string') {
85
+ return content.toLowerCase().includes('error:');
86
+ }
87
+
88
+ // Check for error markers in array content (MCP format)
89
+ if (Array.isArray(content)) {
90
+ const textBlock = (content as any[]).find((block: any) => block.type === 'text');
91
+ if (textBlock && textBlock.text) {
92
+ return textBlock.text.toLowerCase().includes('error:');
93
+ }
94
+ }
95
+
96
+ // Check for isError property in object content
97
+ if (typeof content === 'object' && content !== null) {
98
+ return (content as any).isError === true;
99
+ }
100
+
101
+ return false;
102
+ });
103
+
104
+ // Format input for display
105
+ const formattedInput = $derived(JSON.stringify(toolInput.input, null, 2));
106
+ </script>
107
+
108
+ <div class="mb-2">
109
+ <h3 class="text-slate-900 dark:text-slate-100 flex items-center gap-x-3 gap-y-1 flex-wrap">
110
+ <div class="flex items-center gap-1.5">
111
+ <Icon name="lucide:tool-case" class="w-4 h-4" />
112
+ <span>{serverDisplayName}</span>
113
+ </div>
114
+ <div class="flex items-center gap-1.5">
115
+ <Icon name="lucide:hammer" class="w-4 h-4" />
116
+ <span>{toolDisplayName}</span>
117
+ </div>
118
+ </h3>
119
+ </div>
120
+
121
+ <!-- Tool Input -->
122
+ {#if toolInput.input && Object.keys(toolInput.input).length > 0}
123
+ <div class="bg-white dark:bg-slate-800 rounded-md border border-slate-200/60 dark:border-slate-700/60 p-3">
124
+ <CodeBlock code={formattedInput} type="neutral" label="Input" />
125
+ </div>
126
+ {/if}
127
+
128
+ <!-- Tool Result -->
129
+ {#if resultContent}
130
+ <div class="mt-4 bg-white dark:bg-slate-800 rounded-md border border-slate-200/60 dark:border-slate-700/60 p-3">
131
+ <CodeBlock code={resultContent} type="neutral" label={isError ? 'Error' : 'Result'} />
132
+ <!-- {@html resultContent.replace(/\n/g, '<br>')} -->
133
+ </div>
134
+ {:else if toolInput.$result}
135
+ <!-- Empty result -->
136
+ <div class="mt-4 bg-white dark:bg-slate-800 rounded-md border border-slate-200/60 dark:border-slate-700/60 p-3">
137
+ <p class="text-sm text-slate-500 dark:text-slate-400 italic">No result returned</p>
138
+ </div>
139
+ {/if}