@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,496 @@
1
+ import { Database } from 'better-sqlite3';
2
+
3
+ import {
4
+ APP_CONFIG_TABLE_SCHEMA_SQL,
5
+ LAST_SCANNED_AT_SQL,
6
+ PROJECTS_TABLE_SCHEMA_SQL,
7
+ PUSH_SUBSCRIPTIONS_TABLE_SCHEMA_SQL,
8
+ SESSIONS_TABLE_SCHEMA_SQL,
9
+ USER_NOTIFICATION_PREFERENCES_TABLE_SCHEMA_SQL,
10
+ VAPID_KEYS_TABLE_SCHEMA_SQL,
11
+ } from '@/modules/database/schema.js';
12
+
13
+ const SQLITE_UUID_SQL = `
14
+ lower(hex(randomblob(4))) || '-' ||
15
+ lower(hex(randomblob(2))) || '-' ||
16
+ lower(hex(randomblob(2))) || '-' ||
17
+ lower(hex(randomblob(2))) || '-' ||
18
+ lower(hex(randomblob(6)))
19
+ `;
20
+
21
+ type TableInfoRow = {
22
+ name: string;
23
+ pk: number;
24
+ };
25
+
26
+ const addColumnToTableIfNotExists = (
27
+ db: Database,
28
+ tableName: string,
29
+ columnNames: string[],
30
+ columnName: string,
31
+ columnType: string
32
+ ) => {
33
+ if (!columnNames.includes(columnName)) {
34
+ console.log(`Running migration: Adding ${columnName} column to ${tableName} table`);
35
+ db.exec(`ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${columnType}`);
36
+ }
37
+ };
38
+
39
+ const tableExists = (db: Database, tableName: string): boolean =>
40
+ Boolean(
41
+ db
42
+ .prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?")
43
+ .get(tableName)
44
+ );
45
+
46
+ const getTableInfo = (db: Database, tableName: string): TableInfoRow[] =>
47
+ db.prepare(`PRAGMA table_info(${tableName})`).all() as TableInfoRow[];
48
+
49
+ const migrateLegacySessionNames = (db: Database): void => {
50
+ const hasLegacySessionNamesTable = tableExists(db, 'session_names');
51
+ const hasSessionsTable = tableExists(db, 'sessions');
52
+
53
+ if (!hasLegacySessionNamesTable) {
54
+ return;
55
+ }
56
+
57
+ if (hasSessionsTable) {
58
+ console.log('Running migration: Merging session_names into sessions');
59
+ db.exec(`
60
+ INSERT INTO sessions (session_id, user_id, provider, custom_name, created_at, updated_at)
61
+ SELECT
62
+ session_id,
63
+ COALESCE(
64
+ (SELECT id FROM users WHERE is_active = 1 ORDER BY id LIMIT 1),
65
+ 1
66
+ ),
67
+ COALESCE(provider, 'claude'),
68
+ custom_name,
69
+ COALESCE(created_at, CURRENT_TIMESTAMP),
70
+ COALESCE(updated_at, CURRENT_TIMESTAMP)
71
+ FROM session_names
72
+ WHERE true
73
+ ON CONFLICT(user_id, session_id) DO UPDATE SET
74
+ provider = excluded.provider,
75
+ custom_name = COALESCE(excluded.custom_name, sessions.custom_name),
76
+ created_at = COALESCE(sessions.created_at, excluded.created_at),
77
+ updated_at = COALESCE(excluded.updated_at, sessions.updated_at)
78
+ `);
79
+ db.exec('DROP TABLE session_names');
80
+ return;
81
+ }
82
+
83
+ console.log('Running migration: Renaming session_names table to sessions');
84
+ db.exec('ALTER TABLE session_names RENAME TO sessions');
85
+ };
86
+
87
+ const migrateLegacyWorkspaceTableIntoProjects = (db: Database): void => {
88
+ db.exec(PROJECTS_TABLE_SCHEMA_SQL);
89
+
90
+ if (!tableExists(db, 'workspace_original_paths')) {
91
+ return;
92
+ }
93
+
94
+ console.log('Running migration: Migrating workspace_original_paths data into projects');
95
+ db.exec(`
96
+ INSERT INTO projects (project_id, user_id, project_path, custom_project_name, isStarred, isArchived)
97
+ SELECT
98
+ CASE
99
+ WHEN workspace_id IS NULL OR trim(workspace_id) = ''
100
+ THEN ${SQLITE_UUID_SQL}
101
+ ELSE workspace_id
102
+ END,
103
+ COALESCE(
104
+ (SELECT id FROM users WHERE is_active = 1 ORDER BY id LIMIT 1),
105
+ 1
106
+ ),
107
+ workspace_path,
108
+ custom_workspace_name,
109
+ COALESCE(isStarred, 0),
110
+ 0
111
+ FROM workspace_original_paths
112
+ WHERE workspace_path IS NOT NULL AND trim(workspace_path) <> ''
113
+ ON CONFLICT(user_id, project_path) DO UPDATE SET
114
+ custom_project_name = COALESCE(projects.custom_project_name, excluded.custom_project_name),
115
+ isStarred = COALESCE(projects.isStarred, excluded.isStarred)
116
+ `);
117
+ };
118
+
119
+ const rebuildProjectsTableWithPrimaryKeySchema = (db: Database): void => {
120
+ const hasProjectsTable = tableExists(db, 'projects');
121
+ if (!hasProjectsTable) {
122
+ db.exec(PROJECTS_TABLE_SCHEMA_SQL);
123
+ return;
124
+ }
125
+
126
+ const projectsTableInfo = getTableInfo(db, 'projects');
127
+ const columnNames = projectsTableInfo.map((column) => column.name);
128
+ const hasProjectIdPrimaryKey = projectsTableInfo.some(
129
+ (column) => column.name === 'project_id' && column.pk === 1,
130
+ );
131
+
132
+ const shouldRebuild = !hasProjectIdPrimaryKey || !columnNames.includes('user_id');
133
+
134
+ if (!shouldRebuild) {
135
+ addColumnToTableIfNotExists(db, 'projects', columnNames, 'custom_project_name', 'TEXT DEFAULT NULL');
136
+ addColumnToTableIfNotExists(db, 'projects', columnNames, 'isStarred', 'BOOLEAN DEFAULT 0');
137
+ addColumnToTableIfNotExists(db, 'projects', columnNames, 'isArchived', 'BOOLEAN DEFAULT 0');
138
+ db.exec(`
139
+ UPDATE projects
140
+ SET project_id = ${SQLITE_UUID_SQL}
141
+ WHERE project_id IS NULL OR trim(project_id) = ''
142
+ `);
143
+ return;
144
+ }
145
+
146
+ console.log('Running migration: Rebuilding projects table to enforce user_id + project_id primary key schema');
147
+
148
+ const projectPathExpression = columnNames.includes('project_path')
149
+ ? 'project_path'
150
+ : columnNames.includes('workspace_path')
151
+ ? 'workspace_path'
152
+ : 'NULL';
153
+
154
+ const userIdExpression = columnNames.includes('user_id')
155
+ ? 'user_id'
156
+ : 'COALESCE((SELECT id FROM users WHERE is_active = 1 ORDER BY id LIMIT 1), 1)';
157
+
158
+ const customProjectNameExpression = columnNames.includes('custom_project_name')
159
+ ? 'custom_project_name'
160
+ : columnNames.includes('custom_workspace_name')
161
+ ? 'custom_workspace_name'
162
+ : 'NULL';
163
+
164
+ const isStarredExpression = columnNames.includes('isStarred') ? 'COALESCE(isStarred, 0)' : '0';
165
+
166
+ const isArchivedExpression = columnNames.includes('isArchived') ? 'COALESCE(isArchived, 0)' : '0';
167
+
168
+ const projectIdExpression = columnNames.includes('project_id')
169
+ ? `CASE
170
+ WHEN project_id IS NULL OR trim(project_id) = ''
171
+ THEN ${SQLITE_UUID_SQL}
172
+ ELSE project_id
173
+ END`
174
+ : SQLITE_UUID_SQL;
175
+
176
+ db.exec('PRAGMA foreign_keys = OFF');
177
+ try {
178
+ db.exec('BEGIN TRANSACTION');
179
+ db.exec('DROP TABLE IF EXISTS projects__new');
180
+ db.exec(`
181
+ CREATE TABLE projects__new (
182
+ project_id TEXT PRIMARY KEY NOT NULL,
183
+ user_id INTEGER NOT NULL,
184
+ project_path TEXT NOT NULL,
185
+ custom_project_name TEXT DEFAULT NULL,
186
+ isStarred BOOLEAN DEFAULT 0,
187
+ isArchived BOOLEAN DEFAULT 0,
188
+ FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
189
+ UNIQUE(user_id, project_path)
190
+ )
191
+ `);
192
+ db.exec(`
193
+ WITH source_rows AS (
194
+ SELECT
195
+ ${userIdExpression} AS user_id,
196
+ ${projectPathExpression} AS project_path,
197
+ ${customProjectNameExpression} AS custom_project_name,
198
+ ${isStarredExpression} AS isStarred,
199
+ ${isArchivedExpression} AS isArchived,
200
+ ${projectIdExpression} AS candidate_project_id,
201
+ rowid AS source_rowid
202
+ FROM projects
203
+ WHERE ${projectPathExpression} IS NOT NULL AND trim(${projectPathExpression}) <> ''
204
+ ),
205
+ deduped_paths AS (
206
+ SELECT
207
+ user_id,
208
+ project_path,
209
+ custom_project_name,
210
+ isStarred,
211
+ isArchived,
212
+ candidate_project_id,
213
+ source_rowid,
214
+ ROW_NUMBER() OVER (PARTITION BY user_id, project_path ORDER BY source_rowid) AS project_path_rank
215
+ FROM source_rows
216
+ ),
217
+ prepared_rows AS (
218
+ SELECT
219
+ CASE
220
+ WHEN ROW_NUMBER() OVER (PARTITION BY candidate_project_id ORDER BY source_rowid) = 1
221
+ THEN candidate_project_id
222
+ ELSE ${SQLITE_UUID_SQL}
223
+ END AS project_id,
224
+ user_id,
225
+ project_path,
226
+ custom_project_name,
227
+ isStarred,
228
+ isArchived
229
+ FROM deduped_paths
230
+ WHERE project_path_rank = 1
231
+ )
232
+ INSERT INTO projects__new (
233
+ project_id,
234
+ user_id,
235
+ project_path,
236
+ custom_project_name,
237
+ isStarred,
238
+ isArchived
239
+ )
240
+ SELECT
241
+ project_id,
242
+ user_id,
243
+ project_path,
244
+ custom_project_name,
245
+ isStarred,
246
+ isArchived
247
+ FROM prepared_rows
248
+ `);
249
+ db.exec('DROP TABLE projects');
250
+ db.exec('ALTER TABLE projects__new RENAME TO projects');
251
+ db.exec('COMMIT');
252
+ } catch (migrationError) {
253
+ db.exec('ROLLBACK');
254
+ throw migrationError;
255
+ } finally {
256
+ db.exec('PRAGMA foreign_keys = ON');
257
+ }
258
+ };
259
+
260
+ const rebuildSessionsTableWithProjectSchema = (db: Database): void => {
261
+ const hasSessions = tableExists(db, 'sessions');
262
+ if (!hasSessions) {
263
+ db.exec(SESSIONS_TABLE_SCHEMA_SQL);
264
+ return;
265
+ }
266
+
267
+ const sessionsTableInfo = getTableInfo(db, 'sessions');
268
+ const columnNames = sessionsTableInfo.map((column) => column.name);
269
+ const primaryKeyColumns = sessionsTableInfo
270
+ .filter((column) => column.pk > 0)
271
+ .sort((a, b) => a.pk - b.pk)
272
+ .map((column) => column.name);
273
+
274
+ const shouldRebuild =
275
+ !columnNames.includes('project_path') ||
276
+ !columnNames.includes('user_id') ||
277
+ primaryKeyColumns.length !== 2 ||
278
+ primaryKeyColumns[0] !== 'user_id' ||
279
+ primaryKeyColumns[1] !== 'session_id' ||
280
+ !columnNames.includes('provider');
281
+
282
+ if (!shouldRebuild) {
283
+ addColumnToTableIfNotExists(db, 'sessions', columnNames, 'jsonl_path', 'TEXT');
284
+ addColumnToTableIfNotExists(db, 'sessions', columnNames, 'isArchived', 'BOOLEAN DEFAULT 0');
285
+ addColumnToTableIfNotExists(db, 'sessions', columnNames, 'created_at', 'DATETIME');
286
+ addColumnToTableIfNotExists(db, 'sessions', columnNames, 'updated_at', 'DATETIME');
287
+ db.exec('UPDATE sessions SET isArchived = COALESCE(isArchived, 0)');
288
+ db.exec('UPDATE sessions SET created_at = COALESCE(created_at, CURRENT_TIMESTAMP)');
289
+ db.exec('UPDATE sessions SET updated_at = COALESCE(updated_at, CURRENT_TIMESTAMP)');
290
+ return;
291
+ }
292
+
293
+ console.log('Running migration: Rebuilding sessions table to project-based schema');
294
+
295
+ const projectPathExpression = columnNames.includes('project_path')
296
+ ? 'project_path'
297
+ : columnNames.includes('workspace_path')
298
+ ? 'workspace_path'
299
+ : 'NULL';
300
+
301
+ const providerExpression = columnNames.includes('provider')
302
+ ? "COALESCE(provider, 'claude')"
303
+ : "'claude'";
304
+
305
+ const userIdExpression = columnNames.includes('user_id')
306
+ ? 'user_id'
307
+ : 'COALESCE((SELECT id FROM users WHERE is_active = 1 ORDER BY id LIMIT 1), 1)';
308
+
309
+ const customNameExpression = columnNames.includes('custom_name')
310
+ ? 'custom_name'
311
+ : 'NULL';
312
+
313
+ const jsonlPathExpression = columnNames.includes('jsonl_path')
314
+ ? 'jsonl_path'
315
+ : 'NULL';
316
+
317
+ const isArchivedExpression = columnNames.includes('isArchived')
318
+ ? 'COALESCE(isArchived, 0)'
319
+ : '0';
320
+
321
+ const createdAtExpression = columnNames.includes('created_at')
322
+ ? 'COALESCE(created_at, CURRENT_TIMESTAMP)'
323
+ : 'CURRENT_TIMESTAMP';
324
+
325
+ const updatedAtExpression = columnNames.includes('updated_at')
326
+ ? 'COALESCE(updated_at, CURRENT_TIMESTAMP)'
327
+ : 'CURRENT_TIMESTAMP';
328
+
329
+ db.exec('PRAGMA foreign_keys = OFF');
330
+ try {
331
+ db.exec('BEGIN TRANSACTION');
332
+ db.exec('DROP TABLE IF EXISTS sessions__new');
333
+ db.exec(`
334
+ CREATE TABLE sessions__new (
335
+ session_id TEXT NOT NULL,
336
+ user_id INTEGER NOT NULL,
337
+ provider TEXT NOT NULL DEFAULT 'claude',
338
+ custom_name TEXT,
339
+ project_path TEXT,
340
+ jsonl_path TEXT,
341
+ isArchived BOOLEAN DEFAULT 0,
342
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
343
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
344
+ PRIMARY KEY (user_id, session_id),
345
+ FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
346
+ FOREIGN KEY (user_id, project_path) REFERENCES projects(user_id, project_path)
347
+ ON DELETE CASCADE
348
+ ON UPDATE CASCADE
349
+ )
350
+ `);
351
+ db.exec(`
352
+ WITH source_rows AS (
353
+ SELECT
354
+ session_id,
355
+ ${userIdExpression} AS user_id,
356
+ ${providerExpression} AS provider,
357
+ ${customNameExpression} AS custom_name,
358
+ ${projectPathExpression} AS project_path,
359
+ ${jsonlPathExpression} AS jsonl_path,
360
+ ${isArchivedExpression} AS isArchived,
361
+ ${createdAtExpression} AS created_at,
362
+ ${updatedAtExpression} AS updated_at,
363
+ rowid AS source_rowid
364
+ FROM sessions
365
+ WHERE session_id IS NOT NULL AND trim(session_id) <> ''
366
+ ),
367
+ ranked_rows AS (
368
+ SELECT
369
+ session_id,
370
+ user_id,
371
+ provider,
372
+ custom_name,
373
+ project_path,
374
+ jsonl_path,
375
+ isArchived,
376
+ created_at,
377
+ updated_at,
378
+ ROW_NUMBER() OVER (
379
+ PARTITION BY user_id, session_id
380
+ ORDER BY datetime(COALESCE(updated_at, created_at)) DESC, source_rowid DESC
381
+ ) AS session_rank
382
+ FROM source_rows
383
+ )
384
+ INSERT INTO sessions__new (
385
+ session_id,
386
+ user_id,
387
+ provider,
388
+ custom_name,
389
+ project_path,
390
+ jsonl_path,
391
+ isArchived,
392
+ created_at,
393
+ updated_at
394
+ )
395
+ SELECT
396
+ session_id,
397
+ user_id,
398
+ provider,
399
+ custom_name,
400
+ project_path,
401
+ jsonl_path,
402
+ isArchived,
403
+ created_at,
404
+ updated_at
405
+ FROM ranked_rows
406
+ WHERE session_rank = 1
407
+ `);
408
+ db.exec('DROP TABLE sessions');
409
+ db.exec('ALTER TABLE sessions__new RENAME TO sessions');
410
+ db.exec('COMMIT');
411
+ } catch (migrationError) {
412
+ db.exec('ROLLBACK');
413
+ throw migrationError;
414
+ } finally {
415
+ db.exec('PRAGMA foreign_keys = ON');
416
+ }
417
+ };
418
+
419
+ const ensureProjectsForSessionPaths = (db: Database): void => {
420
+ if (!tableExists(db, 'sessions')) {
421
+ return;
422
+ }
423
+
424
+ db.exec(`
425
+ INSERT INTO projects (project_id, user_id, project_path, custom_project_name, isStarred, isArchived)
426
+ SELECT
427
+ ${SQLITE_UUID_SQL},
428
+ user_id,
429
+ project_path,
430
+ NULL,
431
+ 0,
432
+ 0
433
+ FROM sessions
434
+ WHERE project_path IS NOT NULL AND trim(project_path) <> ''
435
+ ON CONFLICT(user_id, project_path) DO NOTHING
436
+ `);
437
+ };
438
+
439
+ export const runMigrations = (db: Database) => {
440
+ try {
441
+ const usersTableInfo = db.prepare('PRAGMA table_info(users)').all() as { name: string }[];
442
+ const userColumnNames = usersTableInfo.map((column) => column.name);
443
+
444
+ addColumnToTableIfNotExists(db, 'users', userColumnNames, 'git_name', 'TEXT');
445
+ addColumnToTableIfNotExists(db, 'users', userColumnNames, 'git_email', 'TEXT');
446
+ addColumnToTableIfNotExists(
447
+ db,
448
+ 'users',
449
+ userColumnNames,
450
+ 'has_completed_onboarding',
451
+ 'BOOLEAN DEFAULT 0'
452
+ );
453
+ addColumnToTableIfNotExists(db, 'users', userColumnNames, 'is_admin', 'BOOLEAN DEFAULT 0');
454
+
455
+ db.exec("UPDATE users SET is_admin = 1 WHERE id = 1 AND is_active = 1");
456
+
457
+ db.exec(APP_CONFIG_TABLE_SCHEMA_SQL);
458
+ db.exec(USER_NOTIFICATION_PREFERENCES_TABLE_SCHEMA_SQL);
459
+ db.exec(VAPID_KEYS_TABLE_SCHEMA_SQL);
460
+ db.exec(PUSH_SUBSCRIPTIONS_TABLE_SCHEMA_SQL);
461
+ db.exec('CREATE INDEX IF NOT EXISTS idx_push_subscriptions_user_id ON push_subscriptions(user_id)');
462
+
463
+ db.exec(PROJECTS_TABLE_SCHEMA_SQL);
464
+ rebuildProjectsTableWithPrimaryKeySchema(db);
465
+
466
+ migrateLegacyWorkspaceTableIntoProjects(db);
467
+ rebuildSessionsTableWithProjectSchema(db);
468
+ migrateLegacySessionNames(db);
469
+ ensureProjectsForSessionPaths(db);
470
+
471
+ db.exec('CREATE INDEX IF NOT EXISTS idx_session_ids_lookup ON sessions(user_id, session_id)');
472
+ db.exec('CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id)');
473
+ db.exec('CREATE INDEX IF NOT EXISTS idx_sessions_project_path ON sessions(user_id, project_path)');
474
+ db.exec('CREATE INDEX IF NOT EXISTS idx_sessions_is_archived ON sessions(isArchived)');
475
+ db.exec('CREATE INDEX IF NOT EXISTS idx_projects_user_id ON projects(user_id)');
476
+ db.exec('CREATE INDEX IF NOT EXISTS idx_projects_user_path ON projects(user_id, project_path)');
477
+ db.exec('CREATE INDEX IF NOT EXISTS idx_projects_is_starred ON projects(isStarred)');
478
+ db.exec('CREATE INDEX IF NOT EXISTS idx_projects_is_archived ON projects(isArchived)');
479
+
480
+ db.exec('DROP INDEX IF EXISTS idx_session_names_lookup');
481
+ db.exec('DROP INDEX IF EXISTS idx_sessions_workspace_path');
482
+ db.exec('DROP INDEX IF EXISTS idx_workspace_original_paths_is_starred');
483
+ db.exec('DROP INDEX IF EXISTS idx_workspace_original_paths_workspace_id');
484
+
485
+ if (tableExists(db, 'workspace_original_paths')) {
486
+ console.log('Running migration: Dropping legacy workspace_original_paths table');
487
+ db.exec('DROP TABLE workspace_original_paths');
488
+ }
489
+
490
+ db.exec(LAST_SCANNED_AT_SQL);
491
+ console.log('Database migrations completed successfully');
492
+ } catch (error: any) {
493
+ console.error('Error running migrations:', error.message);
494
+ throw error;
495
+ }
496
+ };
@@ -0,0 +1,119 @@
1
+ /**
2
+ * API keys repository.
3
+ *
4
+ * Manages API keys used for external/programmatic access to the backend.
5
+ * Keys are prefixed with `ck_` and tied to a user via foreign key.
6
+ */
7
+
8
+ import crypto from 'crypto';
9
+
10
+ import { getConnection } from '@/modules/database/connection.js';
11
+
12
+ type ApiKeyRow = {
13
+ id: number;
14
+ key_name: string;
15
+ api_key: string;
16
+ created_at: string;
17
+ last_used: string | null;
18
+ is_active: number;
19
+ };
20
+
21
+ type CreateApiKeyResult = {
22
+ id: number | bigint;
23
+ keyName: string;
24
+ apiKey: string;
25
+ };
26
+
27
+ type ValidatedApiKeyUser = {
28
+ id: number;
29
+ username: string;
30
+ api_key_id: number;
31
+ };
32
+
33
+ // ---------------------------------------------------------------------------
34
+ // Helpers
35
+ // ---------------------------------------------------------------------------
36
+
37
+ /** Generates a cryptographically random API key with the `ck_` prefix. */
38
+ function generateApiKey(): string {
39
+ return 'ck_' + crypto.randomBytes(32).toString('hex');
40
+ }
41
+
42
+ // ---------------------------------------------------------------------------
43
+ // Queries
44
+ // ---------------------------------------------------------------------------
45
+
46
+ export const apiKeysDb = {
47
+ generateApiKey,
48
+
49
+ /** Creates a new API key for the given user and returns it for one-time display. */
50
+ createApiKey(userId: number, keyName: string): CreateApiKeyResult {
51
+ const db = getConnection();
52
+ const apiKey = generateApiKey();
53
+ const result = db
54
+ .prepare(
55
+ 'INSERT INTO api_keys (user_id, key_name, api_key) VALUES (?, ?, ?)'
56
+ )
57
+ .run(userId, keyName, apiKey);
58
+ return { id: result.lastInsertRowid, keyName, apiKey };
59
+ },
60
+
61
+ /** Lists all API keys for a user, most recent first. */
62
+ getApiKeys(userId: number): ApiKeyRow[] {
63
+ const db = getConnection();
64
+ return db
65
+ .prepare(
66
+ 'SELECT id, key_name, api_key, created_at, last_used, is_active FROM api_keys WHERE user_id = ? ORDER BY created_at DESC'
67
+ )
68
+ .all(userId) as ApiKeyRow[];
69
+ },
70
+
71
+ /**
72
+ * Validates an API key and resolves the owning user.
73
+ * If the key is valid, its `last_used` timestamp is updated as a side effect.
74
+ * Returns undefined when the key is invalid or the user is inactive.
75
+ */
76
+ validateApiKey(apiKey: string): ValidatedApiKeyUser | undefined {
77
+ const db = getConnection();
78
+ const row = db
79
+ .prepare(
80
+ `SELECT u.id, u.username, ak.id as api_key_id
81
+ FROM api_keys ak
82
+ JOIN users u ON ak.user_id = u.id
83
+ WHERE ak.api_key = ? AND ak.is_active = 1 AND u.is_active = 1`
84
+ )
85
+ .get(apiKey) as ValidatedApiKeyUser | undefined;
86
+
87
+ if (row) {
88
+ db.prepare(
89
+ 'UPDATE api_keys SET last_used = CURRENT_TIMESTAMP WHERE id = ?'
90
+ ).run(row.api_key_id);
91
+ }
92
+
93
+ return row;
94
+ },
95
+
96
+ /** Permanently removes an API key. Returns true if a row was deleted. */
97
+ deleteApiKey(userId: number, apiKeyId: number): boolean {
98
+ const db = getConnection();
99
+ const result = db
100
+ .prepare('DELETE FROM api_keys WHERE id = ? AND user_id = ?')
101
+ .run(apiKeyId, userId);
102
+ return result.changes > 0;
103
+ },
104
+
105
+ /** Enables or disables an API key without deleting it. */
106
+ toggleApiKey(
107
+ userId: number,
108
+ apiKeyId: number,
109
+ isActive: boolean
110
+ ): boolean {
111
+ const db = getConnection();
112
+ const result = db
113
+ .prepare(
114
+ 'UPDATE api_keys SET is_active = ? WHERE id = ? AND user_id = ?'
115
+ )
116
+ .run(isActive ? 1 : 0, apiKeyId, userId);
117
+ return result.changes > 0;
118
+ },
119
+ };
@@ -0,0 +1,53 @@
1
+ /**
2
+ * App config repository.
3
+ *
4
+ * Key-value store for application-level configuration that persists
5
+ * across restarts (JWT secret, feature flags, etc.). Values are always
6
+ * stored as strings; callers handle parsing.
7
+ */
8
+
9
+ import crypto from 'crypto';
10
+
11
+ import { getConnection } from '@/modules/database/connection.js';
12
+
13
+ // ---------------------------------------------------------------------------
14
+ // Queries
15
+ // ---------------------------------------------------------------------------
16
+
17
+ export const appConfigDb = {
18
+ /** Returns the stored value for a config key, or null if missing. */
19
+ get(key: string): string | null {
20
+ try {
21
+ const db = getConnection();
22
+ const row = db
23
+ .prepare('SELECT value FROM app_config WHERE key = ?')
24
+ .get(key) as { value: string } | undefined;
25
+ return row?.value ?? null;
26
+ } catch {
27
+ // Swallow errors so early-startup reads (e.g. JWT secret) do not crash.
28
+ return null;
29
+ }
30
+ },
31
+
32
+ /** Inserts or updates a config key (upsert). */
33
+ set(key: string, value: string): void {
34
+ const db = getConnection();
35
+ db.prepare(
36
+ 'INSERT INTO app_config (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value'
37
+ ).run(key, value);
38
+ },
39
+
40
+ /**
41
+ * Returns the JWT signing secret, generating and persisting one
42
+ * if it does not already exist. This ensures the secret survives
43
+ * server restarts while being created automatically on first boot.
44
+ */
45
+ getOrCreateJwtSecret(): string {
46
+ let secret = appConfigDb.get('jwt_secret');
47
+ if (!secret) {
48
+ secret = crypto.randomBytes(64).toString('hex');
49
+ appConfigDb.set('jwt_secret', secret);
50
+ }
51
+ return secret;
52
+ },
53
+ };