@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,316 @@
1
+ /**
2
+ * MCP Custom Tools Configuration & Registry
3
+ *
4
+ * This file combines server registry and configuration in one place
5
+ * to avoid duplication and make it easier to add new servers.
6
+ */
7
+
8
+ import type { McpSdkServerConfigWithInstance, McpServerConfig } from "@anthropic-ai/claude-agent-sdk";
9
+ import type { McpLocalConfig } from '@opencode-ai/sdk';
10
+ import type { ServerConfig, ParsedMcpToolName, ServerName } from './types';
11
+ import { serverRegistry } from './servers';
12
+ import { debug } from '$shared/utils/logger';
13
+ import { resolve } from 'path';
14
+
15
+ /**
16
+ * User-defined MCP Servers Configuration
17
+ *
18
+ * Define your server configuration here. Only specify `enabled` and `tools`.
19
+ * Server instances are automatically merged from the registry.
20
+ *
21
+ * Type-safe: Server names and tool names are validated at compile time!
22
+ */
23
+ const mcpServersConfig: Record<ServerName, ServerConfig> = {
24
+ "weather-service": {
25
+ enabled: true,
26
+ tools: [
27
+ "get_temperature",
28
+ ]
29
+ },
30
+ "browser-automation": {
31
+ enabled: true,
32
+ tools: [
33
+ // Tab Management
34
+ "list_tabs",
35
+ "switch_tab",
36
+ "open_new_tab",
37
+ "close_tab",
38
+
39
+ // Navigation
40
+ "navigate",
41
+
42
+ // Browser Actions
43
+ "actions",
44
+
45
+ // Page Inspection
46
+ "analyze_dom",
47
+ "take_screenshot",
48
+ "get_console_logs",
49
+ "clear_console_logs",
50
+ "execute_console",
51
+ ]
52
+ }
53
+ };
54
+
55
+ /**
56
+ * Helper to merge user config with server instances from registry
57
+ */
58
+ function createServerConfig<T extends Record<ServerName, ServerConfig>>(
59
+ config: T
60
+ ): { [K in keyof T]: T[K] & { instance: McpSdkServerConfigWithInstance } } {
61
+ const result = {} as any;
62
+
63
+ for (const [serverName, serverConfig] of Object.entries(config)) {
64
+ result[serverName] = {
65
+ ...serverConfig,
66
+ instance: serverRegistry[serverName as ServerName]
67
+ };
68
+ }
69
+
70
+ return result;
71
+ }
72
+
73
+ /**
74
+ * MCP Servers Configuration with instances
75
+ *
76
+ * This is the final configuration used throughout the application.
77
+ * Automatically merges user config with server instances.
78
+ */
79
+ export const mcpServers: Record<string, ServerConfig & { instance: McpSdkServerConfigWithInstance }> = createServerConfig(mcpServersConfig);
80
+
81
+ // ============================================================================
82
+ // Server Registry Functions
83
+ // ============================================================================
84
+
85
+ /**
86
+ * Get all enabled MCP servers for Claude SDK
87
+ */
88
+ export function getEnabledMcpServers(): Record<string, McpServerConfig> {
89
+ const enabledServers: Record<string, McpServerConfig> = {};
90
+
91
+ Object.entries(mcpServers).forEach(([serverName, serverConfig]) => {
92
+ if (serverConfig.enabled) {
93
+ enabledServers[serverName] = serverConfig.instance;
94
+ debug.log('mcp', `โœ“ Enabled MCP server: ${serverName}`);
95
+ } else {
96
+ debug.log('mcp', `โœ— Disabled MCP server: ${serverName}`);
97
+ }
98
+ });
99
+
100
+ debug.log('mcp', `Total enabled MCP servers: ${Object.keys(enabledServers).length}`);
101
+
102
+ return enabledServers;
103
+ }
104
+
105
+ /**
106
+ * Get list of all allowed MCP tool names
107
+ *
108
+ * Tool names follow the format: mcp__{server-name}__{tool-name}
109
+ * Example: "mcp__weather-service__get_temperature"
110
+ */
111
+ export function getAllowedMcpTools(): string[] {
112
+ const tools: string[] = [];
113
+
114
+ Object.entries(mcpServers).forEach(([serverName, serverConfig]) => {
115
+ if (!serverConfig.enabled) return;
116
+
117
+ serverConfig.tools.forEach((toolName) => {
118
+ const formattedName = `mcp__${serverName}__${toolName}`;
119
+ tools.push(formattedName);
120
+ debug.log('mcp', `โœ“ Allowed MCP tool: ${formattedName}`);
121
+ });
122
+ });
123
+
124
+ debug.log('mcp', `Total allowed MCP tools: ${tools.length}`);
125
+
126
+ return tools;
127
+ }
128
+
129
+ // ============================================================================
130
+ // Configuration Helper Functions
131
+ // ============================================================================
132
+
133
+ /**
134
+ * Get server configuration by name
135
+ */
136
+ export function getServerConfig(serverName: string) {
137
+ return mcpServers[serverName];
138
+ }
139
+
140
+ /**
141
+ * Check if a tool exists in server configuration
142
+ */
143
+ export function getToolConfig(serverName: string, toolName: string): boolean {
144
+ const server = getServerConfig(serverName);
145
+ return server?.tools.includes(toolName as any) ?? false;
146
+ }
147
+
148
+ /**
149
+ * Check if a server is enabled
150
+ */
151
+ export function isServerEnabled(serverName: string): boolean {
152
+ return mcpServers[serverName]?.enabled ?? false;
153
+ }
154
+
155
+ /**
156
+ * Check if a tool is enabled
157
+ */
158
+ export function isToolEnabled(serverName: string, toolName: string): boolean {
159
+ const server = mcpServers[serverName];
160
+ if (!server?.enabled) return false;
161
+
162
+ return server.tools.includes(toolName as any);
163
+ }
164
+
165
+ // ============================================================================
166
+ // Utility Functions
167
+ // ============================================================================
168
+
169
+ /**
170
+ * Parse MCP tool name into components
171
+ *
172
+ * Format: mcp__{server-name}__{tool-name}
173
+ * Example: "mcp__weather-service__get_temperature"
174
+ */
175
+ export function parseMcpToolName(fullName: string): ParsedMcpToolName | null {
176
+ if (!fullName.startsWith('mcp__')) {
177
+ return null;
178
+ }
179
+
180
+ const withoutPrefix = fullName.replace('mcp__', '');
181
+ const parts = withoutPrefix.split('__');
182
+
183
+ if (parts.length !== 2) {
184
+ debug.warn('mcp', `Invalid MCP tool name format: ${fullName}`);
185
+ return null;
186
+ }
187
+
188
+ const [server, tool] = parts;
189
+
190
+ return {
191
+ server,
192
+ tool,
193
+ fullName
194
+ };
195
+ }
196
+
197
+ /**
198
+ * Check if a tool name is a custom MCP tool
199
+ */
200
+ export function isMcpTool(toolName: string): boolean {
201
+ return toolName.startsWith('mcp__');
202
+ }
203
+
204
+ /**
205
+ * Get all enabled server names
206
+ */
207
+ export function getEnabledServerNames(): string[] {
208
+ return Object.entries(mcpServers)
209
+ .filter(([_, config]) => config.enabled)
210
+ .map(([name, _]) => name);
211
+ }
212
+
213
+ /**
214
+ * Get all enabled tool names for a specific server
215
+ */
216
+ export function getEnabledToolsForServer(serverName: string): string[] {
217
+ const serverConfig = mcpServers[serverName];
218
+ if (!serverConfig?.enabled) {
219
+ return [];
220
+ }
221
+
222
+ return serverConfig.tools.map((toolName) => `mcp__${serverName}__${toolName}`);
223
+ }
224
+
225
+ /**
226
+ * Get statistics about MCP servers and tools
227
+ */
228
+ export function getMcpStats() {
229
+ const enabledServers = getEnabledServerNames();
230
+ const allTools = getAllowedMcpTools();
231
+
232
+ return {
233
+ totalServers: Object.keys(mcpServers).length,
234
+ enabledServers: enabledServers.length,
235
+ totalTools: allTools.length,
236
+ serverNames: enabledServers,
237
+ toolNames: allTools
238
+ };
239
+ }
240
+
241
+ // ============================================================================
242
+ // Open Code Tool Name Resolution (single source of truth)
243
+ // ============================================================================
244
+
245
+ /**
246
+ * Resolve an Open Code tool name to our mcp__server__tool format.
247
+ *
248
+ * Open Code prefixes tool names with the MCP server name:
249
+ * e.g. "clopen-mcp_open_new_tab" โ†’ "mcp__browser-automation__open_new_tab"
250
+ *
251
+ * This function strips the prefix and maps back using the mcpServers
252
+ * registry โ€” the SAME source that defines which tools exist.
253
+ *
254
+ * Returns null if the tool name is not one of our custom MCP tools.
255
+ */
256
+ export function resolveOpenCodeToolName(toolName: string): string | null {
257
+ // Already in our format
258
+ if (toolName.startsWith('mcp__')) return toolName;
259
+
260
+ // Strip Open Code MCP server prefix if present
261
+ // Open Code prefixes with the stdio server name: "clopen-mcp_<tool>"
262
+ let rawName = toolName;
263
+ const ocPrefix = 'clopen-mcp_';
264
+ if (rawName.startsWith(ocPrefix)) {
265
+ rawName = rawName.slice(ocPrefix.length);
266
+ }
267
+
268
+ // Look up which server owns this tool
269
+ for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
270
+ if (!serverConfig.enabled) continue;
271
+ if ((serverConfig.tools as readonly string[]).includes(rawName)) {
272
+ return `mcp__${serverName}__${rawName}`;
273
+ }
274
+ }
275
+
276
+ return null;
277
+ }
278
+
279
+ // ============================================================================
280
+ // Open Code MCP Configuration
281
+ // ============================================================================
282
+
283
+ /**
284
+ * Get MCP configuration for Open Code engine.
285
+ *
286
+ * Open Code expects MCP servers as local (stdio subprocess) or remote (HTTP URL).
287
+ * We provide a single local MCP server that wraps all our custom tools.
288
+ * The server communicates with the main Clopen process via an HTTP bridge
289
+ * for tools that need in-process access (browser-automation).
290
+ */
291
+ export function getOpenCodeMcpConfig(): Record<string, McpLocalConfig> {
292
+ // Check if any servers are enabled
293
+ const enabledServers = getEnabledServerNames();
294
+ if (enabledServers.length === 0) {
295
+ return {};
296
+ }
297
+
298
+ // Resolve path to the stdio server script
299
+ const stdioServerPath = resolve(import.meta.dir, 'stdio-server.ts');
300
+ const port = process.env.PORT || '9141';
301
+
302
+ debug.log('mcp', `๐Ÿ“ฆ Open Code MCP: stdio server at ${stdioServerPath}`);
303
+ debug.log('mcp', `๐Ÿ“ฆ Open Code MCP: bridge port ${port}`);
304
+
305
+ return {
306
+ 'clopen-mcp': {
307
+ type: 'local',
308
+ command: ['bun', 'run', stdioServerPath],
309
+ environment: {
310
+ CLOPEN_PORT: port,
311
+ },
312
+ enabled: true,
313
+ timeout: 10000,
314
+ },
315
+ };
316
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * MCP (Model Context Protocol) Custom Tools
3
+ *
4
+ * Main export point for the custom MCP tools system.
5
+ */
6
+
7
+ // Type definitions
8
+ export type {
9
+ ParsedMcpToolName,
10
+ McpServerStatus
11
+ } from './types';
12
+
13
+ // Main configuration and all utilities
14
+ export {
15
+ mcpServers,
16
+ getEnabledMcpServers,
17
+ getAllowedMcpTools,
18
+ getServerConfig,
19
+ getToolConfig,
20
+ isServerEnabled,
21
+ isToolEnabled,
22
+ parseMcpToolName,
23
+ isMcpTool,
24
+ getEnabledServerNames,
25
+ getEnabledToolsForServer,
26
+ getMcpStats,
27
+ getOpenCodeMcpConfig,
28
+ resolveOpenCodeToolName
29
+ } from './config';
30
+
31
+ // Server implementations
32
+ export * from './servers';
33
+
34
+ // Project context service for MCP tool handlers
35
+ export { projectContextService } from './project-context';
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Project Context Service
3
+ *
4
+ * Stores mapping between chat sessions and projectId to provide
5
+ * project context to MCP tool handlers.
6
+ *
7
+ * This is needed because MCP tools are executed within a chat session context,
8
+ * but the Claude Agent SDK doesn't provide a way to pass custom context
9
+ * to tool handlers.
10
+ */
11
+
12
+ import { AsyncLocalStorage } from 'node:async_hooks';
13
+ import { debug } from '$shared/utils/logger';
14
+
15
+ // Execution context for MCP tool handlers
16
+ interface ExecutionContext {
17
+ chatSessionId?: string;
18
+ projectId?: string;
19
+ streamId?: string;
20
+ }
21
+
22
+ // AsyncLocalStorage for execution context
23
+ const executionContext = new AsyncLocalStorage<ExecutionContext>();
24
+
25
+ class ProjectContextService {
26
+ // Map chat session ID to project ID
27
+ private sessionProjectMap = new Map<string, string>();
28
+
29
+ // Map stream ID to project ID (for additional tracking)
30
+ private streamProjectMap = new Map<string, string>();
31
+
32
+ // Track active streams (streamId -> context)
33
+ private activeStreams = new Map<string, { chatSessionId: string; projectId: string; startedAt: number }>();
34
+
35
+ // Track the most recently active stream (for MCP tool execution context)
36
+ private mostRecentActiveStream: { streamId: string; chatSessionId: string; projectId: string } | null = null;
37
+
38
+ // Track the most recently used projectId (as a last resort fallback)
39
+ private lastUsedProjectId: string | null = null;
40
+
41
+ /**
42
+ * Register a chat session with its project ID
43
+ * Should be called when a chat stream starts
44
+ */
45
+ registerSession(chatSessionId: string, projectId: string): void {
46
+ if (!chatSessionId || !projectId) {
47
+ debug.warn('mcp', `โš ๏ธ Cannot register session: chatSessionId='${chatSessionId}' projectId='${projectId}'`);
48
+ return;
49
+ }
50
+
51
+ this.sessionProjectMap.set(chatSessionId, projectId);
52
+ this.lastUsedProjectId = projectId;
53
+
54
+ debug.log('mcp', `๐Ÿ“Œ Registered session: ${chatSessionId} -> project: ${projectId}`);
55
+ debug.log('mcp', `๐Ÿ“Š Total sessions registered: ${this.sessionProjectMap.size}`);
56
+ }
57
+
58
+ /**
59
+ * Register a stream ID with its project ID
60
+ * Should be called when a chat stream starts
61
+ */
62
+ registerStream(streamId: string, projectId: string, chatSessionId?: string): void {
63
+ if (!streamId || !projectId) {
64
+ debug.warn('mcp', `โš ๏ธ Cannot register stream: streamId='${streamId}' projectId='${projectId}'`);
65
+ return;
66
+ }
67
+
68
+ this.streamProjectMap.set(streamId, projectId);
69
+
70
+ // Track as active stream
71
+ if (chatSessionId) {
72
+ this.activeStreams.set(streamId, {
73
+ chatSessionId,
74
+ projectId,
75
+ startedAt: Date.now()
76
+ });
77
+
78
+ // Update most recent active stream
79
+ this.mostRecentActiveStream = { streamId, chatSessionId, projectId };
80
+
81
+ debug.log('mcp', `๐Ÿ“Œ Registered stream: ${streamId.slice(0, 8)} -> project: ${projectId} (session: ${chatSessionId.slice(0, 8)})`);
82
+ debug.log('mcp', `๐ŸŽฏ Most recent active stream set to: ${projectId}`);
83
+ } else {
84
+ debug.log('mcp', `๐Ÿ“Œ Registered stream: ${streamId.slice(0, 8)} -> project: ${projectId} (no session)`);
85
+ }
86
+
87
+ debug.log('mcp', `๐Ÿ“Š Total active streams: ${this.activeStreams.size}`);
88
+ }
89
+
90
+ /**
91
+ * Get project ID for a chat session
92
+ */
93
+ getProjectIdForSession(chatSessionId: string): string | null {
94
+ return this.sessionProjectMap.get(chatSessionId) || null;
95
+ }
96
+
97
+ /**
98
+ * Get project ID for a stream
99
+ */
100
+ getProjectIdForStream(streamId: string): string | null {
101
+ return this.streamProjectMap.get(streamId) || null;
102
+ }
103
+
104
+ /**
105
+ * Unregister a session (cleanup)
106
+ */
107
+ unregisterSession(chatSessionId: string): void {
108
+ this.sessionProjectMap.delete(chatSessionId);
109
+ debug.log('mcp', `๐Ÿ—‘๏ธ Unregistered session ${chatSessionId}`);
110
+ }
111
+
112
+ /**
113
+ * Unregister a stream (cleanup)
114
+ */
115
+ unregisterStream(streamId: string): void {
116
+ this.streamProjectMap.delete(streamId);
117
+ this.activeStreams.delete(streamId);
118
+
119
+ // Clear most recent if it was this stream
120
+ if (this.mostRecentActiveStream?.streamId === streamId) {
121
+ // Find another active stream to use as most recent
122
+ const remaining = Array.from(this.activeStreams.entries());
123
+ if (remaining.length > 0) {
124
+ // Get the most recently started stream
125
+ const [latestStreamId, latestContext] = remaining.sort((a, b) => b[1].startedAt - a[1].startedAt)[0];
126
+ this.mostRecentActiveStream = {
127
+ streamId: latestStreamId,
128
+ chatSessionId: latestContext.chatSessionId,
129
+ projectId: latestContext.projectId
130
+ };
131
+ } else {
132
+ this.mostRecentActiveStream = null;
133
+ }
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Get the last used project ID (fallback)
139
+ * This is used as a last resort when no session context is available
140
+ */
141
+ getLastUsedProjectId(): string | null {
142
+ return this.lastUsedProjectId;
143
+ }
144
+
145
+ /**
146
+ * Get all registered sessions (for debugging)
147
+ */
148
+ getAllSessions(): Array<{ sessionId: string; projectId: string }> {
149
+ return Array.from(this.sessionProjectMap.entries()).map(([sessionId, projectId]) => ({
150
+ sessionId,
151
+ projectId
152
+ }));
153
+ }
154
+
155
+ /**
156
+ * Clear all mappings (for testing or cleanup)
157
+ */
158
+ clear(): void {
159
+ this.sessionProjectMap.clear();
160
+ this.streamProjectMap.clear();
161
+ this.lastUsedProjectId = null;
162
+ debug.log('mcp', '๐Ÿงน Cleared all project context mappings');
163
+ }
164
+
165
+ /**
166
+ * Get current execution context (from AsyncLocalStorage)
167
+ */
168
+ getCurrentContext(): ExecutionContext | undefined {
169
+ return executionContext.getStore();
170
+ }
171
+
172
+ /**
173
+ * Run callback with execution context
174
+ * This should be called by stream manager when starting MCP tool execution
175
+ */
176
+ runWithContext<T>(context: ExecutionContext, callback: () => T): T {
177
+ return executionContext.run(context, callback);
178
+ }
179
+
180
+ /**
181
+ * Run async callback with execution context
182
+ */
183
+ async runWithContextAsync<T>(context: ExecutionContext, callback: () => Promise<T>): Promise<T> {
184
+ return executionContext.run(context, callback);
185
+ }
186
+
187
+ /**
188
+ * Get project ID from current execution context
189
+ * This is the primary method MCP handlers should use
190
+ */
191
+ getCurrentProjectId(): string | null {
192
+ const context = this.getCurrentContext();
193
+
194
+ // 1. Try to get from execution context (highest priority)
195
+ if (context?.projectId) {
196
+ debug.log('mcp', `๐Ÿ“ Project ID from execution context: ${context.projectId}`);
197
+ return context.projectId;
198
+ }
199
+
200
+ // 2. Try to get from session mapping
201
+ if (context?.chatSessionId) {
202
+ const projectId = this.getProjectIdForSession(context.chatSessionId);
203
+ if (projectId) {
204
+ debug.log('mcp', `๐Ÿ“ Project ID from session mapping: ${projectId}`);
205
+ return projectId;
206
+ }
207
+ }
208
+
209
+ // 3. Try to get from stream mapping
210
+ if (context?.streamId) {
211
+ const projectId = this.getProjectIdForStream(context.streamId);
212
+ if (projectId) {
213
+ debug.log('mcp', `๐Ÿ“ Project ID from stream mapping: ${projectId}`);
214
+ return projectId;
215
+ }
216
+ }
217
+
218
+ // 4. Try to get from most recent active stream
219
+ if (this.mostRecentActiveStream) {
220
+ debug.log('mcp', `๐Ÿ“ Project ID from most recent active stream: ${this.mostRecentActiveStream.projectId}`);
221
+ return this.mostRecentActiveStream.projectId;
222
+ }
223
+
224
+ // 5. Fallback to last used project ID
225
+ const fallback = this.getLastUsedProjectId();
226
+ if (fallback) {
227
+ debug.log('mcp', `๐Ÿ“ Project ID from fallback: ${fallback}`);
228
+ } else {
229
+ debug.warn('mcp', 'โš ๏ธ No project ID available in any context!');
230
+ }
231
+ return fallback;
232
+ }
233
+ }
234
+
235
+ // Singleton instance
236
+ export const projectContextService = new ProjectContextService();