@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,1144 @@
1
+ # Custom MCP Tools
2
+
3
+ Custom MCP (Model Context Protocol) tools for adding specialized functionality to both **Claude Code** and **Open Code** engines. Servers are defined once and shared across both engines via a single-source-of-truth architecture.
4
+
5
+ ## 📚 Table of Contents
6
+
7
+ - [Overview](#overview)
8
+ - [Quick Start](#quick-start)
9
+ - [Architecture](#architecture)
10
+ - [Creating Custom Tools](#creating-custom-tools)
11
+ - [Configuration](#configuration)
12
+ - [API Reference](#api-reference)
13
+ - [Examples](#examples)
14
+ - [Best Practices](#best-practices)
15
+ - [Troubleshooting](#troubleshooting)
16
+
17
+ ---
18
+
19
+ ## Overview
20
+
21
+ **What is Custom MCP Tools?**
22
+ System for adding custom tools to AI engines with type-safe TypeScript definitions. Tools are defined once using `defineServer()` and automatically available to both Claude Code (in-process) and Open Code (stdio subprocess).
23
+
24
+ **Features:**
25
+ - Single source of truth — define tools once, use in both engines
26
+ - In-process execution for Claude Code via `createSdkMcpServer`
27
+ - Stdio subprocess for Open Code via `@modelcontextprotocol/sdk`
28
+ - WebSocket bridge for tool handlers that need in-process access
29
+ - Type-safe with TypeScript
30
+ - Auto metadata extraction and registration
31
+ - Configuration-based enable/disable
32
+ - Zod validation
33
+
34
+ ---
35
+
36
+ ## Quick Start
37
+
38
+ ### 1. Create a New Server
39
+
40
+ Create a new folder in `./servers/` (e.g., `calculator/`) and create an `index.ts` file using the `defineServer` helper:
41
+
42
+ **File: `./servers/calculator/index.ts`**
43
+ ```typescript
44
+ import { z } from "zod";
45
+ import { defineServer } from "../helper";
46
+
47
+ export default defineServer({
48
+ name: "calculator",
49
+ version: "1.0.0",
50
+ tools: {
51
+ "calculate": {
52
+ description: "Perform mathematical calculations",
53
+ schema: {
54
+ expression: z.string().describe("Mathematical expression to evaluate"),
55
+ precision: z.number().optional().default(2).describe("Decimal precision")
56
+ },
57
+ handler: async (args) => {
58
+ try {
59
+ // IMPORTANT: Use a safe math evaluation library in production!
60
+ // This is just an example - eval() is dangerous!
61
+ const result = eval(args.expression);
62
+ const formatted = Number(result).toFixed(args.precision);
63
+
64
+ return {
65
+ content: [{
66
+ type: "text",
67
+ text: `${args.expression} = ${formatted}`
68
+ }]
69
+ };
70
+ } catch (error) {
71
+ return {
72
+ content: [{
73
+ type: "text",
74
+ text: `Error: Invalid expression - ${error.message}`
75
+ }],
76
+ isError: true
77
+ };
78
+ }
79
+ }
80
+ }
81
+ }
82
+ });
83
+ ```
84
+
85
+ ### 2. Register the Server
86
+
87
+ Add to `./servers/index.ts` to auto-build registries:
88
+
89
+ ```typescript
90
+ import weather from './weather';
91
+ import calculator from './calculator';
92
+ import { buildServerRegistries } from './helper';
93
+
94
+ const allServers = [
95
+ weather,
96
+ calculator, // Simply add your server here!
97
+ // Add more servers...
98
+ ] as const;
99
+
100
+ const { metadata, registry } = buildServerRegistries(allServers);
101
+
102
+ export const serverMetadata = metadata;
103
+ export const serverRegistry = registry;
104
+ ```
105
+
106
+ ### 3. Configure the Server
107
+
108
+ Add to `./config.ts` (only specify `enabled` and `tools`):
109
+
110
+ ```typescript
111
+ const mcpServersConfig: Record<ServerName, ServerConfig> = {
112
+ "weather-service": {
113
+ enabled: true,
114
+ tools: ["get_temperature"]
115
+ },
116
+
117
+ // Add your new server config
118
+ "calculator": {
119
+ enabled: true,
120
+ tools: ["calculate"] // Type-safe! Only valid tool names allowed
121
+ }
122
+ };
123
+ ```
124
+
125
+ ### 4. Done!
126
+
127
+ Tool available to Claude as: `mcp__calculator__calculate`
128
+
129
+ ---
130
+
131
+ ## Architecture
132
+
133
+ ```
134
+ backend/lib/mcp/
135
+ ├── types.ts # TypeScript type definitions (auto-inferred from metadata)
136
+ ├── config.ts # User configuration (enabled, tools) + auto-merge with registry
137
+ │ # + resolveOpenCodeToolName() & getOpenCodeMcpConfig()
138
+ ├── index.ts # Main export point
139
+ ├── stdio-server.ts # Standalone MCP stdio server for Open Code (subprocess)
140
+ ├── servers/ # Server implementations (single source of truth)
141
+ │ ├── index.ts # Auto-build registries from server array
142
+ │ ├── helper.ts # defineServer & buildServerRegistries functions
143
+ │ ├── weather/ # Example: Weather service
144
+ │ │ ├── index.ts # Server definition using defineServer
145
+ │ │ └── get-temperature.ts # Tool handler implementation
146
+ │ └── browser-automation/ # Example: Browser automation service
147
+ │ ├── index.ts # Server definition
148
+ │ ├── session.ts # Session management handlers
149
+ │ ├── navigation.ts # Navigation handlers
150
+ │ └── ... # Other tool handlers
151
+ └── README.md # This file
152
+
153
+ backend/ws/mcp/ # WebSocket bridge route (lives in ws/ per convention)
154
+ └── index.ts # WS .http() route for stdio server → main server
155
+ ```
156
+
157
+ ### Server Organization
158
+
159
+ For simple servers with one or two tools, you can keep all logic in `index.ts`:
160
+ ```
161
+ servers/
162
+ └── simple-server/
163
+ └── index.ts # All tools defined here
164
+ ```
165
+
166
+ For complex servers with many tools, split handlers into separate files:
167
+ ```
168
+ servers/
169
+ └── complex-server/
170
+ ├── index.ts # Server definition using defineServer
171
+ ├── tool-a.ts # Handler for tool A
172
+ ├── tool-b.ts # Handler for tool B
173
+ └── utils.ts # Shared utilities
174
+ ```
175
+
176
+ Example structure from `browser-automation`:
177
+ ```
178
+ servers/browser-automation/
179
+ ├── index.ts # Main server definition with all tools
180
+ ├── session.ts # Session management handlers
181
+ ├── navigation.ts # Navigation handlers
182
+ ├── actions.ts # Browser action handlers
183
+ ├── inspection.ts # Page inspection handlers
184
+ └── ... # Other organized handler files
185
+ ```
186
+
187
+ ### Data Flow
188
+
189
+ **Claude Code (in-process):**
190
+ ```
191
+ 1. Server Definition (servers/weather/index.ts)
192
+ └─> defineServer() extracts metadata automatically
193
+
194
+ 2. Registry Building (servers/index.ts)
195
+ └─> buildServerRegistries() creates metadata + registry
196
+
197
+ 3. Configuration (config.ts)
198
+ └─> User config merged with registry automatically
199
+
200
+ 4. Claude Agent SDK (stream.ts)
201
+ └─> Uses getEnabledMcpServers()
202
+
203
+ 5. Claude uses the tool (in-process handler execution)
204
+
205
+ 6. UI displays result (CustomMcpTool.svelte)
206
+ ```
207
+
208
+ **Open Code (stdio subprocess + WS bridge):**
209
+ ```
210
+ 1. Server Definition (servers/weather/index.ts)
211
+ └─> Same defineServer() — single source of truth
212
+
213
+ 2. Open Code engine (opencode/stream.ts)
214
+ └─> Uses getOpenCodeMcpConfig() → spawns stdio-server.ts
215
+
216
+ 3. stdio-server.ts (subprocess)
217
+ └─> Reads serverMetadata for tool schemas/descriptions
218
+ └─> Registers tools via @modelcontextprotocol/sdk
219
+
220
+ 4. Open Code calls a tool → stdio-server receives JSON-RPC
221
+
222
+ 5. stdio-server proxies via WSClient.http('mcp:execute', ...)
223
+
224
+ 6. WS bridge route (backend/ws/mcp/)
225
+ └─> Looks up handler from serverMetadata.toolDefs
226
+ └─> Executes handler in-process (same context as main server)
227
+
228
+ 7. Response flows back: bridge → WSClient → stdio → Open Code
229
+
230
+ 8. UI displays result (CustomMcpTool.svelte)
231
+ ```
232
+
233
+ ### Key Components
234
+
235
+ **`defineServer`**
236
+ Helper function to define MCP server with automatic metadata extraction.
237
+ Stores both Claude SDK server instance AND raw tool definitions (`toolDefs`)
238
+ for reuse by other transports (stdio server, bridge).
239
+
240
+ **`buildServerRegistries`**
241
+ Function to build server registries from server array.
242
+
243
+ **`mcpServers`**
244
+ Final configuration combining user config with server instances.
245
+
246
+ **`stdio-server.ts`**
247
+ Standalone MCP stdio server subprocess spawned by Open Code. Reads tool
248
+ definitions from `serverMetadata` and proxies all calls to the main server
249
+ via `WSClient.http()`. Uses `@modelcontextprotocol/sdk` for MCP protocol.
250
+
251
+ **`backend/ws/mcp/`**
252
+ WebSocket `.http()` route that receives tool calls from the stdio server
253
+ and executes handlers in-process. Lives in `backend/ws/` per the WS
254
+ module convention (see `backend/ws/README.md`).
255
+
256
+ ---
257
+
258
+ ## Creating Custom Tools
259
+
260
+ ### Folder Structure
261
+
262
+ Each MCP server should be in its own folder under `./servers/`:
263
+
264
+ 1. **Create a folder**: `./servers/your-server-name/`
265
+ 2. **Create index.ts**: Main server definition file
266
+ 3. **Optional**: Create separate files for tool handlers (e.g., `tool-name.ts`)
267
+
268
+ Example:
269
+ ```
270
+ servers/
271
+ └── your-server-name/
272
+ ├── index.ts # Server definition
273
+ ├── handler-1.ts # Optional: Separate handler file
274
+ └── handler-2.ts # Optional: Another handler file
275
+ ```
276
+
277
+ ### Tool Definition Format
278
+
279
+ Tools are defined as an object. Each tool has three components:
280
+
281
+ ```typescript
282
+ {
283
+ "tool_name": {
284
+ description: string, // Tool description for Claude
285
+ schema: Record<string, ZodType>, // Zod schema (plain object, not wrapped)
286
+ handler: async (args) => Promise<ToolResult> // Handler function
287
+ }
288
+ }
289
+ ```
290
+
291
+ ### Input Schema (Zod)
292
+
293
+ Define schema as a plain object of Zod types:
294
+
295
+ ```typescript
296
+ schema: {
297
+ // Required string
298
+ name: z.string().describe("User's name"),
299
+
300
+ // Required number with constraints
301
+ age: z.number().min(0).max(150).describe("User's age"),
302
+
303
+ // Optional with default
304
+ format: z.enum(["json", "csv"]).default("json").describe("Output format"),
305
+
306
+ // Optional field
307
+ email: z.string().email().optional().describe("Email address"),
308
+
309
+ // Array
310
+ tags: z.array(z.string()).describe("List of tags"),
311
+
312
+ // Nested object
313
+ address: z.object({
314
+ street: z.string(),
315
+ city: z.string(),
316
+ zipCode: z.string()
317
+ }).describe("User address")
318
+ }
319
+ ```
320
+
321
+ **Note:** The schema is automatically wrapped in `z.object()` by `defineServer`.
322
+
323
+ ### Handler Function
324
+
325
+ The handler receives validated arguments and returns a result:
326
+
327
+ ```typescript
328
+ async (args) => {
329
+ try {
330
+ // Do your work here
331
+ const result = await someAsyncOperation(args);
332
+
333
+ // Return success
334
+ return {
335
+ content: [{
336
+ type: "text",
337
+ text: `Result: ${result}`
338
+ }]
339
+ };
340
+
341
+ } catch (error) {
342
+ // Return error
343
+ return {
344
+ content: [{
345
+ type: "text",
346
+ text: `Error: ${error.message}`
347
+ }],
348
+ isError: true
349
+ };
350
+ }
351
+ }
352
+ ```
353
+
354
+ ### Return Format
355
+
356
+ Tools must return an object with this structure:
357
+
358
+ ```typescript
359
+ {
360
+ content: Array<{
361
+ type: "text" | "image" | "resource",
362
+ text?: string, // For type: "text"
363
+ // Additional fields for other types
364
+ }>,
365
+ isError?: boolean // Mark as error result
366
+ }
367
+ ```
368
+
369
+ ---
370
+
371
+ ## Configuration
372
+
373
+ ### Server Configuration
374
+
375
+ Configuration is split into two parts:
376
+
377
+ **1. User Configuration (`mcpServersConfig` in `config.ts`):**
378
+ ```typescript
379
+ const mcpServersConfig: Record<ServerName, ServerConfig> = {
380
+ "weather-service": {
381
+ enabled: boolean, // Whether server is active
382
+ tools: readonly string[] // Array of enabled tool names (type-safe!)
383
+ }
384
+ };
385
+ ```
386
+
387
+ **2. Auto-Merged with Registry:**
388
+ Server instances from `serverRegistry` are automatically merged to create the final `mcpServers` object:
389
+
390
+ ```typescript
391
+ // Final structure (after merge):
392
+ {
393
+ instance: McpSdkServerConfigWithInstance, // From registry
394
+ enabled: boolean, // From user config
395
+ tools: readonly string[] // From user config (type-validated)
396
+ }
397
+ ```
398
+
399
+ ### Environment Variables & Secrets
400
+
401
+ For tools that require API keys or secrets:
402
+
403
+ 1. **Never hardcode secrets** in the code
404
+ 2. Use environment variables:
405
+
406
+ ```typescript
407
+ async (args) => {
408
+ // Get API key from environment
409
+ const apiKey = process.env.MY_API_KEY;
410
+
411
+ if (!apiKey) {
412
+ return {
413
+ content: [{
414
+ type: "text",
415
+ text: "Error: MY_API_KEY environment variable not set"
416
+ }],
417
+ isError: true
418
+ };
419
+ }
420
+
421
+ // Use the API key
422
+ const response = await fetch(url, {
423
+ headers: {
424
+ 'Authorization': `Bearer ${apiKey}`
425
+ }
426
+ });
427
+
428
+ // ... rest of implementation
429
+ }
430
+ ```
431
+
432
+ 3. Add to `.env` file:
433
+ ```bash
434
+ MY_API_KEY=your-secret-key-here
435
+ ```
436
+
437
+ ---
438
+
439
+ ## API Reference
440
+
441
+ ### Main Exports
442
+
443
+ #### Type Definitions
444
+ ```typescript
445
+ import type {
446
+ ServerName, // Union of all server names (from metadata)
447
+ ToolsForServer, // Tool names for a specific server (from metadata)
448
+ ServerConfig, // User config structure
449
+ McpServerConfigWithInstance, // Config + instance structure
450
+ ParsedMcpToolName, // Parsed tool name components
451
+ McpServerStatus // Server status from SDK
452
+ } from '$backend/lib/mcp';
453
+ ```
454
+
455
+ #### Main Configuration
456
+
457
+ **`mcpServers`** - Final merged configuration:
458
+ ```typescript
459
+ import { mcpServers } from '$backend/lib/mcp';
460
+
461
+ // Access server configuration
462
+ const weatherConfig = mcpServers["weather-service"];
463
+ // {
464
+ // instance: McpSdkServerConfigWithInstance,
465
+ // enabled: true,
466
+ // tools: ["get_temperature"]
467
+ // }
468
+ ```
469
+
470
+ #### Server Registries
471
+
472
+ **`serverMetadata`** - Metadata for type inference:
473
+ ```typescript
474
+ import { serverMetadata } from '$backend/lib/mcp/servers';
475
+
476
+ // Access metadata
477
+ const weatherMeta = serverMetadata["weather-service"];
478
+ // { name: "weather-service", tools: ["get_temperature"] }
479
+ ```
480
+
481
+ **`serverRegistry`** - Server instances:
482
+ ```typescript
483
+ import { serverRegistry } from '$backend/lib/mcp/servers';
484
+
485
+ // Access server instance
486
+ const weatherServer = serverRegistry["weather-service"];
487
+ ```
488
+
489
+ ### Main Functions
490
+
491
+ #### `getEnabledMcpServers()`
492
+ Returns all enabled MCP servers for use with Claude SDK.
493
+
494
+ ```typescript
495
+ import { getEnabledMcpServers } from '$backend/lib/mcp';
496
+
497
+ const servers = getEnabledMcpServers();
498
+ // Returns: Record<string, McpServerConfig>
499
+ ```
500
+
501
+ #### `getAllowedMcpTools()`
502
+ Returns array of allowed tool names (formatted for Claude SDK).
503
+
504
+ ```typescript
505
+ import { getAllowedMcpTools } from '$backend/lib/mcp';
506
+
507
+ const tools = getAllowedMcpTools();
508
+ // Returns: ["mcp__weather-service__get_temperature", ...]
509
+ ```
510
+
511
+ #### `parseMcpToolName(fullName)`
512
+ Parse MCP tool name into components.
513
+
514
+ ```typescript
515
+ import { parseMcpToolName } from '$backend/lib/mcp';
516
+
517
+ const parsed = parseMcpToolName("mcp__weather-service__get_temperature");
518
+ // Returns: { server: "weather-service", tool: "get_temperature", fullName: "..." }
519
+ ```
520
+
521
+ #### `isMcpTool(toolName)`
522
+ Check if a tool name is a custom MCP tool.
523
+
524
+ ```typescript
525
+ import { isMcpTool } from '$backend/lib/mcp';
526
+
527
+ isMcpTool("mcp__weather-service__get_temperature"); // true
528
+ isMcpTool("Bash"); // false
529
+ ```
530
+
531
+ #### `getOpenCodeMcpConfig()`
532
+ Returns MCP configuration for Open Code engine (spawns stdio subprocess).
533
+
534
+ ```typescript
535
+ import { getOpenCodeMcpConfig } from '$backend/lib/mcp';
536
+
537
+ const mcpConfig = getOpenCodeMcpConfig();
538
+ // Returns: { 'clopen-mcp': { type: 'local', command: ['bun', 'run', '...'], ... } }
539
+ ```
540
+
541
+ #### `resolveOpenCodeToolName(toolName)`
542
+ Resolve an Open Code tool name to `mcp__server__tool` format (single source of truth).
543
+
544
+ ```typescript
545
+ import { resolveOpenCodeToolName } from '$backend/lib/mcp';
546
+
547
+ resolveOpenCodeToolName("clopen-mcp_get_temperature");
548
+ // Returns: "mcp__weather-service__get_temperature"
549
+
550
+ resolveOpenCodeToolName("get_temperature");
551
+ // Returns: "mcp__weather-service__get_temperature"
552
+
553
+ resolveOpenCodeToolName("unknown_tool");
554
+ // Returns: null
555
+ ```
556
+
557
+ ### Helper Functions
558
+
559
+ ```typescript
560
+ import {
561
+ getServerConfig,
562
+ getToolConfig,
563
+ isServerEnabled,
564
+ isToolEnabled,
565
+ getEnabledServerNames,
566
+ getEnabledToolsForServer,
567
+ getMcpStats
568
+ } from '$backend/lib/mcp';
569
+
570
+ // Get server configuration (includes instance)
571
+ const config = getServerConfig("weather-service");
572
+
573
+ // Get tool configuration
574
+ const hasTemperature = getToolConfig("weather-service", "get_temperature");
575
+
576
+ // Check if server/tool enabled
577
+ const serverEnabled = isServerEnabled("weather-service");
578
+ const toolEnabled = isToolEnabled("weather-service", "get_temperature");
579
+
580
+ // Get enabled server names
581
+ const enabledServers = getEnabledServerNames();
582
+ // Returns: ["weather-service", ...]
583
+
584
+ // Get enabled tools for a server
585
+ const tools = getEnabledToolsForServer("weather-service");
586
+ // Returns: ["mcp__weather-service__get_temperature", ...]
587
+
588
+ // Get statistics
589
+ const stats = getMcpStats();
590
+ // Returns: {
591
+ // totalServers: number,
592
+ // enabledServers: number,
593
+ // totalTools: number,
594
+ // serverNames: string[],
595
+ // toolNames: string[]
596
+ // }
597
+ ```
598
+
599
+ ---
600
+
601
+ ## Examples
602
+
603
+ ### Example 1: Weather Service (Included)
604
+
605
+ **Simple approach** - All logic in `index.ts`:
606
+
607
+ **File: `servers/weather/index.ts`**
608
+ ```typescript
609
+ import { z } from "zod";
610
+ import { defineServer } from "../helper";
611
+
612
+ export default defineServer({
613
+ name: "weather-service",
614
+ version: "1.0.0",
615
+ tools: {
616
+ "get_temperature": {
617
+ description: "Get current temperature for a location using coordinates. Returns temperature in Fahrenheit.",
618
+ schema: {
619
+ latitude: z.number().min(-90).max(90).describe("Latitude coordinate (-90 to 90)"),
620
+ longitude: z.number().min(-180).max(180).describe("Longitude coordinate (-180 to 180)")
621
+ },
622
+ handler: async (args) => {
623
+ try {
624
+ const url = `https://api.open-meteo.com/v1/forecast?latitude=${args.latitude}&longitude=${args.longitude}&current=temperature_2m&temperature_unit=fahrenheit`;
625
+ const response = await fetch(url);
626
+
627
+ if (!response.ok) {
628
+ return {
629
+ content: [{
630
+ type: "text",
631
+ text: `Failed to fetch weather data: ${response.status} ${response.statusText}`
632
+ }],
633
+ isError: true
634
+ };
635
+ }
636
+
637
+ const data = await response.json();
638
+ const temperature = data.current.temperature_2m;
639
+ const unit = data.current_units?.temperature_2m || "°F";
640
+
641
+ return {
642
+ content: [{
643
+ type: "text",
644
+ text: `Temperature: ${temperature}${unit}`
645
+ }]
646
+ };
647
+ } catch (error) {
648
+ return {
649
+ content: [{
650
+ type: "text",
651
+ text: `Error fetching temperature: ${error.message}`
652
+ }],
653
+ isError: true
654
+ };
655
+ }
656
+ }
657
+ }
658
+ }
659
+ });
660
+ ```
661
+
662
+ **Organized approach** - Separate handler file:
663
+
664
+ **File: `servers/weather/get-temperature.ts`**
665
+ ```typescript
666
+ export async function getTemperatureHandler(args: { latitude: number; longitude: number }) {
667
+ try {
668
+ const url = `https://api.open-meteo.com/v1/forecast?latitude=${args.latitude}&longitude=${args.longitude}&current=temperature_2m&temperature_unit=fahrenheit`;
669
+ const response = await fetch(url);
670
+
671
+ if (!response.ok) {
672
+ return {
673
+ content: [{
674
+ type: "text",
675
+ text: `Failed to fetch weather data: ${response.status} ${response.statusText}`
676
+ }],
677
+ isError: true
678
+ };
679
+ }
680
+
681
+ const data = await response.json();
682
+ const temperature = data.current.temperature_2m;
683
+ const unit = data.current_units?.temperature_2m || "°F";
684
+
685
+ return {
686
+ content: [{
687
+ type: "text",
688
+ text: `Temperature: ${temperature}${unit}`
689
+ }]
690
+ };
691
+ } catch (error) {
692
+ return {
693
+ content: [{
694
+ type: "text",
695
+ text: `Error fetching temperature: ${error.message}`
696
+ }],
697
+ isError: true
698
+ };
699
+ }
700
+ }
701
+ ```
702
+
703
+ **File: `servers/weather/index.ts`**
704
+ ```typescript
705
+ import { z } from "zod";
706
+ import { defineServer } from "../helper";
707
+ import { getTemperatureHandler } from "./get-temperature";
708
+
709
+ export default defineServer({
710
+ name: "weather-service",
711
+ version: "1.0.0",
712
+ tools: {
713
+ "get_temperature": {
714
+ description: "Get current temperature for a location using coordinates. Returns temperature in Fahrenheit.",
715
+ schema: {
716
+ latitude: z.number().min(-90).max(90).describe("Latitude coordinate (-90 to 90)"),
717
+ longitude: z.number().min(-180).max(180).describe("Longitude coordinate (-180 to 180)")
718
+ },
719
+ handler: getTemperatureHandler
720
+ }
721
+ }
722
+ });
723
+ ```
724
+
725
+ ### Example 2: Database Query
726
+
727
+ Execute database queries with connection pooling:
728
+
729
+ ```typescript
730
+ import { z } from "zod";
731
+ import { defineServer } from "../helper";
732
+ import { Pool } from 'pg'; // PostgreSQL client
733
+
734
+ // Create connection pool (outside defineServer)
735
+ const pool = new Pool({
736
+ connectionString: process.env.DATABASE_URL
737
+ });
738
+
739
+ export default defineServer({
740
+ name: "database",
741
+ version: "1.0.0",
742
+ tools: {
743
+ "query_database": {
744
+ description: "Execute a read-only database query",
745
+ schema: {
746
+ query: z.string().describe("SQL query to execute (SELECT only)"),
747
+ params: z.array(z.any()).optional().describe("Query parameters")
748
+ },
749
+ handler: async (args) => {
750
+ try {
751
+ // Validate query is SELECT only
752
+ if (!args.query.trim().toLowerCase().startsWith('select')) {
753
+ return {
754
+ content: [{
755
+ type: "text",
756
+ text: "Error: Only SELECT queries are allowed"
757
+ }],
758
+ isError: true
759
+ };
760
+ }
761
+
762
+ const result = await pool.query(args.query, args.params || []);
763
+
764
+ return {
765
+ content: [{
766
+ type: "text",
767
+ text: `Found ${result.rowCount} rows:\n${JSON.stringify(result.rows, null, 2)}`
768
+ }]
769
+ };
770
+
771
+ } catch (error) {
772
+ return {
773
+ content: [{
774
+ type: "text",
775
+ text: `Database error: ${error.message}`
776
+ }],
777
+ isError: true
778
+ };
779
+ }
780
+ }
781
+ }
782
+ }
783
+ });
784
+ ```
785
+
786
+ ### Example 3: API Gateway
787
+
788
+ Make authenticated requests to external APIs:
789
+
790
+ ```typescript
791
+ import { z } from "zod";
792
+ import { defineServer } from "../helper";
793
+
794
+ // Service configurations (outside defineServer)
795
+ const configs = {
796
+ github: {
797
+ baseUrl: "https://api.github.com",
798
+ token: process.env.GITHUB_TOKEN
799
+ },
800
+ slack: {
801
+ baseUrl: "https://slack.com/api",
802
+ token: process.env.SLACK_TOKEN
803
+ },
804
+ stripe: {
805
+ baseUrl: "https://api.stripe.com/v1",
806
+ token: process.env.STRIPE_KEY
807
+ }
808
+ };
809
+
810
+ export default defineServer({
811
+ name: "api-gateway",
812
+ version: "1.0.0",
813
+ tools: {
814
+ "api_request": {
815
+ description: "Make authenticated API requests to external services",
816
+ schema: {
817
+ service: z.enum(["github", "slack", "stripe"]).describe("Service to call"),
818
+ endpoint: z.string().describe("API endpoint path"),
819
+ method: z.enum(["GET", "POST", "PUT", "DELETE"]).describe("HTTP method"),
820
+ body: z.record(z.any()).optional().describe("Request body")
821
+ },
822
+ handler: async (args) => {
823
+ const config = configs[args.service];
824
+ const url = `${config.baseUrl}${args.endpoint}`;
825
+
826
+ const response = await fetch(url, {
827
+ method: args.method,
828
+ headers: {
829
+ 'Authorization': `Bearer ${config.token}`,
830
+ 'Content-Type': 'application/json'
831
+ },
832
+ body: args.body ? JSON.stringify(args.body) : undefined
833
+ });
834
+
835
+ const data = await response.json();
836
+
837
+ return {
838
+ content: [{
839
+ type: "text",
840
+ text: JSON.stringify(data, null, 2)
841
+ }]
842
+ };
843
+ }
844
+ }
845
+ }
846
+ });
847
+ ```
848
+
849
+ ### Example 4: File Operations
850
+
851
+ Read and process files from the filesystem:
852
+
853
+ ```typescript
854
+ import { z } from "zod";
855
+ import { defineServer } from "../helper";
856
+
857
+ export default defineServer({
858
+ name: "file-utils",
859
+ version: "1.0.0",
860
+ tools: {
861
+ "count_lines": {
862
+ description: "Count lines in a file",
863
+ schema: {
864
+ filePath: z.string().describe("Path to the file")
865
+ },
866
+ handler: async (args) => {
867
+ try {
868
+ const content = await Bun.file(args.filePath).text();
869
+ const lines = content.split('\n').length;
870
+
871
+ return {
872
+ content: [{
873
+ type: "text",
874
+ text: `File has ${lines} lines`
875
+ }]
876
+ };
877
+ } catch (error) {
878
+ return {
879
+ content: [{
880
+ type: "text",
881
+ text: `Error reading file: ${error.message}`
882
+ }],
883
+ isError: true
884
+ };
885
+ }
886
+ }
887
+ }
888
+ }
889
+ });
890
+ ```
891
+
892
+ ---
893
+
894
+ ## Best Practices
895
+
896
+ ### 1. Error Handling
897
+
898
+ Always wrap tool logic in try-catch and return meaningful errors:
899
+
900
+ ```typescript
901
+ async (args) => {
902
+ try {
903
+ // Your logic here
904
+ return { content: [{ type: "text", text: result }] };
905
+ } catch (error) {
906
+ return {
907
+ content: [{ type: "text", text: `Error: ${error.message}` }],
908
+ isError: true
909
+ };
910
+ }
911
+ }
912
+ ```
913
+
914
+ ### 2. Input Validation
915
+
916
+ Use Zod constraints for robust validation:
917
+
918
+ ```typescript
919
+ {
920
+ email: z.string().email().describe("Valid email address"),
921
+ age: z.number().min(0).max(150).describe("Age in years"),
922
+ url: z.string().url().describe("Valid URL")
923
+ }
924
+ ```
925
+
926
+ ### 3. Descriptive Messages
927
+
928
+ Provide clear descriptions for Claude to understand tool usage:
929
+
930
+ ```typescript
931
+ {
932
+ "send_email": {
933
+ description: "Send an email to a recipient. Use this when the user explicitly asks to send an email.",
934
+ schema: { /* ... */ },
935
+ handler: async (args) => { /* ... */ }
936
+ }
937
+ }
938
+ ```
939
+
940
+ ### 4. Resource Management
941
+
942
+ Clean up resources properly:
943
+
944
+ ```typescript
945
+ handler: async (args) => {
946
+ const connection = await createConnection();
947
+
948
+ try {
949
+ const result = await connection.query(args.query);
950
+ return { content: [{ type: "text", text: result }] };
951
+ } finally {
952
+ await connection.close(); // Always clean up
953
+ }
954
+ }
955
+ ```
956
+
957
+ ### 5. Security
958
+
959
+ ```typescript
960
+ // Use environment variables for secrets
961
+ const apiKey = process.env.API_KEY;
962
+ if (!apiKey) {
963
+ return { content: [{ type: "text", text: "API key not configured" }], isError: true };
964
+ }
965
+
966
+ // Validate user input with Zod
967
+ // Use read-only database connections
968
+ // Sanitize file paths
969
+ ```
970
+
971
+ ### 6. Performance
972
+
973
+ ```typescript
974
+ // Use connection pool (create once, outside defineServer)
975
+ const pool = new Pool({ connectionString: process.env.DATABASE_URL });
976
+
977
+ export default defineServer({
978
+ name: "database",
979
+ version: "1.0.0",
980
+ tools: {
981
+ "query": {
982
+ description: "Execute a query",
983
+ schema: { query: z.string() },
984
+ handler: async (args) => {
985
+ const result = await pool.query(args.query);
986
+ // ...
987
+ }
988
+ }
989
+ }
990
+ });
991
+ ```
992
+
993
+ ---
994
+
995
+ ## Troubleshooting
996
+
997
+ ### Tool Not Appearing
998
+
999
+ **Problem:** My custom tool doesn't appear in Claude's available tools.
1000
+
1001
+ **Solutions:**
1002
+ 1. Verify server folder exists in `./servers/` with an `index.ts` file
1003
+ 2. Verify server is defined using `defineServer` and exported as default (`export default defineServer(...)`)
1004
+ 3. Check server is imported and added to `allServers` array in `servers/index.ts`
1005
+ 4. Check that server is enabled in `mcpServersConfig` in `config.ts`
1006
+ 5. Check that tool is listed in `tools` array in `config.ts`
1007
+ 6. Verify tool name format: `mcp__{server}__{tool}`
1008
+ 7. Check console for MCP initialization errors or TypeScript errors
1009
+
1010
+ ### Connection Errors
1011
+
1012
+ **Problem:** MCP server fails to connect.
1013
+
1014
+ **Check:**
1015
+ - Server uses `defineServer` and exports as default (`export default defineServer(...)`)
1016
+ - Server is imported in `servers/index.ts` and added to `allServers` array
1017
+ - No syntax errors in server file
1018
+ - All dependencies are installed (`bun install`)
1019
+ - Console logs show initialization
1020
+ - Run `bun run check` to catch TypeScript errors
1021
+
1022
+ ### Tool Execution Fails
1023
+
1024
+ **Problem:** Tool executes but returns errors.
1025
+
1026
+ **Debug:**
1027
+ 1. Check error message in Claude's response
1028
+ 2. Look at server logs/console output
1029
+ 3. Verify input schema matches what Claude is sending
1030
+ 4. Test tool handler independently
1031
+ 5. Check for missing environment variables
1032
+
1033
+ ### Environment Variables Not Working
1034
+
1035
+ **Problem:** `process.env.MY_KEY` returns undefined.
1036
+
1037
+ **Solutions:**
1038
+ 1. Add to `.env` file in project root
1039
+ 2. Restart the application (env vars are loaded at startup)
1040
+ 3. Check that variable name matches exactly
1041
+ 4. Verify `.env` file is not gitignored
1042
+
1043
+ ### Type Errors
1044
+
1045
+ **Problem:** TypeScript errors in custom tool.
1046
+
1047
+ **Solutions:**
1048
+ 1. Install dependencies: `bun install zod @anthropic-ai/claude-agent-sdk`
1049
+ 2. Verify you're importing `defineServer` from `../helper`
1050
+ 3. Check that server name matches between `defineServer` and `config.ts`
1051
+ 4. Verify tool names in `config.ts` match tool keys in `defineServer`
1052
+ 5. Ensure schema is a plain object, not wrapped in `z.object()`
1053
+ 6. Run `bun run check` to see all errors
1054
+
1055
+ **Common Type Errors:**
1056
+
1057
+ ```typescript
1058
+ // ❌ Wrong - wrapped in z.object()
1059
+ schema: z.object({
1060
+ name: z.string()
1061
+ })
1062
+
1063
+ // ✅ Correct - plain object
1064
+ schema: {
1065
+ name: z.string()
1066
+ }
1067
+
1068
+ // ❌ Wrong - invalid tool name in config
1069
+ "calculator": {
1070
+ enabled: true,
1071
+ tools: ["add", "multiply"] // "multiply" doesn't exist in defineServer
1072
+ }
1073
+
1074
+ // ✅ Correct - matches defineServer
1075
+ "calculator": {
1076
+ enabled: true,
1077
+ tools: ["add"] // Tool exists in defineServer
1078
+ }
1079
+ ```
1080
+
1081
+ ---
1082
+
1083
+ ## Open Code Integration
1084
+
1085
+ ### How It Works
1086
+
1087
+ Open Code uses a **stdio subprocess** pattern for MCP tools. The integration has three parts:
1088
+
1089
+ 1. **`stdio-server.ts`** — Standalone Bun subprocess that Open Code spawns. It registers tools from `serverMetadata` using `@modelcontextprotocol/sdk` and communicates with Open Code via stdin/stdout (JSON-RPC 2.0).
1090
+
1091
+ 2. **`WSClient` bridge** — The stdio server uses `WSClient` from `shared/utils/ws-client.ts` to connect to the main Clopen server via WebSocket. Tool calls are proxied using the standard `.http()` request-response pattern.
1092
+
1093
+ 3. **`backend/ws/mcp-bridge/`** — WS `.http()` route that receives bridge requests and executes tool handlers in-process. This is necessary because handlers like browser-automation need access to Puppeteer instances managed by the main server.
1094
+
1095
+ ### Why a Bridge?
1096
+
1097
+ Tool handlers often need in-process access to resources managed by the main server (browser instances, project context, database connections). The stdio subprocess runs in a separate process and cannot access these directly. The WS bridge pattern solves this by:
1098
+
1099
+ - Keeping tool **definitions** (schema, description) in the subprocess for MCP protocol
1100
+ - Proxying tool **execution** to the main server where handlers run in-process
1101
+ - Using the standard WSClient protocol (same as frontend), not custom WebSocket code
1102
+
1103
+ ### Adding Open Code Support to New Tools
1104
+
1105
+ No extra work needed! When you add a new tool via `defineServer()`, it's automatically available to both engines:
1106
+
1107
+ - **Claude Code**: Uses the in-process `createSdkMcpServer` instance
1108
+ - **Open Code**: `stdio-server.ts` reads from `serverMetadata` and `mcpServers` — the same registries
1109
+
1110
+ ### File Locations
1111
+
1112
+ | File | Location | Purpose |
1113
+ |------|----------|---------|
1114
+ | Tool definitions | `backend/lib/mcp/servers/` | Single source of truth |
1115
+ | Stdio server | `backend/lib/mcp/stdio-server.ts` | Subprocess for Open Code |
1116
+ | WS bridge route | `backend/ws/mcp/index.ts` | Bridge handler (in ws/) |
1117
+ | Open Code config | `backend/lib/mcp/config.ts` | `getOpenCodeMcpConfig()` |
1118
+ | Tool name resolver | `backend/lib/mcp/config.ts` | `resolveOpenCodeToolName()` |
1119
+
1120
+ ---
1121
+
1122
+ ## Additional Resources
1123
+
1124
+ - [Agent SDK Reference](https://platform.claude.com/docs/en/agent-sdk/typescript.md)
1125
+ - [Custom Tools](https://platform.claude.com/docs/en/agent-sdk/custom-tools.md)
1126
+ - [MCP in the SDK](https://platform.claude.com/docs/en/agent-sdk/mcp.md)
1127
+ - [MCP SDK (@modelcontextprotocol/sdk)](https://github.com/modelcontextprotocol/typescript-sdk)
1128
+ - [WebSocket API Documentation](../../../backend/ws/README.md)
1129
+ - [Zod Documentation](https://zod.dev/)
1130
+
1131
+ ---
1132
+
1133
+ ## Support
1134
+
1135
+ For questions or issues:
1136
+ 1. Check this README
1137
+ 2. Review example implementations in `./servers/`
1138
+ 3. Check console logs for error messages
1139
+ 4. Review Claude Agent SDK documentation
1140
+ 5. For WS bridge issues, see `backend/ws/README.md`
1141
+
1142
+ ---
1143
+
1144
+ **Happy coding!**