@glwhappen/web-code 1.32.0

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 (479) hide show
  1. package/LICENSE +718 -0
  2. package/README.de.md +250 -0
  3. package/README.ja.md +242 -0
  4. package/README.ko.md +242 -0
  5. package/README.md +252 -0
  6. package/README.ru.md +250 -0
  7. package/README.tr.md +252 -0
  8. package/README.zh-CN.md +242 -0
  9. package/dist/api-docs.html +879 -0
  10. package/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  11. package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  12. package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  13. package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  14. package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  15. package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  16. package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  17. package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  18. package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  19. package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  20. package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  21. package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  22. package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  23. package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  24. package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  25. package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  26. package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  27. package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  28. package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  29. package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  30. package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  31. package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  32. package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  33. package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  34. package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  35. package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  36. package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  37. package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  38. package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  39. package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  40. package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  41. package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  42. package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  43. package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  44. package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  45. package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  46. package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  47. package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  48. package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  49. package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  50. package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  51. package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  52. package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  53. package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  54. package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  55. package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  56. package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  57. package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  58. package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  59. package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  60. package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  61. package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  62. package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  63. package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  64. package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  65. package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  66. package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  67. package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  68. package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  69. package/dist/assets/index-Ct6oPUQk.css +32 -0
  70. package/dist/assets/index-u6XmIqLb.js +1346 -0
  71. package/dist/assets/vendor-codemirror-OwyKSvPE.js +41 -0
  72. package/dist/assets/vendor-react-BGZc9oRE.js +59 -0
  73. package/dist/assets/vendor-xterm-CJZjLICi.js +66 -0
  74. package/dist/clear-cache.html +85 -0
  75. package/dist/convert-icons.md +53 -0
  76. package/dist/favicon.png +0 -0
  77. package/dist/favicon.svg +9 -0
  78. package/dist/generate-icons.js +49 -0
  79. package/dist/icons/claude-ai-icon.svg +1 -0
  80. package/dist/icons/codex-white.svg +3 -0
  81. package/dist/icons/codex.svg +3 -0
  82. package/dist/icons/cursor-white.svg +12 -0
  83. package/dist/icons/cursor.svg +1 -0
  84. package/dist/icons/gemini-ai-icon.svg +1 -0
  85. package/dist/icons/icon-128x128.png +0 -0
  86. package/dist/icons/icon-128x128.svg +12 -0
  87. package/dist/icons/icon-144x144.png +0 -0
  88. package/dist/icons/icon-144x144.svg +12 -0
  89. package/dist/icons/icon-152x152.png +0 -0
  90. package/dist/icons/icon-152x152.svg +12 -0
  91. package/dist/icons/icon-192x192.png +0 -0
  92. package/dist/icons/icon-192x192.svg +12 -0
  93. package/dist/icons/icon-384x384.png +0 -0
  94. package/dist/icons/icon-384x384.svg +12 -0
  95. package/dist/icons/icon-512x512.png +0 -0
  96. package/dist/icons/icon-512x512.svg +12 -0
  97. package/dist/icons/icon-72x72.png +0 -0
  98. package/dist/icons/icon-72x72.svg +12 -0
  99. package/dist/icons/icon-96x96.png +0 -0
  100. package/dist/icons/icon-96x96.svg +12 -0
  101. package/dist/icons/icon-template.svg +12 -0
  102. package/dist/index.html +52 -0
  103. package/dist/logo-128.png +0 -0
  104. package/dist/logo-256.png +0 -0
  105. package/dist/logo-32.png +0 -0
  106. package/dist/logo-512.png +0 -0
  107. package/dist/logo-64.png +0 -0
  108. package/dist/logo.svg +17 -0
  109. package/dist/manifest.json +61 -0
  110. package/dist/screenshots/cli-selection.png +0 -0
  111. package/dist/screenshots/desktop-main.png +0 -0
  112. package/dist/screenshots/mobile-chat.png +0 -0
  113. package/dist/screenshots/tools-modal.png +0 -0
  114. package/dist/sw.js +124 -0
  115. package/dist-server/server/claude-sdk.js +738 -0
  116. package/dist-server/server/claude-sdk.js.map +1 -0
  117. package/dist-server/server/cli.js +641 -0
  118. package/dist-server/server/cli.js.map +1 -0
  119. package/dist-server/server/constants/config.js +6 -0
  120. package/dist-server/server/constants/config.js.map +1 -0
  121. package/dist-server/server/cursor-cli.js +271 -0
  122. package/dist-server/server/cursor-cli.js.map +1 -0
  123. package/dist-server/server/gemini-cli.js +539 -0
  124. package/dist-server/server/gemini-cli.js.map +1 -0
  125. package/dist-server/server/gemini-response-handler.js +72 -0
  126. package/dist-server/server/gemini-response-handler.js.map +1 -0
  127. package/dist-server/server/index.js +1340 -0
  128. package/dist-server/server/index.js.map +1 -0
  129. package/dist-server/server/load-env.js +32 -0
  130. package/dist-server/server/load-env.js.map +1 -0
  131. package/dist-server/server/middleware/auth.js +117 -0
  132. package/dist-server/server/middleware/auth.js.map +1 -0
  133. package/dist-server/server/modules/database/connection.js +125 -0
  134. package/dist-server/server/modules/database/connection.js.map +1 -0
  135. package/dist-server/server/modules/database/index.js +13 -0
  136. package/dist-server/server/modules/database/index.js.map +1 -0
  137. package/dist-server/server/modules/database/init-db.js +18 -0
  138. package/dist-server/server/modules/database/init-db.js.map +1 -0
  139. package/dist-server/server/modules/database/migrations.js +419 -0
  140. package/dist-server/server/modules/database/migrations.js.map +1 -0
  141. package/dist-server/server/modules/database/repositories/api-keys.js +72 -0
  142. package/dist-server/server/modules/database/repositories/api-keys.js.map +1 -0
  143. package/dist-server/server/modules/database/repositories/app-config.js +47 -0
  144. package/dist-server/server/modules/database/repositories/app-config.js.map +1 -0
  145. package/dist-server/server/modules/database/repositories/credentials.js +68 -0
  146. package/dist-server/server/modules/database/repositories/credentials.js.map +1 -0
  147. package/dist-server/server/modules/database/repositories/github-tokens.js +54 -0
  148. package/dist-server/server/modules/database/repositories/github-tokens.js.map +1 -0
  149. package/dist-server/server/modules/database/repositories/notification-preferences.js +72 -0
  150. package/dist-server/server/modules/database/repositories/notification-preferences.js.map +1 -0
  151. package/dist-server/server/modules/database/repositories/projects.db.integration.test.js +67 -0
  152. package/dist-server/server/modules/database/repositories/projects.db.integration.test.js.map +1 -0
  153. package/dist-server/server/modules/database/repositories/projects.db.js +185 -0
  154. package/dist-server/server/modules/database/repositories/projects.db.js.map +1 -0
  155. package/dist-server/server/modules/database/repositories/push-subscriptions.js +49 -0
  156. package/dist-server/server/modules/database/repositories/push-subscriptions.js.map +1 -0
  157. package/dist-server/server/modules/database/repositories/scan-state.db.js +31 -0
  158. package/dist-server/server/modules/database/repositories/scan-state.db.js.map +1 -0
  159. package/dist-server/server/modules/database/repositories/sessions.db.integration.test.js +64 -0
  160. package/dist-server/server/modules/database/repositories/sessions.db.integration.test.js.map +1 -0
  161. package/dist-server/server/modules/database/repositories/sessions.db.js +150 -0
  162. package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -0
  163. package/dist-server/server/modules/database/repositories/users.js +116 -0
  164. package/dist-server/server/modules/database/repositories/users.js.map +1 -0
  165. package/dist-server/server/modules/database/repositories/vapid-keys.js +38 -0
  166. package/dist-server/server/modules/database/repositories/vapid-keys.js.map +1 -0
  167. package/dist-server/server/modules/database/schema.js +150 -0
  168. package/dist-server/server/modules/database/schema.js.map +1 -0
  169. package/dist-server/server/modules/projects/index.js +4 -0
  170. package/dist-server/server/modules/projects/index.js.map +1 -0
  171. package/dist-server/server/modules/projects/projects.routes.js +225 -0
  172. package/dist-server/server/modules/projects/projects.routes.js.map +1 -0
  173. package/dist-server/server/modules/projects/services/project-clone.service.js +220 -0
  174. package/dist-server/server/modules/projects/services/project-clone.service.js.map +1 -0
  175. package/dist-server/server/modules/projects/services/project-delete.service.js +83 -0
  176. package/dist-server/server/modules/projects/services/project-delete.service.js.map +1 -0
  177. package/dist-server/server/modules/projects/services/project-management.service.js +99 -0
  178. package/dist-server/server/modules/projects/services/project-management.service.js.map +1 -0
  179. package/dist-server/server/modules/projects/services/project-star.service.js +60 -0
  180. package/dist-server/server/modules/projects/services/project-star.service.js.map +1 -0
  181. package/dist-server/server/modules/projects/services/projects-has-taskmaster.service.js +171 -0
  182. package/dist-server/server/modules/projects/services/projects-has-taskmaster.service.js.map +1 -0
  183. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +213 -0
  184. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -0
  185. package/dist-server/server/modules/projects/tests/project-clone.service.test.js +129 -0
  186. package/dist-server/server/modules/projects/tests/project-clone.service.test.js.map +1 -0
  187. package/dist-server/server/modules/projects/tests/project-management.service.test.js +89 -0
  188. package/dist-server/server/modules/projects/tests/project-management.service.test.js.map +1 -0
  189. package/dist-server/server/modules/projects/tests/project-star.service.test.js +99 -0
  190. package/dist-server/server/modules/projects/tests/project-star.service.test.js.map +1 -0
  191. package/dist-server/server/modules/projects/tests/projects-has-taskmaster.service.test.js +88 -0
  192. package/dist-server/server/modules/projects/tests/projects-has-taskmaster.service.test.js.map +1 -0
  193. package/dist-server/server/modules/providers/index.js +5 -0
  194. package/dist-server/server/modules/providers/index.js.map +1 -0
  195. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +104 -0
  196. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -0
  197. package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js +103 -0
  198. package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js.map +1 -0
  199. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +116 -0
  200. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -0
  201. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +546 -0
  202. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -0
  203. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js +198 -0
  204. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js.map +1 -0
  205. package/dist-server/server/modules/providers/list/claude/claude.provider.js +17 -0
  206. package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -0
  207. package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js +84 -0
  208. package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js.map +1 -0
  209. package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js +107 -0
  210. package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js.map +1 -0
  211. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +123 -0
  212. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -0
  213. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +513 -0
  214. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -0
  215. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js +82 -0
  216. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js.map +1 -0
  217. package/dist-server/server/modules/providers/list/codex/codex.provider.js +17 -0
  218. package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -0
  219. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js +118 -0
  220. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js.map +1 -0
  221. package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js +80 -0
  222. package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js.map +1 -0
  223. package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js +105 -0
  224. package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js.map +1 -0
  225. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +545 -0
  226. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -0
  227. package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js +28 -0
  228. package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js.map +1 -0
  229. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +17 -0
  230. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -0
  231. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js +254 -0
  232. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js.map +1 -0
  233. package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js +82 -0
  234. package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js.map +1 -0
  235. package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js +312 -0
  236. package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js.map +1 -0
  237. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js +484 -0
  238. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js.map +1 -0
  239. package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js +33 -0
  240. package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js.map +1 -0
  241. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js +17 -0
  242. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js.map +1 -0
  243. package/dist-server/server/modules/providers/provider.registry.js +31 -0
  244. package/dist-server/server/modules/providers/provider.registry.js.map +1 -0
  245. package/dist-server/server/modules/providers/provider.routes.js +377 -0
  246. package/dist-server/server/modules/providers/provider.routes.js.map +1 -0
  247. package/dist-server/server/modules/providers/services/mcp.service.js +69 -0
  248. package/dist-server/server/modules/providers/services/mcp.service.js.map +1 -0
  249. package/dist-server/server/modules/providers/services/provider-auth.service.js +25 -0
  250. package/dist-server/server/modules/providers/services/provider-auth.service.js.map +1 -0
  251. package/dist-server/server/modules/providers/services/session-conversations-search.service.js +984 -0
  252. package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -0
  253. package/dist-server/server/modules/providers/services/session-synchronizer.service.js +56 -0
  254. package/dist-server/server/modules/providers/services/session-synchronizer.service.js.map +1 -0
  255. package/dist-server/server/modules/providers/services/sessions-watcher.service.js +269 -0
  256. package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -0
  257. package/dist-server/server/modules/providers/services/sessions.service.js +179 -0
  258. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -0
  259. package/dist-server/server/modules/providers/services/skills.service.js +11 -0
  260. package/dist-server/server/modules/providers/services/skills.service.js.map +1 -0
  261. package/dist-server/server/modules/providers/shared/base/abstract.provider.js +14 -0
  262. package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -0
  263. package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js +102 -0
  264. package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js.map +1 -0
  265. package/dist-server/server/modules/providers/shared/skills/skills.provider.js +45 -0
  266. package/dist-server/server/modules/providers/shared/skills/skills.provider.js.map +1 -0
  267. package/dist-server/server/modules/providers/tests/mcp.test.js +250 -0
  268. package/dist-server/server/modules/providers/tests/mcp.test.js.map +1 -0
  269. package/dist-server/server/modules/providers/tests/skills.test.js +226 -0
  270. package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -0
  271. package/dist-server/server/modules/websocket/index.js +3 -0
  272. package/dist-server/server/modules/websocket/index.js.map +1 -0
  273. package/dist-server/server/modules/websocket/services/chat-websocket.service.js +192 -0
  274. package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -0
  275. package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js +52 -0
  276. package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js.map +1 -0
  277. package/dist-server/server/modules/websocket/services/shell-websocket.service.js +360 -0
  278. package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -0
  279. package/dist-server/server/modules/websocket/services/websocket-auth.service.js +32 -0
  280. package/dist-server/server/modules/websocket/services/websocket-auth.service.js.map +1 -0
  281. package/dist-server/server/modules/websocket/services/websocket-server.service.js +36 -0
  282. package/dist-server/server/modules/websocket/services/websocket-server.service.js.map +1 -0
  283. package/dist-server/server/modules/websocket/services/websocket-state.service.js +14 -0
  284. package/dist-server/server/modules/websocket/services/websocket-state.service.js.map +1 -0
  285. package/dist-server/server/modules/websocket/services/websocket-writer.service.js +32 -0
  286. package/dist-server/server/modules/websocket/services/websocket-writer.service.js.map +1 -0
  287. package/dist-server/server/openai-codex.js +418 -0
  288. package/dist-server/server/openai-codex.js.map +1 -0
  289. package/dist-server/server/routes/admin.js +109 -0
  290. package/dist-server/server/routes/admin.js.map +1 -0
  291. package/dist-server/server/routes/agent.js +1145 -0
  292. package/dist-server/server/routes/agent.js.map +1 -0
  293. package/dist-server/server/routes/auth.js +123 -0
  294. package/dist-server/server/routes/auth.js.map +1 -0
  295. package/dist-server/server/routes/commands.js +487 -0
  296. package/dist-server/server/routes/commands.js.map +1 -0
  297. package/dist-server/server/routes/cursor.js +49 -0
  298. package/dist-server/server/routes/cursor.js.map +1 -0
  299. package/dist-server/server/routes/gemini.js +25 -0
  300. package/dist-server/server/routes/gemini.js.map +1 -0
  301. package/dist-server/server/routes/git.js +1263 -0
  302. package/dist-server/server/routes/git.js.map +1 -0
  303. package/dist-server/server/routes/mcp-utils.js +29 -0
  304. package/dist-server/server/routes/mcp-utils.js.map +1 -0
  305. package/dist-server/server/routes/plugins.js +266 -0
  306. package/dist-server/server/routes/plugins.js.map +1 -0
  307. package/dist-server/server/routes/settings.js +259 -0
  308. package/dist-server/server/routes/settings.js.map +1 -0
  309. package/dist-server/server/routes/taskmaster.js +1360 -0
  310. package/dist-server/server/routes/taskmaster.js.map +1 -0
  311. package/dist-server/server/routes/user.js +115 -0
  312. package/dist-server/server/routes/user.js.map +1 -0
  313. package/dist-server/server/services/notification-orchestrator.js +177 -0
  314. package/dist-server/server/services/notification-orchestrator.js.map +1 -0
  315. package/dist-server/server/services/vapid-keys.js +27 -0
  316. package/dist-server/server/services/vapid-keys.js.map +1 -0
  317. package/dist-server/server/sessionManager.js +215 -0
  318. package/dist-server/server/sessionManager.js.map +1 -0
  319. package/dist-server/server/shared/claude-cli-path.js +103 -0
  320. package/dist-server/server/shared/claude-cli-path.js.map +1 -0
  321. package/dist-server/server/shared/claude-cli-path.test.js +45 -0
  322. package/dist-server/server/shared/claude-cli-path.test.js.map +1 -0
  323. package/dist-server/server/shared/default-user.js +29 -0
  324. package/dist-server/server/shared/default-user.js.map +1 -0
  325. package/dist-server/server/shared/frontmatter.js +16 -0
  326. package/dist-server/server/shared/frontmatter.js.map +1 -0
  327. package/dist-server/server/shared/interfaces.js +2 -0
  328. package/dist-server/server/shared/interfaces.js.map +1 -0
  329. package/dist-server/server/shared/types.js +2 -0
  330. package/dist-server/server/shared/types.js.map +1 -0
  331. package/dist-server/server/shared/utils.js +633 -0
  332. package/dist-server/server/shared/utils.js.map +1 -0
  333. package/dist-server/server/utils/colors.js +20 -0
  334. package/dist-server/server/utils/colors.js.map +1 -0
  335. package/dist-server/server/utils/commandParser.js +255 -0
  336. package/dist-server/server/utils/commandParser.js.map +1 -0
  337. package/dist-server/server/utils/gitConfig.js +36 -0
  338. package/dist-server/server/utils/gitConfig.js.map +1 -0
  339. package/dist-server/server/utils/mcp-detector.js +134 -0
  340. package/dist-server/server/utils/mcp-detector.js.map +1 -0
  341. package/dist-server/server/utils/plugin-loader.js +413 -0
  342. package/dist-server/server/utils/plugin-loader.js.map +1 -0
  343. package/dist-server/server/utils/plugin-process-manager.js +163 -0
  344. package/dist-server/server/utils/plugin-process-manager.js.map +1 -0
  345. package/dist-server/server/utils/runtime-paths.js +30 -0
  346. package/dist-server/server/utils/runtime-paths.js.map +1 -0
  347. package/dist-server/server/utils/taskmaster-websocket.js +124 -0
  348. package/dist-server/server/utils/taskmaster-websocket.js.map +1 -0
  349. package/dist-server/server/utils/url-detection.js +58 -0
  350. package/dist-server/server/utils/url-detection.js.map +1 -0
  351. package/dist-server/shared/modelConstants.js +99 -0
  352. package/dist-server/shared/modelConstants.js.map +1 -0
  353. package/dist-server/shared/networkHosts.js +20 -0
  354. package/dist-server/shared/networkHosts.js.map +1 -0
  355. package/package.json +169 -0
  356. package/scripts/fix-node-pty.js +67 -0
  357. package/server/claude-sdk.js +864 -0
  358. package/server/cli.js +688 -0
  359. package/server/constants/config.js +5 -0
  360. package/server/cursor-cli.js +334 -0
  361. package/server/gemini-cli.js +622 -0
  362. package/server/gemini-response-handler.js +79 -0
  363. package/server/index.js +1505 -0
  364. package/server/load-env.js +34 -0
  365. package/server/middleware/auth.js +142 -0
  366. package/server/modules/database/connection.ts +143 -0
  367. package/server/modules/database/index.ts +12 -0
  368. package/server/modules/database/init-db.ts +17 -0
  369. package/server/modules/database/migrations.ts +496 -0
  370. package/server/modules/database/repositories/api-keys.ts +119 -0
  371. package/server/modules/database/repositories/app-config.ts +53 -0
  372. package/server/modules/database/repositories/credentials.ts +106 -0
  373. package/server/modules/database/repositories/github-tokens.ts +100 -0
  374. package/server/modules/database/repositories/notification-preferences.ts +103 -0
  375. package/server/modules/database/repositories/projects.db.integration.test.ts +78 -0
  376. package/server/modules/database/repositories/projects.db.ts +210 -0
  377. package/server/modules/database/repositories/push-subscriptions.ts +80 -0
  378. package/server/modules/database/repositories/scan-state.db.ts +42 -0
  379. package/server/modules/database/repositories/sessions.db.integration.test.ts +78 -0
  380. package/server/modules/database/repositories/sessions.db.ts +230 -0
  381. package/server/modules/database/repositories/users.ts +186 -0
  382. package/server/modules/database/repositories/vapid-keys.ts +57 -0
  383. package/server/modules/database/schema.ts +159 -0
  384. package/server/modules/projects/index.ts +6 -0
  385. package/server/modules/projects/projects.routes.ts +292 -0
  386. package/server/modules/projects/services/project-clone.service.ts +327 -0
  387. package/server/modules/projects/services/project-delete.service.ts +95 -0
  388. package/server/modules/projects/services/project-management.service.ts +158 -0
  389. package/server/modules/projects/services/project-star.service.ts +78 -0
  390. package/server/modules/projects/services/projects-has-taskmaster.service.ts +257 -0
  391. package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +355 -0
  392. package/server/modules/projects/tests/project-clone.service.test.ts +186 -0
  393. package/server/modules/projects/tests/project-management.service.test.ts +122 -0
  394. package/server/modules/projects/tests/project-star.service.test.ts +128 -0
  395. package/server/modules/projects/tests/projects-has-taskmaster.service.test.ts +107 -0
  396. package/server/modules/providers/README.md +346 -0
  397. package/server/modules/providers/index.ts +5 -0
  398. package/server/modules/providers/list/claude/claude-auth.provider.ts +124 -0
  399. package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -0
  400. package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +179 -0
  401. package/server/modules/providers/list/claude/claude-sessions.provider.ts +642 -0
  402. package/server/modules/providers/list/claude/claude-skills.provider.ts +257 -0
  403. package/server/modules/providers/list/claude/claude.provider.ts +24 -0
  404. package/server/modules/providers/list/codex/codex-auth.provider.ts +100 -0
  405. package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -0
  406. package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +182 -0
  407. package/server/modules/providers/list/codex/codex-sessions.provider.ts +589 -0
  408. package/server/modules/providers/list/codex/codex-skills.provider.ts +100 -0
  409. package/server/modules/providers/list/codex/codex.provider.ts +24 -0
  410. package/server/modules/providers/list/cursor/cursor-auth.provider.ts +143 -0
  411. package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -0
  412. package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +155 -0
  413. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +624 -0
  414. package/server/modules/providers/list/cursor/cursor-skills.provider.ts +31 -0
  415. package/server/modules/providers/list/cursor/cursor.provider.ts +24 -0
  416. package/server/modules/providers/list/gemini/gemini-auth.provider.ts +307 -0
  417. package/server/modules/providers/list/gemini/gemini-mcp.provider.ts +110 -0
  418. package/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.ts +407 -0
  419. package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +552 -0
  420. package/server/modules/providers/list/gemini/gemini-skills.provider.ts +36 -0
  421. package/server/modules/providers/list/gemini/gemini.provider.ts +24 -0
  422. package/server/modules/providers/provider.registry.ts +36 -0
  423. package/server/modules/providers/provider.routes.ts +488 -0
  424. package/server/modules/providers/services/mcp.service.ts +94 -0
  425. package/server/modules/providers/services/provider-auth.service.ts +26 -0
  426. package/server/modules/providers/services/session-conversations-search.service.ts +1319 -0
  427. package/server/modules/providers/services/session-synchronizer.service.ts +75 -0
  428. package/server/modules/providers/services/sessions-watcher.service.ts +318 -0
  429. package/server/modules/providers/services/sessions.service.ts +240 -0
  430. package/server/modules/providers/services/skills.service.ts +15 -0
  431. package/server/modules/providers/shared/base/abstract.provider.ts +29 -0
  432. package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -0
  433. package/server/modules/providers/shared/skills/skills.provider.ts +64 -0
  434. package/server/modules/providers/tests/mcp.test.ts +293 -0
  435. package/server/modules/providers/tests/skills.test.ts +446 -0
  436. package/server/modules/websocket/README.md +267 -0
  437. package/server/modules/websocket/index.ts +2 -0
  438. package/server/modules/websocket/services/chat-websocket.service.ts +275 -0
  439. package/server/modules/websocket/services/plugin-websocket-proxy.service.ts +65 -0
  440. package/server/modules/websocket/services/shell-websocket.service.ts +489 -0
  441. package/server/modules/websocket/services/websocket-auth.service.ts +54 -0
  442. package/server/modules/websocket/services/websocket-server.service.ts +58 -0
  443. package/server/modules/websocket/services/websocket-state.service.ts +16 -0
  444. package/server/modules/websocket/services/websocket-writer.service.ts +38 -0
  445. package/server/openai-codex.js +474 -0
  446. package/server/routes/admin.js +128 -0
  447. package/server/routes/agent.js +1246 -0
  448. package/server/routes/auth.js +144 -0
  449. package/server/routes/commands.js +556 -0
  450. package/server/routes/cursor.js +52 -0
  451. package/server/routes/gemini.js +30 -0
  452. package/server/routes/git.js +1493 -0
  453. package/server/routes/mcp-utils.js +31 -0
  454. package/server/routes/plugins.js +307 -0
  455. package/server/routes/settings.js +286 -0
  456. package/server/routes/taskmaster.js +1468 -0
  457. package/server/routes/user.js +123 -0
  458. package/server/services/notification-orchestrator.js +228 -0
  459. package/server/services/vapid-keys.js +36 -0
  460. package/server/sessionManager.js +248 -0
  461. package/server/shared/claude-cli-path.test.ts +61 -0
  462. package/server/shared/claude-cli-path.ts +139 -0
  463. package/server/shared/default-user.ts +30 -0
  464. package/server/shared/frontmatter.ts +18 -0
  465. package/server/shared/interfaces.ts +111 -0
  466. package/server/shared/types.ts +406 -0
  467. package/server/shared/utils.ts +763 -0
  468. package/server/tsconfig.json +36 -0
  469. package/server/utils/colors.js +21 -0
  470. package/server/utils/commandParser.js +305 -0
  471. package/server/utils/gitConfig.js +34 -0
  472. package/server/utils/mcp-detector.js +147 -0
  473. package/server/utils/plugin-loader.js +457 -0
  474. package/server/utils/plugin-process-manager.js +184 -0
  475. package/server/utils/runtime-paths.js +37 -0
  476. package/server/utils/taskmaster-websocket.js +135 -0
  477. package/server/utils/url-detection.js +71 -0
  478. package/shared/modelConstants.js +107 -0
  479. package/shared/networkHosts.js +22 -0
@@ -0,0 +1,75 @@
1
+ import { scanStateDb } from '@/modules/database/index.js';
2
+ import { providerRegistry } from '@/modules/providers/provider.registry.js';
3
+ import type { LLMProvider } from '@/shared/types.js';
4
+
5
+ type SessionSynchronizeResult = {
6
+ processedByProvider: Record<LLMProvider, number>;
7
+ failures: string[];
8
+ };
9
+
10
+ /**
11
+ * Orchestrates provider-specific session indexers and indexed-session lifecycle operations.
12
+ */
13
+ export const sessionSynchronizerService = {
14
+ /**
15
+ * Runs all provider synchronizers and updates scan_state.last_scanned_at.
16
+ */
17
+ async synchronizeSessions(ownerUserId: number): Promise<SessionSynchronizeResult> {
18
+ const lastScanAt = scanStateDb.getLastScannedAt();
19
+ const scanBoundary = new Date();
20
+ const processedByProvider: Record<LLMProvider, number> = {
21
+ claude: 0,
22
+ codex: 0,
23
+ cursor: 0,
24
+ gemini: 0,
25
+ };
26
+ const failures: string[] = [];
27
+
28
+ const results = await Promise.allSettled(
29
+ providerRegistry.listProviders().map(async (provider) => ({
30
+ provider: provider.id,
31
+ processed: await provider.sessionSynchronizer.synchronize(lastScanAt ?? undefined, ownerUserId),
32
+ }))
33
+ );
34
+
35
+ for (const result of results) {
36
+ if (result.status === 'fulfilled') {
37
+ processedByProvider[result.value.provider] = result.value.processed;
38
+ continue;
39
+ }
40
+
41
+ const reason = result.reason instanceof Error ? result.reason.message : String(result.reason);
42
+ failures.push(reason);
43
+ }
44
+
45
+ if (failures.length === 0) {
46
+ scanStateDb.updateLastScannedAt(scanBoundary);
47
+ } else {
48
+ console.warn(
49
+ `[Sessions] Skipping scan_state cursor advance because ${failures.length} provider sync(s) failed.`,
50
+ );
51
+ }
52
+
53
+ return {
54
+ processedByProvider,
55
+ failures,
56
+ };
57
+ },
58
+
59
+ /**
60
+ * Indexes one provider artifact file without running a full provider rescan.
61
+ */
62
+ async synchronizeProviderFile(
63
+ ownerUserId: number,
64
+ provider: LLMProvider,
65
+ filePath: string
66
+ ): Promise<{ provider: LLMProvider; indexed: boolean; sessionId: string | null }> {
67
+ const resolvedProvider = providerRegistry.resolveProvider(provider);
68
+ const sessionId = await resolvedProvider.sessionSynchronizer.synchronizeFile(filePath, ownerUserId);
69
+ return {
70
+ provider,
71
+ indexed: Boolean(sessionId),
72
+ sessionId,
73
+ };
74
+ },
75
+ };
@@ -0,0 +1,318 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import { promises as fsPromises } from 'node:fs';
4
+
5
+ import chokidar, { type FSWatcher } from 'chokidar';
6
+
7
+ import { sessionSynchronizerService } from '@/modules/providers/services/session-synchronizer.service.js';
8
+ import { WS_OPEN_STATE, connectedClients } from '@/modules/websocket/index.js';
9
+ import type { LLMProvider } from '@/shared/types.js';
10
+ import { getProjectsWithSessions } from '@/modules/projects/index.js';
11
+ import { getDefaultOwnerUserId } from '@/shared/default-user.js';
12
+ import { AppError } from '@/shared/utils.js';
13
+
14
+ /**
15
+ * Resolves the user id used to attribute background-watcher synchronizations.
16
+ *
17
+ * Returns `null` (with a console warning) when no user has registered yet so
18
+ * that the watcher can keep running silently until the first account exists.
19
+ */
20
+ function resolveWatcherOwnerUserId(): number | null {
21
+ try {
22
+ return getDefaultOwnerUserId();
23
+ } catch (error) {
24
+ if (error instanceof AppError && error.code === 'DEFAULT_USER_NOT_AVAILABLE') {
25
+ console.warn('Session watcher skipping synchronization: no registered user yet');
26
+ return null;
27
+ }
28
+ throw error;
29
+ }
30
+ }
31
+
32
+ type WatcherEventType = 'add' | 'change';
33
+
34
+ const PROVIDER_WATCH_PATHS: Array<{ provider: LLMProvider; rootPath: string }> = [
35
+ {
36
+ provider: 'claude',
37
+ rootPath: path.join(os.homedir(), '.claude', 'projects'),
38
+ },
39
+ {
40
+ provider: 'cursor',
41
+ rootPath: path.join(os.homedir(), '.cursor', 'projects'),
42
+ },
43
+ {
44
+ provider: 'codex',
45
+ rootPath: path.join(os.homedir(), '.codex', 'sessions'),
46
+ },
47
+ // {
48
+ // provider: 'gemini',
49
+ // rootPath: path.join(os.homedir(), '.gemini', 'sessions'),
50
+ // },
51
+ // Keep `sessions/` watcher disabled: Gemini also mirrors artifacts there,
52
+ // which causes duplicate synchronization events.
53
+ {
54
+ provider: 'gemini',
55
+ rootPath: path.join(os.homedir(), '.gemini', 'tmp'),
56
+ },
57
+ ];
58
+
59
+ const WATCHER_IGNORED_PATTERNS = [
60
+ '**/node_modules/**',
61
+ '**/.git/**',
62
+ '**/dist/**',
63
+ '**/build/**',
64
+ '**/*.tmp',
65
+ '**/*.swp',
66
+ '**/.DS_Store',
67
+ ];
68
+
69
+ const PROJECTS_UPDATE_DEBOUNCE_MS = 500;
70
+ const PROJECTS_UPDATE_MAX_WAIT_MS = 2_000;
71
+
72
+ const watchers: FSWatcher[] = [];
73
+
74
+ type PendingWatcherUpdate = {
75
+ providers: Set<LLMProvider>;
76
+ changeTypes: Set<WatcherEventType>;
77
+ updatedSessionIds: Set<string>;
78
+ };
79
+
80
+ let pendingWatcherUpdate: PendingWatcherUpdate | null = null;
81
+ let pendingWatcherUpdateStartedAt: number | null = null;
82
+ let pendingWatcherFlushTimer: ReturnType<typeof setTimeout> | null = null;
83
+ let watcherRefreshInFlight = false;
84
+ let watcherRescheduleAfterRefresh = false;
85
+
86
+ /**
87
+ * Filters watcher events to provider-specific session artifact file types.
88
+ */
89
+ function isWatcherTargetFile(provider: LLMProvider, filePath: string): boolean {
90
+ if (provider === 'gemini') {
91
+ return filePath.endsWith('.json') || filePath.endsWith('.jsonl');
92
+ }
93
+
94
+ return filePath.endsWith('.jsonl');
95
+ }
96
+
97
+ function clearPendingWatcherFlushTimer(): void {
98
+ if (pendingWatcherFlushTimer) {
99
+ clearTimeout(pendingWatcherFlushTimer);
100
+ pendingWatcherFlushTimer = null;
101
+ }
102
+ }
103
+
104
+ function schedulePendingWatcherFlush(): void {
105
+ if (!pendingWatcherUpdate) {
106
+ return;
107
+ }
108
+
109
+ const now = Date.now();
110
+ if (pendingWatcherUpdateStartedAt === null) {
111
+ pendingWatcherUpdateStartedAt = now;
112
+ }
113
+
114
+ const elapsed = now - pendingWatcherUpdateStartedAt;
115
+ const remainingMaxWait = Math.max(0, PROJECTS_UPDATE_MAX_WAIT_MS - elapsed);
116
+ const delay = Math.min(PROJECTS_UPDATE_DEBOUNCE_MS, remainingMaxWait);
117
+
118
+ clearPendingWatcherFlushTimer();
119
+ pendingWatcherFlushTimer = setTimeout(() => {
120
+ void flushPendingWatcherUpdate();
121
+ }, delay);
122
+ }
123
+
124
+ function queuePendingWatcherUpdate(
125
+ eventType: WatcherEventType,
126
+ provider: LLMProvider,
127
+ updatedSessionId: string | null
128
+ ): void {
129
+ if (!pendingWatcherUpdate) {
130
+ pendingWatcherUpdate = {
131
+ providers: new Set<LLMProvider>(),
132
+ changeTypes: new Set<WatcherEventType>(),
133
+ updatedSessionIds: new Set<string>(),
134
+ };
135
+ }
136
+
137
+ pendingWatcherUpdate.providers.add(provider);
138
+ pendingWatcherUpdate.changeTypes.add(eventType);
139
+ if (updatedSessionId) {
140
+ pendingWatcherUpdate.updatedSessionIds.add(updatedSessionId);
141
+ }
142
+
143
+ schedulePendingWatcherFlush();
144
+ }
145
+
146
+ async function flushPendingWatcherUpdate(): Promise<void> {
147
+ clearPendingWatcherFlushTimer();
148
+
149
+ if (!pendingWatcherUpdate) {
150
+ return;
151
+ }
152
+
153
+ if (watcherRefreshInFlight) {
154
+ watcherRescheduleAfterRefresh = true;
155
+ return;
156
+ }
157
+
158
+ const queuedUpdate = pendingWatcherUpdate;
159
+ pendingWatcherUpdate = null;
160
+ pendingWatcherUpdateStartedAt = null;
161
+ watcherRefreshInFlight = true;
162
+
163
+ try {
164
+ const ownerUserId = resolveWatcherOwnerUserId();
165
+ const updatedProjects = ownerUserId !== null
166
+ ? await getProjectsWithSessions(ownerUserId, { skipSynchronization: true })
167
+ : [];
168
+ const changeTypes = Array.from(queuedUpdate.changeTypes);
169
+ const watchProviders = Array.from(queuedUpdate.providers);
170
+ const updatedSessionIds = Array.from(queuedUpdate.updatedSessionIds);
171
+
172
+ // Backward-compatible fields stay populated with the first queued values.
173
+ const updateMessage = JSON.stringify({
174
+ type: 'projects_updated',
175
+ projects: updatedProjects,
176
+ timestamp: new Date().toISOString(),
177
+ changeType: changeTypes[0] ?? 'change',
178
+ updatedSessionId: updatedSessionIds[0] ?? undefined,
179
+ watchProvider: watchProviders[0] ?? undefined,
180
+ changeTypes,
181
+ updatedSessionIds,
182
+ watchProviders,
183
+ batched: true,
184
+ });
185
+
186
+ connectedClients.forEach(client => {
187
+ if (client.readyState === WS_OPEN_STATE) {
188
+ client.send(updateMessage);
189
+ }
190
+ });
191
+ } catch (error) {
192
+ const message = error instanceof Error ? error.message : String(error);
193
+ console.error('Session watcher refresh failed while broadcasting projects_updated', { error: message });
194
+ } finally {
195
+ watcherRefreshInFlight = false;
196
+
197
+ if (pendingWatcherUpdate || watcherRescheduleAfterRefresh) {
198
+ watcherRescheduleAfterRefresh = false;
199
+ schedulePendingWatcherFlush();
200
+ }
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Handles file watcher updates and triggers provider file-level synchronization.
206
+ */
207
+ async function onUpdate(
208
+ eventType: WatcherEventType,
209
+ filePath: string,
210
+ provider: LLMProvider
211
+ ): Promise<void> {
212
+ if (!isWatcherTargetFile(provider, filePath)) {
213
+ return;
214
+ }
215
+
216
+ try {
217
+ const ownerUserId = resolveWatcherOwnerUserId();
218
+ if (ownerUserId === null) {
219
+ return;
220
+ }
221
+
222
+ const result = await sessionSynchronizerService.synchronizeProviderFile(ownerUserId, provider, filePath);
223
+ if (!result.indexed) {
224
+ return;
225
+ }
226
+
227
+ console.log(`Session synchronization triggered by ${eventType} event for provider "${provider}"`, {
228
+ filePath,
229
+ sessionId: result.sessionId,
230
+ });
231
+ queuePendingWatcherUpdate(eventType, provider, result.sessionId);
232
+ } catch (error) {
233
+ const message = error instanceof Error ? error.message : String(error);
234
+ console.error(`Session watcher sync failed for provider "${provider}"`, {
235
+ eventType,
236
+ filePath,
237
+ error: message,
238
+ });
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Starts provider filesystem watchers and performs initial DB synchronization.
244
+ */
245
+ export async function initializeSessionsWatcher(): Promise<void> {
246
+ console.log('Setting up session watchers');
247
+
248
+ const initialOwnerUserId = resolveWatcherOwnerUserId();
249
+ if (initialOwnerUserId !== null) {
250
+ const initialSync = await sessionSynchronizerService.synchronizeSessions(initialOwnerUserId);
251
+ console.log('Initial session synchronization complete', {
252
+ processedByProvider: initialSync.processedByProvider,
253
+ failures: initialSync.failures,
254
+ });
255
+ } else {
256
+ console.log('Initial session synchronization skipped: no registered user yet');
257
+ }
258
+
259
+ for (const { provider, rootPath } of PROVIDER_WATCH_PATHS) {
260
+ try {
261
+ await fsPromises.mkdir(rootPath, { recursive: true });
262
+
263
+ const watcher = chokidar.watch(rootPath, {
264
+ ignored: WATCHER_IGNORED_PATTERNS,
265
+ persistent: true,
266
+ ignoreInitial: true,
267
+ followSymlinks: false,
268
+ depth: 6,
269
+ usePolling: true,
270
+ interval: 6_000,
271
+ binaryInterval: 6_000,
272
+ });
273
+
274
+ watcher
275
+ .on('add', (filePath: string) => {
276
+ void onUpdate('add', filePath, provider);
277
+ })
278
+ .on('change', (filePath: string) => {
279
+ void onUpdate('change', filePath, provider);
280
+ })
281
+ .on('error', (error: unknown) => {
282
+ const message = error instanceof Error ? error.message : String(error);
283
+ console.error(`Session watcher error for provider "${provider}"`, { error: message });
284
+ });
285
+
286
+ watchers.push(watcher);
287
+ } catch (error) {
288
+ const message = error instanceof Error ? error.message : String(error);
289
+ console.error(`Failed to initialize session watcher for provider "${provider}"`, {
290
+ rootPath,
291
+ error: message,
292
+ });
293
+ }
294
+ }
295
+ }
296
+
297
+ /**
298
+ * Stops all active provider session watchers.
299
+ */
300
+ export async function closeSessionsWatcher(): Promise<void> {
301
+ clearPendingWatcherFlushTimer();
302
+
303
+ await Promise.all(
304
+ watchers.map(async (watcher) => {
305
+ try {
306
+ await watcher.close();
307
+ } catch (error) {
308
+ const message = error instanceof Error ? error.message : String(error);
309
+ console.error('Failed to close session watcher', { error: message });
310
+ }
311
+ })
312
+ );
313
+ watchers.length = 0;
314
+ pendingWatcherUpdate = null;
315
+ pendingWatcherUpdateStartedAt = null;
316
+ watcherRefreshInFlight = false;
317
+ watcherRescheduleAfterRefresh = false;
318
+ }
@@ -0,0 +1,240 @@
1
+ import fsp from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ import { projectsDb, sessionsDb } from '@/modules/database/index.js';
5
+ import { providerRegistry } from '@/modules/providers/provider.registry.js';
6
+ import type {
7
+ FetchHistoryOptions,
8
+ FetchHistoryResult,
9
+ LLMProvider,
10
+ NormalizedMessage,
11
+ } from '@/shared/types.js';
12
+ import { AppError } from '@/shared/utils.js';
13
+
14
+ type ArchivedSessionListItem = {
15
+ sessionId: string;
16
+ provider: LLMProvider;
17
+ projectId: string | null;
18
+ projectPath: string | null;
19
+ projectDisplayName: string;
20
+ sessionTitle: string;
21
+ createdAt: string | null;
22
+ updatedAt: string | null;
23
+ lastActivity: string | null;
24
+ isProjectArchived: boolean;
25
+ };
26
+
27
+ /**
28
+ * Removes one file if it exists.
29
+ */
30
+ async function removeFileIfExists(filePath: string): Promise<boolean> {
31
+ try {
32
+ await fsp.unlink(filePath);
33
+ return true;
34
+ } catch (error) {
35
+ const code = (error as NodeJS.ErrnoException).code;
36
+ if (code === 'ENOENT') {
37
+ return false;
38
+ }
39
+ throw error;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Archive rows need a stable project label even when the owning project is not
45
+ * part of the active sidebar payload. This lightweight resolver keeps the
46
+ * archive API self-contained while still matching the project's stored display
47
+ * name when one exists.
48
+ */
49
+ function resolveProjectDisplayName(
50
+ projectPath: string | null,
51
+ customProjectName: string | null | undefined,
52
+ ): string {
53
+ const trimmedCustomName = typeof customProjectName === 'string' ? customProjectName.trim() : '';
54
+ if (trimmedCustomName.length > 0) {
55
+ return trimmedCustomName;
56
+ }
57
+
58
+ if (!projectPath) {
59
+ return 'Unknown Project';
60
+ }
61
+
62
+ return path.basename(projectPath) || projectPath;
63
+ }
64
+
65
+ /**
66
+ * Application service for provider-backed session message operations.
67
+ *
68
+ * Callers pass a provider id and this service resolves the concrete provider
69
+ * class, keeping normalization/history call sites decoupled from implementation
70
+ * file layout.
71
+ */
72
+ export const sessionsService = {
73
+ /**
74
+ * Lists provider ids that can load session history and normalize live messages.
75
+ */
76
+ listProviderIds(): LLMProvider[] {
77
+ return providerRegistry.listProviders().map((provider) => provider.id);
78
+ },
79
+
80
+ /**
81
+ * Normalizes one provider-native event into frontend session message events.
82
+ */
83
+ normalizeMessage(
84
+ providerName: string,
85
+ raw: unknown,
86
+ sessionId: string | null,
87
+ ): NormalizedMessage[] {
88
+ return providerRegistry.resolveProvider(providerName).sessions.normalizeMessage(raw, sessionId);
89
+ },
90
+
91
+ /**
92
+ * Fetches persisted history by session id.
93
+ *
94
+ * Provider and provider-specific lookup hints are resolved from the indexed
95
+ * session metadata in the database.
96
+ */
97
+ fetchHistory(
98
+ userId: number,
99
+ sessionId: string,
100
+ options: Pick<FetchHistoryOptions, 'limit' | 'offset'> = {},
101
+ ): Promise<FetchHistoryResult> {
102
+ const session = sessionsDb.getSessionById(userId, sessionId);
103
+ if (!session) {
104
+ throw new AppError(`Session "${sessionId}" was not found.`, {
105
+ code: 'SESSION_NOT_FOUND',
106
+ statusCode: 404,
107
+ });
108
+ }
109
+
110
+ const provider = session.provider as LLMProvider;
111
+ return providerRegistry.resolveProvider(provider).sessions.fetchHistory(sessionId, {
112
+ limit: options.limit ?? null,
113
+ offset: options.offset ?? 0,
114
+ projectPath: session.project_path ?? '',
115
+ userId,
116
+ });
117
+ },
118
+
119
+ /**
120
+ * Returns archived sessions with enough project metadata for the sidebar to
121
+ * group, filter, open, and restore them without a per-row follow-up query.
122
+ */
123
+ listArchivedSessions(userId: number): ArchivedSessionListItem[] {
124
+ const archivedSessions = sessionsDb.getArchivedSessions(userId);
125
+ const projectCache = new Map<string, ReturnType<typeof projectsDb.getProjectPath>>();
126
+
127
+ return archivedSessions.map((session) => {
128
+ const projectPath = session.project_path?.trim() ? session.project_path : null;
129
+ let project = null;
130
+
131
+ if (projectPath) {
132
+ if (!projectCache.has(projectPath)) {
133
+ projectCache.set(projectPath, projectsDb.getProjectPath(userId, projectPath));
134
+ }
135
+ project = projectCache.get(projectPath) ?? null;
136
+ }
137
+
138
+ return {
139
+ sessionId: session.session_id,
140
+ provider: session.provider as LLMProvider,
141
+ projectId: project?.project_id ?? null,
142
+ projectPath,
143
+ projectDisplayName: resolveProjectDisplayName(projectPath, project?.custom_project_name),
144
+ sessionTitle: session.custom_name?.trim() || session.session_id,
145
+ createdAt: session.created_at ?? null,
146
+ updatedAt: session.updated_at ?? null,
147
+ lastActivity: session.updated_at ?? session.created_at ?? null,
148
+ isProjectArchived: Boolean(project?.isArchived),
149
+ };
150
+ });
151
+ },
152
+
153
+ /**
154
+ * Archives or permanently deletes one persisted session row by id.
155
+ *
156
+ * Soft-delete mirrors the project behavior by toggling `isArchived` so the
157
+ * row disappears from active lists but remains restorable. Force-delete
158
+ * optionally removes the transcript file before deleting the database row.
159
+ */
160
+ async deleteOrArchiveSessionById(
161
+ userId: number,
162
+ sessionId: string,
163
+ options: {
164
+ force?: boolean;
165
+ deletedFromDisk?: boolean;
166
+ } = {},
167
+ ): Promise<{ sessionId: string; action: 'archived' | 'deleted'; deletedFromDisk: boolean }> {
168
+ const session = sessionsDb.getSessionById(userId, sessionId);
169
+ if (!session) {
170
+ throw new AppError(`Session "${sessionId}" was not found.`, {
171
+ code: 'SESSION_NOT_FOUND',
172
+ statusCode: 404,
173
+ });
174
+ }
175
+
176
+ if (!options.force) {
177
+ sessionsDb.updateSessionIsArchived(userId, sessionId, true);
178
+ return {
179
+ sessionId,
180
+ action: 'archived',
181
+ deletedFromDisk: false,
182
+ };
183
+ }
184
+
185
+ let removedFromDisk = false;
186
+ if (options.deletedFromDisk && session.jsonl_path) {
187
+ removedFromDisk = await removeFileIfExists(session.jsonl_path);
188
+ }
189
+
190
+ const deleted = sessionsDb.deleteSessionById(userId, sessionId);
191
+ if (!deleted) {
192
+ throw new AppError(`Session "${sessionId}" was not found.`, {
193
+ code: 'SESSION_NOT_FOUND',
194
+ statusCode: 404,
195
+ });
196
+ }
197
+
198
+ return {
199
+ sessionId,
200
+ action: 'deleted',
201
+ deletedFromDisk: removedFromDisk,
202
+ };
203
+ },
204
+
205
+ /**
206
+ * Restores one archived session back into the active sidebar lists.
207
+ */
208
+ restoreSessionById(userId: number, sessionId: string): { sessionId: string; isArchived: false } {
209
+ const session = sessionsDb.getSessionById(userId, sessionId);
210
+ if (!session) {
211
+ throw new AppError(`Session "${sessionId}" was not found.`, {
212
+ code: 'SESSION_NOT_FOUND',
213
+ statusCode: 404,
214
+ });
215
+ }
216
+
217
+ sessionsDb.updateSessionIsArchived(userId, sessionId, false);
218
+ return { sessionId, isArchived: false };
219
+ },
220
+
221
+ /**
222
+ * Renames one session by id without requiring the caller to pass provider.
223
+ */
224
+ renameSessionById(
225
+ userId: number,
226
+ sessionId: string,
227
+ summary: string,
228
+ ): { sessionId: string; summary: string } {
229
+ const session = sessionsDb.getSessionById(userId, sessionId);
230
+ if (!session) {
231
+ throw new AppError(`Session "${sessionId}" was not found.`, {
232
+ code: 'SESSION_NOT_FOUND',
233
+ statusCode: 404,
234
+ });
235
+ }
236
+
237
+ sessionsDb.updateSessionCustomName(userId, sessionId, summary);
238
+ return { sessionId, summary };
239
+ },
240
+ };
@@ -0,0 +1,15 @@
1
+ import { providerRegistry } from '@/modules/providers/provider.registry.js';
2
+ import type { ProviderSkill, ProviderSkillListOptions } from '@/shared/types.js';
3
+
4
+ export const providerSkillsService = {
5
+ /**
6
+ * Lists normalized skills visible to one provider.
7
+ */
8
+ async listProviderSkills(
9
+ providerName: string,
10
+ options?: ProviderSkillListOptions,
11
+ ): Promise<ProviderSkill[]> {
12
+ const provider = providerRegistry.resolveProvider(providerName);
13
+ return provider.skills.listSkills(options);
14
+ },
15
+ };
@@ -0,0 +1,29 @@
1
+ import type {
2
+ IProvider,
3
+ IProviderAuth,
4
+ IProviderMcp,
5
+ IProviderSessionSynchronizer,
6
+ IProviderSkills,
7
+ IProviderSessions,
8
+ } from '@/shared/interfaces.js';
9
+ import type { LLMProvider } from '@/shared/types.js';
10
+
11
+ /**
12
+ * Shared provider base.
13
+ *
14
+ * Concrete providers must expose auth/MCP handlers and implement message
15
+ * normalization/history loading because those behaviors depend on native
16
+ * SDK/CLI formats.
17
+ */
18
+ export abstract class AbstractProvider implements IProvider {
19
+ readonly id: LLMProvider;
20
+ abstract readonly mcp: IProviderMcp;
21
+ abstract readonly auth: IProviderAuth;
22
+ abstract readonly skills: IProviderSkills;
23
+ abstract readonly sessions: IProviderSessions;
24
+ abstract readonly sessionSynchronizer: IProviderSessionSynchronizer;
25
+
26
+ protected constructor(id: LLMProvider) {
27
+ this.id = id;
28
+ }
29
+ }