@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,501 @@
1
+ /**
2
+ * Page Inspection Handlers
3
+ */
4
+
5
+ import { browserPreviewServiceManager, type BrowserPreviewService } from "$backend/lib/preview";
6
+ import { browserMcpControl } from "$backend/lib/preview";
7
+ import { projectContextService } from "$backend/lib/mcp/project-context";
8
+ import { getActiveTabSession } from "./browser";
9
+ import { debug } from "$shared/utils/logger";
10
+
11
+ /**
12
+ * Get BrowserPreviewService for current MCP execution context
13
+ */
14
+ function getPreviewService(projectId?: string): BrowserPreviewService {
15
+ // 1. Use explicit projectId if provided
16
+ if (projectId) {
17
+ debug.log('mcp', `Using explicit projectId: ${projectId}`);
18
+ return browserPreviewServiceManager.getService(projectId);
19
+ }
20
+
21
+ // 2. Try to get projectId from current execution context
22
+ const contextProjectId = projectContextService.getCurrentProjectId();
23
+ if (contextProjectId) {
24
+ debug.log('mcp', `Using projectId from context: ${contextProjectId}`);
25
+ return browserPreviewServiceManager.getService(contextProjectId);
26
+ }
27
+
28
+ // 3. Fallback: Get first available project's service
29
+ const activeProjects = browserPreviewServiceManager.getActiveProjects();
30
+ if (activeProjects.length > 0) {
31
+ const fallbackProjectId = activeProjects[0];
32
+ debug.warn('mcp', `⚠️ No project context found, falling back to first active project: ${fallbackProjectId}`);
33
+ return browserPreviewServiceManager.getService(fallbackProjectId);
34
+ }
35
+
36
+ throw new Error('No active browser preview service found. Project isolation requires projectId.');
37
+ }
38
+
39
+ export async function getConsoleLogsHandler(args: {
40
+ limit?: number;
41
+ projectId?: string;
42
+ }) {
43
+ try {
44
+ // Get active tab and session
45
+ const { tab } = await getActiveTabSession(args.projectId);
46
+ const sessionId = tab.id;
47
+
48
+ // Get preview service
49
+ const previewService = getPreviewService(args.projectId);
50
+ const logs = previewService.getConsoleLogs(sessionId);
51
+
52
+ // Update last action to keep control alive
53
+ browserMcpControl.updateLastAction();
54
+
55
+ if (logs.length === 0) {
56
+ return {
57
+ content: [{
58
+ type: "text" as const,
59
+ text: "No console logs available."
60
+ }]
61
+ };
62
+ }
63
+
64
+ const limit = Math.min(args.limit || 20, 100);
65
+ const limitedLogs = logs.slice(-limit);
66
+ const formattedLogs = limitedLogs.map((log: any) => {
67
+ const timestamp = new Date(log.timestamp).toLocaleTimeString();
68
+ const type = log.type.toUpperCase().padEnd(5);
69
+ return `[${timestamp}] ${type} ${log.text}`;
70
+ }).join('\n');
71
+
72
+ return {
73
+ content: [{
74
+ type: "text" as const,
75
+ text: `Console Logs (${limitedLogs.length} of ${logs.length} total):\n\n${formattedLogs}`
76
+ }]
77
+ };
78
+ } catch (error) {
79
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
80
+ return {
81
+ content: [{
82
+ type: "text" as const,
83
+ text: `Failed to get console logs: ${errorMessage}`
84
+ }],
85
+ isError: true
86
+ };
87
+ }
88
+ }
89
+
90
+ export async function clearConsoleLogsHandler(args: { projectId?: string } = {}) {
91
+ try {
92
+ // Get active tab and session
93
+ const { tab } = await getActiveTabSession(args.projectId);
94
+ const sessionId = tab.id;
95
+
96
+ // Get preview service
97
+ const previewService = getPreviewService(args.projectId);
98
+ const success = previewService.clearConsoleLogs(sessionId);
99
+
100
+ // Update last action to keep control alive
101
+ browserMcpControl.updateLastAction();
102
+
103
+ if (!success) {
104
+ return {
105
+ content: [{
106
+ type: "text" as const,
107
+ text: `Failed to clear console logs.`
108
+ }],
109
+ isError: true
110
+ };
111
+ }
112
+
113
+ return {
114
+ content: [{
115
+ type: "text" as const,
116
+ text: "Console logs cleared successfully."
117
+ }]
118
+ };
119
+ } catch (error) {
120
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
121
+ return {
122
+ content: [{
123
+ type: "text" as const,
124
+ text: `Failed to clear console logs: ${errorMessage}`
125
+ }],
126
+ isError: true
127
+ };
128
+ }
129
+ }
130
+
131
+ export async function executeConsoleHandler(args: {
132
+ command: string;
133
+ projectId?: string;
134
+ }) {
135
+ try {
136
+ // Get active tab and session
137
+ const { tab } = await getActiveTabSession(args.projectId);
138
+ const sessionId = tab.id;
139
+
140
+ // Get preview service
141
+ const previewService = getPreviewService(args.projectId);
142
+ const result = await previewService.executeConsoleCommand(sessionId, args.command);
143
+
144
+ // Update last action to keep control alive
145
+ browserMcpControl.updateLastAction();
146
+
147
+ return {
148
+ content: [{
149
+ type: "text" as const,
150
+ text: `Execution successful.\n\nCommand: ${args.command}\n\nResult:\n${JSON.stringify(result, null, 2)}`
151
+ }]
152
+ };
153
+ } catch (error) {
154
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
155
+ return {
156
+ content: [{
157
+ type: "text" as const,
158
+ text: `Console execution failed: ${errorMessage}`
159
+ }],
160
+ isError: true
161
+ };
162
+ }
163
+ }
164
+
165
+ export async function analyzeDomHandler(args: {
166
+ include?: ('navigation' | 'structure' | 'content' | 'forms' | 'summary')[];
167
+ } = {}) {
168
+ try {
169
+ // Get active tab and session
170
+ const { session } = await getActiveTabSession();
171
+
172
+ // Execute comprehensive DOM analysis
173
+ const analysis = await session.page.evaluate(() => {
174
+ // Helper: Get visible text with proper spacing
175
+ const getVisibleText = (el: Element, maxLength: number = 500): string => {
176
+ // Helper to check if element is block-level
177
+ const isBlockElement = (elem: Element): boolean => {
178
+ const style = window.getComputedStyle(elem);
179
+ return style.display === 'block' ||
180
+ style.display === 'flex' ||
181
+ style.display === 'grid' ||
182
+ style.display === 'list-item' ||
183
+ style.display === 'table';
184
+ };
185
+
186
+ // Helper to check if element is visible
187
+ const isVisible = (elem: Element): boolean => {
188
+ const style = window.getComputedStyle(elem);
189
+ if (style.display === 'none' || style.visibility === 'hidden') {
190
+ return false;
191
+ }
192
+ const tagName = elem.tagName.toLowerCase();
193
+ return tagName !== 'script' && tagName !== 'style';
194
+ };
195
+
196
+ // Recursively extract text with proper separators
197
+ const extractText = (node: Node): string[] => {
198
+ const parts: string[] = [];
199
+
200
+ if (node.nodeType === Node.TEXT_NODE) {
201
+ const text = node.textContent?.trim();
202
+ if (text && text.length > 0) {
203
+ parts.push(text);
204
+ }
205
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
206
+ const elem = node as Element;
207
+
208
+ if (!isVisible(elem)) {
209
+ return parts;
210
+ }
211
+
212
+ const isBlock = isBlockElement(elem);
213
+ const childParts: string[] = [];
214
+
215
+ // Process all children
216
+ for (let i = 0; i < node.childNodes.length; i++) {
217
+ const childResults = extractText(node.childNodes[i]);
218
+ if (childResults.length > 0) {
219
+ childParts.push(...childResults);
220
+ }
221
+ }
222
+
223
+ if (childParts.length > 0) {
224
+ // Join child parts and add to results
225
+ const joined = childParts.join(' ');
226
+ parts.push(joined);
227
+
228
+ // Add block separator marker if this is a block element
229
+ if (isBlock && node.nextSibling) {
230
+ parts.push('|BLOCK|');
231
+ }
232
+ }
233
+ }
234
+
235
+ return parts;
236
+ };
237
+
238
+ // Extract all text parts
239
+ const textParts = extractText(el);
240
+
241
+ // Join parts and handle block separators
242
+ let result = textParts.join(' ');
243
+
244
+ // Replace block separator markers with ' || '
245
+ result = result.replace(/\s*\|BLOCK\|\s*/g, ' || ');
246
+
247
+ // Normalize whitespace (collapse multiple spaces)
248
+ result = result.replace(/\s+/g, ' ').trim();
249
+
250
+ // Clean up any remaining separator artifacts
251
+ // result = result.replace(/\|\s+\|/g, '').replace(/^\|\s*|\s*\|$/g, '');
252
+ result = result.replace(/\|\s+\|/g, '').replace(/\|\s+\|/g, '').replace(/^\|\s*|\s*\|$/g, '').replace(/^\|\s*|\s*\|$/g, '');
253
+
254
+ return result.substring(0, maxLength);
255
+ };
256
+
257
+ // Helper: Check if in viewport
258
+ // const inViewport = (el: Element): boolean => {
259
+ // const rect = el.getBoundingClientRect();
260
+ // return rect.top >= 0 && rect.left >= 0 &&
261
+ // rect.bottom <= window.innerHeight && rect.right <= window.innerWidth;
262
+ // };
263
+
264
+ // Summary
265
+ const summary = {
266
+ url: window.location.href,
267
+ title: document.title,
268
+ hasIframes: document.querySelectorAll('iframe').length > 0,
269
+ hasCaptcha: !!(
270
+ // reCAPTCHA
271
+ document.querySelector('iframe[src*="recaptcha"]') ||
272
+ document.querySelector('iframe[title*="recaptcha" i]') ||
273
+ document.querySelector('.g-recaptcha') ||
274
+ document.querySelector('[data-sitekey]') ||
275
+ // hCaptcha
276
+ document.querySelector('iframe[src*="hcaptcha"]') ||
277
+ document.querySelector('.h-captcha') ||
278
+ // Cloudflare
279
+ document.querySelector('.cf-challenge-running') ||
280
+ document.querySelector('#challenge-running') ||
281
+ document.querySelector('div[id*="cf-challenge"]') ||
282
+ // Turnstile
283
+ document.querySelector('iframe[src*="turnstile"]') ||
284
+ document.querySelector('.cf-turnstile') ||
285
+ // FunCaptcha/ArkoseLabs
286
+ document.querySelector('iframe[src*="funcaptcha"]') ||
287
+ document.querySelector('iframe[src*="arkoselabs"]') ||
288
+ // Generic captcha indicators
289
+ document.querySelector('[class*="captcha" i]') ||
290
+ document.querySelector('[id*="captcha" i]') ||
291
+ // Image/text based captchas
292
+ document.querySelector('img[alt*="captcha" i]') ||
293
+ document.querySelector('img[src*="captcha" i]')
294
+ ),
295
+ scrollableHeight: Math.max(
296
+ document.body.scrollHeight,
297
+ document.documentElement.scrollHeight
298
+ ),
299
+ viewportHeight: window.innerHeight
300
+ };
301
+
302
+ // Forms structure
303
+ const forms: any[] = [];
304
+ document.querySelectorAll('form').forEach((form, formIdx) => {
305
+ const fields: any[] = [];
306
+
307
+ form.querySelectorAll('input, textarea, select').forEach((field) => {
308
+ const tagName = field.tagName.toLowerCase();
309
+ const type = tagName === 'input' ? (field as HTMLInputElement).type : tagName;
310
+
311
+ let label = '';
312
+ const id = field.id;
313
+ if (id) {
314
+ const labelEl = document.querySelector(`label[for="${id}"]`);
315
+ if (labelEl) label = getVisibleText(labelEl);
316
+ }
317
+
318
+ if (!label) {
319
+ label = (field as any).placeholder || (field as any).name || '(no label)';
320
+ }
321
+
322
+ fields.push({
323
+ label,
324
+ type,
325
+ name: (field as any).name || '',
326
+ placeholder: (field as any).placeholder || '',
327
+ required: (field as any).required || false,
328
+ currentValue: (field as any).value || ''
329
+ });
330
+ });
331
+
332
+ forms.push({
333
+ formId: form.id || `form-${formIdx}`,
334
+ action: form.action || '',
335
+ fields
336
+ });
337
+ });
338
+
339
+ // Navigation - collect ALL links (not just nav), then deduplicate
340
+ const navigation = {
341
+ menus: [] as any[],
342
+ links: [] as any[]
343
+ };
344
+
345
+ // Collect all links with href
346
+ const seenHrefs = new Set<string>();
347
+ document.querySelectorAll('a[href]').forEach((link) => {
348
+ const href = (link as HTMLAnchorElement).href;
349
+ const text = getVisibleText(link, 150);
350
+
351
+ // Skip if: empty href, empty text, already seen, or anchor-only link
352
+ if (!href || !text || seenHrefs.has(href) || href.startsWith('#')) {
353
+ return;
354
+ }
355
+
356
+ seenHrefs.add(href);
357
+ navigation.links.push({
358
+ text,
359
+ href
360
+ });
361
+ });
362
+
363
+ // Page structure
364
+ const structure = {
365
+ headings: [] as any[],
366
+ sections: [] as any[]
367
+ };
368
+
369
+ // Collect headings
370
+ document.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach((heading) => {
371
+ structure.headings.push({
372
+ level: parseInt(heading.tagName.substring(1)),
373
+ text: getVisibleText(heading),
374
+ id: heading.id || ''
375
+ });
376
+ });
377
+
378
+ // Collect sections
379
+ document.querySelectorAll('section, article, main').forEach((section, idx) => {
380
+ const heading = section.querySelector('h1, h2, h3, h4, h5, h6');
381
+ const headingText = heading ? getVisibleText(heading, 200) : `Section ${idx + 1}`;
382
+ const summary = getVisibleText(section, 400);
383
+
384
+ structure.sections.push({
385
+ heading: headingText,
386
+ summary
387
+ });
388
+ });
389
+
390
+ // Text content - collect from various element types
391
+ const content = {
392
+ paragraphs: [] as string[]
393
+ };
394
+
395
+ // Collect text from paragraphs, divs, list items, table cells, spans
396
+ const seenTexts = new Set<string>();
397
+ const textSelectors = 'p, div:not(:has(p)):not(:has(div)), li, td, span:not(:has(span))';
398
+
399
+ document.querySelectorAll(textSelectors).forEach((el) => {
400
+ const text = getVisibleText(el, 800);
401
+
402
+ // Skip if: too short, already seen, or likely navigation/UI element
403
+ if (text.length < 10 || seenTexts.has(text)) {
404
+ return;
405
+ }
406
+
407
+ // Limit to 100 text items to avoid overflow
408
+ if (content.paragraphs.length >= 100) {
409
+ return;
410
+ }
411
+
412
+ seenTexts.add(text);
413
+ content.paragraphs.push(text);
414
+ });
415
+
416
+ return {
417
+ navigation,
418
+ structure,
419
+ content,
420
+ forms,
421
+ summary
422
+ };
423
+ });
424
+
425
+ // Filter sections if include provided
426
+ const includeSet = args.include ? new Set(args.include) : null;
427
+ let filtered: any = {};
428
+
429
+ if (includeSet) {
430
+ // Only include requested sections (in priority order)
431
+ if (includeSet.has('navigation')) filtered.navigation = analysis.navigation;
432
+ if (includeSet.has('structure')) filtered.structure = analysis.structure;
433
+ if (includeSet.has('content')) filtered.content = analysis.content;
434
+ if (includeSet.has('forms')) filtered.forms = analysis.forms;
435
+ if (includeSet.has('summary')) filtered.summary = analysis.summary;
436
+ } else {
437
+ // Include all sections
438
+ filtered = analysis;
439
+ }
440
+
441
+ // Update last action to keep control alive
442
+ browserMcpControl.updateLastAction();
443
+
444
+ return {
445
+ content: [{
446
+ type: "text" as const,
447
+ text: JSON.stringify(filtered, null, 2)
448
+ }]
449
+ };
450
+ } catch (error) {
451
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
452
+ return {
453
+ content: [{
454
+ type: "text" as const,
455
+ text: `DOM analysis failed: ${errorMessage}`
456
+ }],
457
+ isError: true
458
+ };
459
+ }
460
+ }
461
+
462
+ export async function takeScreenshotHandler() {
463
+ try {
464
+ // Get active tab and session
465
+ const { session } = await getActiveTabSession();
466
+
467
+ // ALWAYS capture viewport only (cost-efficient, fast)
468
+ const screenshot = await session.page.screenshot({
469
+ encoding: 'base64',
470
+ fullPage: false, // viewport only
471
+ type: 'png'
472
+ });
473
+
474
+ // Update last action to keep control alive
475
+ browserMcpControl.updateLastAction();
476
+
477
+ return {
478
+ content: [
479
+ {
480
+ type: "image" as const,
481
+ data: screenshot,
482
+ mimeType: "image/png"
483
+ },
484
+ {
485
+ type: "text" as const,
486
+ text: `Screenshot captured successfully (viewport only).`
487
+ }
488
+ ]
489
+ };
490
+ } catch (error) {
491
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
492
+
493
+ return {
494
+ content: [{
495
+ type: "text" as const,
496
+ text: `Screenshot failed: ${errorMessage}`
497
+ }],
498
+ isError: true
499
+ };
500
+ }
501
+ }
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Helper to define MCP servers with automatic metadata extraction
3
+ *
4
+ * Stores both the Claude SDK server instance AND raw tool definitions
5
+ * so the same source can be used for Claude Code (in-process) and
6
+ * Open Code (stdio subprocess via @modelcontextprotocol/sdk).
7
+ */
8
+
9
+ import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
10
+ import type { z } from "zod";
11
+
12
+ /**
13
+ * Infer argument types from Zod schema
14
+ */
15
+ type InferArgs<TSchema extends Record<string, z.ZodType<any>>> = {
16
+ [K in keyof TSchema]: z.infer<TSchema[K]>;
17
+ };
18
+
19
+ /**
20
+ * Content types for MCP responses
21
+ */
22
+ type MCPContent =
23
+ | { type: "text"; text: string }
24
+ | { type: "image"; data: string; mimeType: string };
25
+
26
+ /**
27
+ * Tool handler type - infers args type from schema
28
+ */
29
+ type ToolHandler<TSchema extends Record<string, z.ZodType<any>> | undefined> =
30
+ TSchema extends Record<string, z.ZodType<any>>
31
+ ? (args: InferArgs<TSchema>) => Promise<{ content: Array<MCPContent>; isError?: boolean }>
32
+ : () => Promise<{ content: Array<MCPContent>; isError?: boolean }>;
33
+
34
+ /**
35
+ * Raw tool definition — schema, description, and handler.
36
+ * Single source of truth used by:
37
+ * - Claude Code: in-process via createSdkMcpServer
38
+ * - Open Code stdio: schema/description for registration, handler via bridge
39
+ * - MCP bridge: handler for in-process execution
40
+ */
41
+ export interface RawToolDef {
42
+ description: string;
43
+ schema: Record<string, z.ZodType<any>>;
44
+ handler: (args: any) => Promise<{ content: Array<{ type: string; text?: string; data?: string; mimeType?: string }>; isError?: boolean }>;
45
+ }
46
+
47
+ /**
48
+ * Server instance with metadata
49
+ */
50
+ interface ServerWithMeta<
51
+ TName extends string,
52
+ TToolNames extends readonly string[]
53
+ > {
54
+ server: ReturnType<typeof createSdkMcpServer>;
55
+ meta: {
56
+ readonly name: TName;
57
+ readonly tools: TToolNames;
58
+ /** Raw tool definitions (schema + description) for reuse by other transports */
59
+ readonly toolDefs: Record<string, RawToolDef>;
60
+ };
61
+ }
62
+
63
+ /**
64
+ * Define an MCP server with automatic metadata extraction and full type inference
65
+ */
66
+ export function defineServer<
67
+ const TConfig extends {
68
+ name: string;
69
+ version: string;
70
+ tools: Record<string, { description: string; schema?: any; handler: any }>;
71
+ }
72
+ >(
73
+ config: TConfig & {
74
+ tools: {
75
+ [K in keyof TConfig['tools']]: TConfig['tools'][K] extends { schema: infer S extends Record<string, z.ZodType<any>> }
76
+ ? { description: string; schema: S; handler: ToolHandler<S> }
77
+ : { description: string; handler: ToolHandler<undefined> }
78
+ }
79
+ }
80
+ ): ServerWithMeta<TConfig['name'], ReadonlyArray<keyof TConfig['tools'] & string>> {
81
+ // Extract tool names
82
+ const toolNames = Object.keys(config.tools) as Array<keyof TConfig['tools'] & string>;
83
+
84
+ // Build raw tool definitions (engine-agnostic)
85
+ const toolDefs: Record<string, RawToolDef> = {};
86
+
87
+ // Convert tools object to SDK format (array of tools)
88
+ const sdkTools = toolNames.map((toolName) => {
89
+ const toolDef = config.tools[toolName] as any;
90
+ // If schema is not provided, use empty object
91
+ const schema = toolDef.schema || {};
92
+
93
+ // Store raw definition for reuse
94
+ toolDefs[toolName as string] = {
95
+ description: toolDef.description,
96
+ schema,
97
+ handler: toolDef.handler,
98
+ };
99
+
100
+ return tool(toolName as string, toolDef.description, schema, toolDef.handler);
101
+ });
102
+
103
+ // Create SDK server
104
+ const server = createSdkMcpServer({
105
+ name: config.name,
106
+ version: config.version,
107
+ tools: sdkTools
108
+ });
109
+
110
+ // Return server with metadata
111
+ return {
112
+ server,
113
+ meta: {
114
+ name: config.name,
115
+ tools: toolNames as any,
116
+ toolDefs,
117
+ }
118
+ };
119
+ }
120
+
121
+ /**
122
+ * Build server registries from array of servers
123
+ */
124
+ export function buildServerRegistries<
125
+ T extends readonly ServerWithMeta<string, readonly string[]>[]
126
+ >(servers: T) {
127
+ const metadata = {} as any;
128
+ const registry = {} as any;
129
+
130
+ for (const server of servers) {
131
+ metadata[server.meta.name] = server.meta;
132
+ registry[server.meta.name] = server.server;
133
+ }
134
+
135
+ return {
136
+ metadata: metadata as {
137
+ [K in T[number]['meta']['name']]: Extract<T[number], { meta: { name: K } }>['meta']
138
+ },
139
+ registry: registry as {
140
+ [K in T[number]['meta']['name']]: Extract<T[number], { meta: { name: K } }>['server']
141
+ }
142
+ };
143
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * MCP Servers Registry
3
+ *
4
+ * This file exports all custom MCP server implementations and provides
5
+ * a type-safe registry for server configuration.
6
+ *
7
+ * To add a new server:
8
+ * 1. Create your server file (e.g., ./my-server.ts) using defineServer
9
+ * 2. Import it and add to the allServers array below
10
+ * 3. Done! Registries are auto-built and type-safe.
11
+ */
12
+
13
+ import weather from './weather/index';
14
+ import browserAutomation from './browser-automation/index';
15
+ import { buildServerRegistries } from './helper';
16
+
17
+ // Re-export types for stdio server
18
+ export type { RawToolDef } from './helper';
19
+
20
+ /**
21
+ * All MCP Servers
22
+ *
23
+ * Simply import and add new servers to this array.
24
+ * Metadata and registry will be automatically built.
25
+ */
26
+ const allServers = [
27
+ weather,
28
+ browserAutomation,
29
+ // Add more servers here...
30
+ ] as const;
31
+
32
+ /**
33
+ * Auto-build registries from server array
34
+ */
35
+ const { metadata, registry } = buildServerRegistries(allServers);
36
+
37
+ /**
38
+ * Server Metadata Registry - Defines available servers and their tools
39
+ */
40
+ export const serverMetadata = metadata;
41
+
42
+ /**
43
+ * Server Instance Registry - Maps server names to SDK instances
44
+ */
45
+ export const serverRegistry = registry;