@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,61 @@
1
+ /**
2
+ * Component prop types and interfaces
3
+ */
4
+
5
+ export interface ButtonProps {
6
+ variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
7
+ size?: 'sm' | 'md' | 'lg';
8
+ disabled?: boolean;
9
+ loading?: boolean;
10
+ type?: 'button' | 'submit' | 'reset';
11
+ onclick?: () => void;
12
+ }
13
+
14
+ export interface InputProps {
15
+ value?: string;
16
+ placeholder?: string;
17
+ type?: 'text' | 'password' | 'email' | 'number' | 'search';
18
+ disabled?: boolean;
19
+ error?: string;
20
+ label?: string;
21
+ required?: boolean;
22
+ onchange?: (value: string) => void;
23
+ }
24
+
25
+ export interface TextareaProps {
26
+ value?: string;
27
+ placeholder?: string;
28
+ disabled?: boolean;
29
+ error?: string;
30
+ label?: string;
31
+ required?: boolean;
32
+ rows?: number;
33
+ resize?: 'none' | 'both' | 'horizontal' | 'vertical';
34
+ onchange?: (value: string) => void;
35
+ }
36
+
37
+ export interface SelectOption {
38
+ value: string;
39
+ label: string;
40
+ disabled?: boolean;
41
+ }
42
+
43
+ export interface SelectProps {
44
+ value?: string;
45
+ placeholder?: string;
46
+ disabled?: boolean;
47
+ error?: string;
48
+ label?: string;
49
+ required?: boolean;
50
+ options: SelectOption[];
51
+ onchange?: (value: string) => void;
52
+ }
53
+
54
+ export interface CardProps {
55
+ title?: string;
56
+ subtitle?: string;
57
+ variant?: 'default' | 'outlined' | 'elevated' | 'glass';
58
+ padding?: 'none' | 'sm' | 'md' | 'lg';
59
+ clickable?: boolean;
60
+ onclick?: () => void;
61
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Icon system types
3
+ */
4
+
5
+ // Icon types for type safety
6
+ import type { lucideIconRegistry } from '$frontend/lib/components/common/lucide-icons';
7
+ import type { materialIconRegistry } from '$frontend/lib/components/common/material-icons';
8
+
9
+ // Individual icon type exports from auto-generated files
10
+ export type { LucideIconName } from '$frontend/lib/components/common/lucide-icons';
11
+ export type { MaterialIconName } from '$frontend/lib/components/common/material-icons';
12
+
13
+ // Combined icon registry type
14
+ const iconRegistry = {
15
+ // ALL LUCIDE ICONS
16
+ ...({} as typeof lucideIconRegistry),
17
+
18
+ // ALL MATERIAL ICON THEME ICONS
19
+ ...({} as typeof materialIconRegistry),
20
+ } as const;
21
+
22
+ // Type for all supported icons
23
+ export type IconName = keyof typeof iconRegistry;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * UI types barrel export
3
+ */
4
+
5
+ export * from './theme';
6
+ export * from './notifications';
7
+ export * from './icons';
8
+ export * from './components';
9
+
10
+ // Common UI types moved from common/ui.ts
11
+ export type NotificationType = 'success' | 'error' | 'warning' | 'info';
12
+
13
+ export interface ButtonAction {
14
+ label: string;
15
+ action: () => void;
16
+ }
17
+
18
+ export interface BaseDialogOptions {
19
+ title?: string;
20
+ message: string;
21
+ type?: NotificationType;
22
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Notification and toast types
3
+ */
4
+
5
+ import type { NotificationType, ButtonAction } from './index';
6
+
7
+ export interface ToastNotification {
8
+ id: string;
9
+ type: NotificationType;
10
+ title: string;
11
+ message: string;
12
+ duration?: number;
13
+ actions?: ButtonAction[];
14
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Theme and theming types
3
+ */
4
+
5
+ export interface Theme {
6
+ name: string;
7
+ primary: string;
8
+ secondary: string;
9
+ background: string;
10
+ text: string;
11
+ mode: 'light' | 'dark';
12
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * WebSocket Type Definitions
3
+ *
4
+ * Shared types for WebSocket communication between backend and frontend
5
+ */
6
+
7
+ /**
8
+ * WebSocket message format
9
+ */
10
+ export interface WSMessage<T = any> {
11
+ action: string;
12
+ payload: T;
13
+ }
14
+
15
+ /**
16
+ * WebSocket client options
17
+ */
18
+ export interface WSClientOptions {
19
+ /** Auto-reconnect on connection loss */
20
+ autoReconnect?: boolean;
21
+ /** Maximum reconnection attempts (0 = infinite) */
22
+ maxReconnectAttempts?: number;
23
+ /** Initial reconnect delay in ms */
24
+ reconnectDelay?: number;
25
+ /** Maximum reconnect delay in ms */
26
+ maxReconnectDelay?: number;
27
+ /** Debug logging */
28
+ debug?: boolean;
29
+ }
30
+
31
+ /**
32
+ * WebSocket connection state
33
+ */
34
+ export type WSConnectionState = 'connecting' | 'connected' | 'disconnected' | 'reconnecting';
35
+
36
+ /**
37
+ * WebSocket error types
38
+ */
39
+ export interface WSError {
40
+ type: 'connection' | 'validation' | 'timeout' | 'unknown';
41
+ message: string;
42
+ details?: any;
43
+ }
@@ -0,0 +1,13 @@
1
+ // Global window extensions for cursor tracking
2
+ declare global {
3
+ interface Window {
4
+ __cursorInfo?: {
5
+ cursor: string;
6
+ x: number;
7
+ y: number;
8
+ timestamp: number;
9
+ };
10
+ }
11
+ }
12
+
13
+ export {};
@@ -0,0 +1,168 @@
1
+ import { debug } from '$shared/utils/logger';
2
+
3
+ /**
4
+ * Anonymous User Management
5
+ * Client-side utilities for managing anonymous user identities
6
+ * Server-side generation via WebSocket user:anonymous
7
+ */
8
+
9
+ // Dynamic import to avoid circular dependency and SSR issues
10
+ let wsClient: any = null;
11
+ async function getWS() {
12
+ if (!wsClient && typeof window !== 'undefined') {
13
+ const module = await import('$frontend/lib/utils/ws');
14
+ wsClient = module.default;
15
+ }
16
+ return wsClient;
17
+ }
18
+
19
+ export interface AnonymousUser {
20
+ id: string;
21
+ name: string;
22
+ color: string;
23
+ avatar: string;
24
+ createdAt: string;
25
+ }
26
+
27
+ /**
28
+ * Generate a unique anonymous user identity via WebSocket
29
+ */
30
+ async function generateAnonymousUserFromServer(): Promise<AnonymousUser | null> {
31
+ try {
32
+ const ws = await getWS();
33
+ if (!ws) {
34
+ debug.error('user', 'WebSocket client not available');
35
+ return null;
36
+ }
37
+
38
+ const response = await ws.http('user:anonymous', {});
39
+
40
+ debug.log('user', '✅ Generated anonymous user from server:', response.name);
41
+ return response;
42
+ } catch (error) {
43
+ debug.error('user', 'Error calling anonymous user API:', error);
44
+ return null;
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Get or create anonymous user from localStorage
50
+ * If not found, generates new user via server API
51
+ */
52
+ export async function getOrCreateAnonymousUser(): Promise<AnonymousUser | null> {
53
+ // Check if we're in browser environment
54
+ if (typeof window === 'undefined') {
55
+ debug.warn('user', 'Cannot create anonymous user on server side');
56
+ return null;
57
+ }
58
+
59
+ const stored = localStorage.getItem('claude-anonymous-user');
60
+
61
+ if (stored) {
62
+ try {
63
+ const user = JSON.parse(stored);
64
+ // Validate the stored user has all required fields
65
+ if (user.id && user.name && user.color && user.avatar) {
66
+ debug.log('user', 'Found existing anonymous user:', user.name);
67
+ return user;
68
+ }
69
+ } catch (e) {
70
+ debug.error('user', 'Invalid stored anonymous user:', e);
71
+ }
72
+ }
73
+
74
+ // Generate new user via server API
75
+ debug.log('user', 'No valid stored user, generating new one from server...');
76
+ const newUser = await generateAnonymousUserFromServer();
77
+
78
+ if (newUser) {
79
+ localStorage.setItem('claude-anonymous-user', JSON.stringify(newUser));
80
+ return newUser;
81
+ }
82
+
83
+ debug.error('user', 'Failed to generate anonymous user');
84
+ return null;
85
+ }
86
+
87
+ /**
88
+ * Get current anonymous user from localStorage
89
+ */
90
+ export function getCurrentAnonymousUser(): AnonymousUser | null {
91
+ // Check if we're in browser environment
92
+ if (typeof window === 'undefined') {
93
+ return null;
94
+ }
95
+
96
+ const stored = localStorage.getItem('claude-anonymous-user');
97
+
98
+ if (stored) {
99
+ try {
100
+ return JSON.parse(stored);
101
+ } catch (e) {
102
+ debug.error('user', 'Failed to parse anonymous user:', e);
103
+ }
104
+ }
105
+
106
+ return null;
107
+ }
108
+
109
+ /**
110
+ * Update anonymous user name
111
+ * Updates via WebSocket
112
+ */
113
+ export async function updateAnonymousUserName(newName: string): Promise<AnonymousUser | null> {
114
+ // Check if we're in browser environment
115
+ if (typeof window === 'undefined') {
116
+ debug.error('user', 'Cannot update user name on server side');
117
+ return null;
118
+ }
119
+
120
+ const currentUser = getCurrentAnonymousUser();
121
+
122
+ if (!currentUser) {
123
+ debug.error('user', 'No current anonymous user found');
124
+ return null;
125
+ }
126
+
127
+ // Validate name (basic validation)
128
+ if (!newName || newName.trim().length === 0) {
129
+ debug.error('user', 'Invalid name provided');
130
+ return null;
131
+ }
132
+
133
+ const trimmedName = newName.trim();
134
+
135
+ // Call server via WebSocket to get updated user
136
+ try {
137
+ const ws = await getWS();
138
+ if (!ws) {
139
+ debug.error('user', 'WebSocket client not available');
140
+ return null;
141
+ }
142
+
143
+ const response = await ws.http('user:update', {
144
+ userId: currentUser.id,
145
+ newName: trimmedName
146
+ });
147
+
148
+ // Save to localStorage
149
+ localStorage.setItem('claude-anonymous-user', JSON.stringify(response));
150
+ debug.log('user', '✅ Updated user name:', response.name);
151
+ return response;
152
+ } catch (error) {
153
+ debug.error('user', 'Error calling update user API:', error);
154
+ return null;
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Format user display name (shorter version for UI)
160
+ */
161
+ export function formatUserDisplayName(user: AnonymousUser): string {
162
+ // Extract just the animal and number for shorter display
163
+ const parts = user.name.split(' ');
164
+ if (parts.length >= 3) {
165
+ return `${parts[1]} ${parts[2]}`;
166
+ }
167
+ return user.name;
168
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Async utility functions
3
+ */
4
+
5
+ /**
6
+ * Sleep/delay for a specified number of milliseconds
7
+ */
8
+ export function sleep(ms: number): Promise<void> {
9
+ return new Promise(resolve => setTimeout(resolve, ms));
10
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Diff Calculator Utility
3
+ * Calculates git-like line-level differences between file contents
4
+ * Accepts Buffer for binary-safe handling — converts to string internally for line diffing.
5
+ */
6
+
7
+ export interface FileChangeStats {
8
+ filesChanged: number;
9
+ insertions: number;
10
+ deletions: number;
11
+ }
12
+
13
+ export interface FileDiff {
14
+ filepath: string;
15
+ insertions: number;
16
+ deletions: number;
17
+ status: 'added' | 'modified' | 'deleted';
18
+ }
19
+
20
+ /**
21
+ * Calculate line-level diff statistics similar to git
22
+ * Compares two file snapshots and returns stats about changes
23
+ */
24
+ export function calculateFileChangeStats(
25
+ previousSnapshot: Record<string, Buffer>,
26
+ currentSnapshot: Record<string, Buffer>
27
+ ): FileChangeStats {
28
+ let totalInsertions = 0;
29
+ let totalDeletions = 0;
30
+ const changedFiles = new Set<string>();
31
+
32
+ // Check added and modified files
33
+ for (const [filepath, newContent] of Object.entries(currentSnapshot)) {
34
+ const oldContent = previousSnapshot[filepath];
35
+
36
+ if (!oldContent) {
37
+ // File was added - count all lines as insertions
38
+ const lines = countLines(newContent.toString('utf-8'));
39
+ totalInsertions += lines;
40
+ changedFiles.add(filepath);
41
+ } else if (!oldContent.equals(newContent)) {
42
+ // File was modified - calculate line diff
43
+ const diff = calculateLineDiff(oldContent.toString('utf-8'), newContent.toString('utf-8'));
44
+ totalInsertions += diff.insertions;
45
+ totalDeletions += diff.deletions;
46
+ changedFiles.add(filepath);
47
+ }
48
+ }
49
+
50
+ // Check deleted files
51
+ for (const [filepath, oldContent] of Object.entries(previousSnapshot)) {
52
+ if (!currentSnapshot[filepath]) {
53
+ // File was deleted - count all lines as deletions
54
+ const lines = countLines(oldContent.toString('utf-8'));
55
+ totalDeletions += lines;
56
+ changedFiles.add(filepath);
57
+ }
58
+ }
59
+
60
+ return {
61
+ filesChanged: changedFiles.size,
62
+ insertions: totalInsertions,
63
+ deletions: totalDeletions
64
+ };
65
+ }
66
+
67
+ /**
68
+ * Get detailed diff for each file
69
+ * Useful for displaying individual file changes
70
+ */
71
+ export function getDetailedFileDiffs(
72
+ previousSnapshot: Record<string, Buffer>,
73
+ currentSnapshot: Record<string, Buffer>
74
+ ): FileDiff[] {
75
+ const diffs: FileDiff[] = [];
76
+
77
+ // Check added and modified files
78
+ for (const [filepath, newContent] of Object.entries(currentSnapshot)) {
79
+ const oldContent = previousSnapshot[filepath];
80
+
81
+ if (!oldContent) {
82
+ // File was added
83
+ diffs.push({
84
+ filepath,
85
+ insertions: countLines(newContent.toString('utf-8')),
86
+ deletions: 0,
87
+ status: 'added'
88
+ });
89
+ } else if (!oldContent.equals(newContent)) {
90
+ // File was modified
91
+ const diff = calculateLineDiff(oldContent.toString('utf-8'), newContent.toString('utf-8'));
92
+ diffs.push({
93
+ filepath,
94
+ insertions: diff.insertions,
95
+ deletions: diff.deletions,
96
+ status: 'modified'
97
+ });
98
+ }
99
+ }
100
+
101
+ // Check deleted files
102
+ for (const [filepath, oldContent] of Object.entries(previousSnapshot)) {
103
+ if (!currentSnapshot[filepath]) {
104
+ // File was deleted
105
+ diffs.push({
106
+ filepath,
107
+ insertions: 0,
108
+ deletions: countLines(oldContent.toString('utf-8')),
109
+ status: 'deleted'
110
+ });
111
+ }
112
+ }
113
+
114
+ return diffs;
115
+ }
116
+
117
+ /**
118
+ * Calculate line-level diff between two file contents
119
+ * Uses simple line-by-line comparison (similar to diff -u)
120
+ */
121
+ function calculateLineDiff(
122
+ oldContent: string,
123
+ newContent: string
124
+ ): { insertions: number; deletions: number } {
125
+ const oldLines = splitLines(oldContent);
126
+ const newLines = splitLines(newContent);
127
+
128
+ // Use Myers diff algorithm (simplified version)
129
+ // For performance, we use a simple LCS-based approach
130
+ const lcs = longestCommonSubsequence(oldLines, newLines);
131
+
132
+ const insertions = newLines.length - lcs;
133
+ const deletions = oldLines.length - lcs;
134
+
135
+ return { insertions, deletions };
136
+ }
137
+
138
+ /**
139
+ * Calculate Longest Common Subsequence length
140
+ * Used to determine how many lines are unchanged
141
+ */
142
+ function longestCommonSubsequence(arr1: string[], arr2: string[]): number {
143
+ const m = arr1.length;
144
+ const n = arr2.length;
145
+
146
+ // Create DP table
147
+ const dp: number[][] = Array(m + 1).fill(0).map(() => Array(n + 1).fill(0));
148
+
149
+ // Fill DP table
150
+ for (let i = 1; i <= m; i++) {
151
+ for (let j = 1; j <= n; j++) {
152
+ if (arr1[i - 1] === arr2[j - 1]) {
153
+ dp[i][j] = dp[i - 1][j - 1] + 1;
154
+ } else {
155
+ dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
156
+ }
157
+ }
158
+ }
159
+
160
+ return dp[m][n];
161
+ }
162
+
163
+ /**
164
+ * Split content into lines
165
+ * Handles different line endings (CRLF, LF)
166
+ */
167
+ function splitLines(content: string): string[] {
168
+ if (!content) return [];
169
+ // Normalize line endings and split
170
+ return content.replace(/\r\n/g, '\n').split('\n');
171
+ }
172
+
173
+ /**
174
+ * Count number of lines in content
175
+ */
176
+ function countLines(content: string): number {
177
+ if (!content) return 0;
178
+ const lines = splitLines(content);
179
+ // Don't count empty last line
180
+ if (lines.length > 0 && lines[lines.length - 1] === '') {
181
+ return lines.length - 1;
182
+ }
183
+ return lines.length;
184
+ }