upfynai-code 2.6.0 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/README.md +123 -88
  2. package/bin/cli.js +63 -0
  3. package/package.json +48 -106
  4. package/src/auth.js +115 -0
  5. package/src/config.js +33 -0
  6. package/src/connect.js +314 -0
  7. package/src/launch.js +54 -0
  8. package/src/mcp.js +57 -0
  9. package/src/server.js +54 -0
  10. package/client/dist/api-docs.html +0 -879
  11. package/client/dist/assets/AppContent-C0CyP3g5.js +0 -513
  12. package/client/dist/assets/CanvasPanel-0u9QR7U-.js +0 -34
  13. package/client/dist/assets/CanvasPanel-WhZulBJw.css +0 -1
  14. package/client/dist/assets/DashboardPanel-Dgqw1yZk.js +0 -1
  15. package/client/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  16. package/client/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  17. package/client/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  18. package/client/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  19. package/client/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  20. package/client/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  21. package/client/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  22. package/client/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  23. package/client/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  24. package/client/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  25. package/client/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  26. package/client/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  27. package/client/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  28. package/client/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  29. package/client/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  30. package/client/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  31. package/client/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  32. package/client/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  33. package/client/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  34. package/client/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  35. package/client/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  36. package/client/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  37. package/client/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  38. package/client/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  39. package/client/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  40. package/client/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  41. package/client/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  42. package/client/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  43. package/client/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  44. package/client/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  45. package/client/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  46. package/client/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  47. package/client/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  48. package/client/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  49. package/client/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  50. package/client/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  51. package/client/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  52. package/client/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  53. package/client/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  54. package/client/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  55. package/client/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  56. package/client/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  57. package/client/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  58. package/client/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  59. package/client/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  60. package/client/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  61. package/client/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  62. package/client/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  63. package/client/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  64. package/client/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  65. package/client/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  66. package/client/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  67. package/client/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  68. package/client/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  69. package/client/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  70. package/client/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  71. package/client/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  72. package/client/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  73. package/client/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  74. package/client/dist/assets/LoginModal-CZDEzqjK.js +0 -19
  75. package/client/dist/assets/MarkdownPreview-CYdvwJaV.js +0 -1
  76. package/client/dist/assets/Onboarding-DR6NZ4Vz.js +0 -1
  77. package/client/dist/assets/SetupForm-D49gtWY4.js +0 -1
  78. package/client/dist/assets/Tableau10-B-NsZVaP.js +0 -1
  79. package/client/dist/assets/WorkflowsPanel-CqlbEJA_.js +0 -1
  80. package/client/dist/assets/_commonjs-dynamic-modules-TDtrdbi3.js +0 -1
  81. package/client/dist/assets/ar-SA-G6X2FPQ2-BWqa1yBH.js +0 -10
  82. package/client/dist/assets/arc-BegSKqEW.js +0 -1
  83. package/client/dist/assets/array-BKyUJesY.js +0 -1
  84. package/client/dist/assets/az-AZ-76LH7QW2-DrVlbZDP.js +0 -1
  85. package/client/dist/assets/bg-BG-XCXSNQG7-DdunjBgT.js +0 -5
  86. package/client/dist/assets/blockDiagram-38ab4fdb-BKMbwGHu.js +0 -118
  87. package/client/dist/assets/bn-BD-2XOGV67Q-_7DtmvwO.js +0 -5
  88. package/client/dist/assets/c4Diagram-3d4e48cf-hJuiHhSn.js +0 -10
  89. package/client/dist/assets/ca-ES-6MX7JW3Y-BFIrmojG.js +0 -8
  90. package/client/dist/assets/channel-Bur-rRTp.js +0 -1
  91. package/client/dist/assets/classDiagram-70f12bd4-BjiAf9cM.js +0 -2
  92. package/client/dist/assets/classDiagram-v2-f2320105-pwBewejc.js +0 -2
  93. package/client/dist/assets/clone-BtqXeoBJ.js +0 -1
  94. package/client/dist/assets/createText-2e5e7dd3-Dq_acOWe.js +0 -5
  95. package/client/dist/assets/cs-CZ-2BRQDIVT-B-x4F6TJ.js +0 -11
  96. package/client/dist/assets/da-DK-5WZEPLOC-Btlc8Dgn.js +0 -5
  97. package/client/dist/assets/de-DE-XR44H4JA-BVu3ZIoD.js +0 -8
  98. package/client/dist/assets/directory-open-01563666-DWU9wJ6I.js +0 -1
  99. package/client/dist/assets/directory-open-4ed118d0-CunoC1EB.js +0 -1
  100. package/client/dist/assets/edges-e0da2a9e-DH0wVTXR.js +0 -4
  101. package/client/dist/assets/el-GR-BZB4AONW-h2ll8_ZC.js +0 -10
  102. package/client/dist/assets/erDiagram-9861fffd-BYezLIR7.js +0 -51
  103. package/client/dist/assets/es-ES-U4NZUMDT-Cveiulwt.js +0 -9
  104. package/client/dist/assets/eu-ES-A7QVB2H4-DQluL2PY.js +0 -11
  105. package/client/dist/assets/fa-IR-HGAKTJCU-BJtcMBSv.js +0 -8
  106. package/client/dist/assets/fi-FI-Z5N7JZ37-D8NfbVXV.js +0 -6
  107. package/client/dist/assets/file-open-002ab408-DIuFHtCF.js +0 -1
  108. package/client/dist/assets/file-open-7c801643-684qeFg4.js +0 -1
  109. package/client/dist/assets/file-save-3189631c-C1wFhQhH.js +0 -1
  110. package/client/dist/assets/file-save-745eba88-Bb9F9Kg7.js +0 -1
  111. package/client/dist/assets/flowDb-956e92f1-scnUykhM.js +0 -10
  112. package/client/dist/assets/flowDiagram-66a62f08-jVyWsfyU.js +0 -4
  113. package/client/dist/assets/flowDiagram-v2-96b9c2cf-N6xgi25h.js +0 -1
  114. package/client/dist/assets/flowchart-elk-definition-4a651766-gKGX3HqR.js +0 -139
  115. package/client/dist/assets/fr-FR-RHASNOE6-vdj42kC6.js +0 -9
  116. package/client/dist/assets/ganttDiagram-c361ad54-C2CiWFUP.js +0 -257
  117. package/client/dist/assets/gitGraphDiagram-72cf32ee-C59Yz2LK.js +0 -70
  118. package/client/dist/assets/gl-ES-HMX3MZ6V-DQo0TzoP.js +0 -10
  119. package/client/dist/assets/graph-Dx_H43Kv.js +0 -1
  120. package/client/dist/assets/he-IL-6SHJWFNN-DKXK5e33.js +0 -10
  121. package/client/dist/assets/hi-IN-IWLTKZ5I-C2Qgqc0R.js +0 -4
  122. package/client/dist/assets/hu-HU-A5ZG7DT2-Ss-6vX0m.js +0 -7
  123. package/client/dist/assets/id-ID-SAP4L64H-D7Wsg1S2.js +0 -10
  124. package/client/dist/assets/image-blob-reduce.esm-D6s-rqMO.js +0 -7
  125. package/client/dist/assets/index-3862675e-u8Nv7hHC.js +0 -1
  126. package/client/dist/assets/index-BVowJdZF.js +0 -97
  127. package/client/dist/assets/index-ce18TYkg.js +0 -27
  128. package/client/dist/assets/index-kQoJx-bc.css +0 -1
  129. package/client/dist/assets/infoDiagram-f8f76790-LmoJYsxo.js +0 -7
  130. package/client/dist/assets/init-Gi6I4Gst.js +0 -1
  131. package/client/dist/assets/it-IT-JPQ66NNP-CAPTVl7M.js +0 -11
  132. package/client/dist/assets/ja-JP-DBVTYXUO-eNVPawR2.js +0 -8
  133. package/client/dist/assets/journeyDiagram-49397b02-BaJqehpR.js +0 -139
  134. package/client/dist/assets/kaa-6HZHGXH3-tpuNkKhS.js +0 -1
  135. package/client/dist/assets/kab-KAB-ZGHBKWFO-Dp83kx4x.js +0 -8
  136. package/client/dist/assets/kk-KZ-P5N5QNE5-B9IlC6YN.js +0 -1
  137. package/client/dist/assets/km-KH-HSX4SM5Z-B_KMYaMj.js +0 -11
  138. package/client/dist/assets/ko-KR-MTYHY66A-yebnUNdb.js +0 -9
  139. package/client/dist/assets/ku-TR-6OUDTVRD-BR6fh6-5.js +0 -9
  140. package/client/dist/assets/layout-DLl5Jwcl.js +0 -1
  141. package/client/dist/assets/line-FpB7omSK.js +0 -1
  142. package/client/dist/assets/linear-CkXqUFJ8.js +0 -1
  143. package/client/dist/assets/lt-LT-XHIRWOB4-SutZSWtR.js +0 -3
  144. package/client/dist/assets/lv-LV-5QDEKY6T-DuAxdcZL.js +0 -7
  145. package/client/dist/assets/mindmap-definition-fc14e90a-DyxXOExh.js +0 -425
  146. package/client/dist/assets/mr-IN-CRQNXWMA-DqDUWM_8.js +0 -13
  147. package/client/dist/assets/my-MM-5M5IBNSE-C40kMFMR.js +0 -1
  148. package/client/dist/assets/nb-NO-T6EIAALU-DVij32Ju.js +0 -10
  149. package/client/dist/assets/nl-NL-IS3SIHDZ-rT84mDYq.js +0 -8
  150. package/client/dist/assets/nn-NO-6E72VCQL-BBZXBW8V.js +0 -8
  151. package/client/dist/assets/oc-FR-POXYY2M6-DzjOugOf.js +0 -8
  152. package/client/dist/assets/ordinal-Cboi1Yqb.js +0 -1
  153. package/client/dist/assets/pa-IN-N4M65BXN-DD1iU8_F.js +0 -4
  154. package/client/dist/assets/path-CbwjOpE9.js +0 -1
  155. package/client/dist/assets/pdf-CE_K4jFx.js +0 -12
  156. package/client/dist/assets/pdf.worker-BA9kU3Pw.mjs +0 -61080
  157. package/client/dist/assets/percentages-BXMCSKIN-WVlHS4wx.js +0 -207
  158. package/client/dist/assets/pica-CQIY57Tf.js +0 -7
  159. package/client/dist/assets/pieDiagram-8a3498a8-Dd_85qBH.js +0 -35
  160. package/client/dist/assets/pl-PL-T2D74RX3-ukVXa48G.js +0 -9
  161. package/client/dist/assets/pt-BR-5N22H2LF-BibawarT.js +0 -9
  162. package/client/dist/assets/pt-PT-UZXXM6DQ-So3i9l9w.js +0 -9
  163. package/client/dist/assets/quadrantDiagram-120e2f19-C4dFVDEx.js +0 -7
  164. package/client/dist/assets/requirementDiagram-deff3bca-DrTO7yFl.js +0 -52
  165. package/client/dist/assets/ro-RO-JPDTUUEW-DY0Xq_Hd.js +0 -11
  166. package/client/dist/assets/roundRect-0PYZxl1G.js +0 -1
  167. package/client/dist/assets/ru-RU-B4JR7IUQ-B7u_Zvkd.js +0 -9
  168. package/client/dist/assets/sankeyDiagram-04a897e0-D24gfzuS.js +0 -8
  169. package/client/dist/assets/sequenceDiagram-704730f1-Dgji2XLQ.js +0 -122
  170. package/client/dist/assets/si-LK-N5RQ5JYF-OejsLzQ_.js +0 -1
  171. package/client/dist/assets/sk-SK-C5VTKIMK-_vy2Bt-M.js +0 -6
  172. package/client/dist/assets/sl-SI-NN7IZMDC-DKOl_u2M.js +0 -6
  173. package/client/dist/assets/stateDiagram-587899a1-CJ8eBaiU.js +0 -1
  174. package/client/dist/assets/stateDiagram-v2-d93cdb3a-C5K3l-Nt.js +0 -1
  175. package/client/dist/assets/styles-6aaf32cf-DAKE0jbx.js +0 -207
  176. package/client/dist/assets/styles-9a916d00-LFAJCgEy.js +0 -160
  177. package/client/dist/assets/styles-c10674c1-CllKO8NG.js +0 -116
  178. package/client/dist/assets/subset-shared.chunk-Uy-J87FQ.js +0 -84
  179. package/client/dist/assets/subset-worker.chunk-dvgDvqt9.js +0 -1
  180. package/client/dist/assets/sv-SE-XGPEYMSR-CDCB2ZV5.js +0 -10
  181. package/client/dist/assets/svgDrawCommon-08f97a94-CObOzbFQ.js +0 -1
  182. package/client/dist/assets/ta-IN-2NMHFXQM-DHUNdO69.js +0 -9
  183. package/client/dist/assets/th-TH-HPSO5L25-zI2hnBq3.js +0 -2
  184. package/client/dist/assets/timeline-definition-85554ec2-C2XHRmxK.js +0 -61
  185. package/client/dist/assets/tr-TR-DEFEU3FU-l-6Hu4-D.js +0 -7
  186. package/client/dist/assets/uk-UA-QMV73CPH-CqSOwrl7.js +0 -6
  187. package/client/dist/assets/vendor-codemirror-D_s0aGBu.js +0 -35
  188. package/client/dist/assets/vendor-i18n-DCFGyhQR.js +0 -1
  189. package/client/dist/assets/vendor-icons-Lb69KSFJ.js +0 -646
  190. package/client/dist/assets/vendor-markdown-BXEi_H3G.js +0 -298
  191. package/client/dist/assets/vendor-react-9mUTKBHH.js +0 -67
  192. package/client/dist/assets/vendor-syntax-DnmwQQJF.js +0 -16
  193. package/client/dist/assets/vendor-xterm-CZq1hqo1.js +0 -66
  194. package/client/dist/assets/vendor-xterm-qxJ8_QYu.css +0 -32
  195. package/client/dist/assets/vi-VN-M7AON7JQ-CUL8-mBZ.js +0 -5
  196. package/client/dist/assets/xychartDiagram-e933f94c-1fmf6slj.js +0 -7
  197. package/client/dist/assets/zh-CN-LNUGB5OW-CB5y5VVU.js +0 -10
  198. package/client/dist/assets/zh-HK-E62DVLB3-BHcrrEeJ.js +0 -1
  199. package/client/dist/assets/zh-TW-RAJ6MFWO-DoDUdkaJ.js +0 -9
  200. package/client/dist/clear-cache.html +0 -85
  201. package/client/dist/convert-icons.md +0 -53
  202. package/client/dist/favicon.png +0 -0
  203. package/client/dist/favicon.svg +0 -9
  204. package/client/dist/generate-icons.js +0 -49
  205. package/client/dist/icons/claude-ai-icon.svg +0 -1
  206. package/client/dist/icons/codex-white.svg +0 -3
  207. package/client/dist/icons/codex.svg +0 -3
  208. package/client/dist/icons/cursor-white.svg +0 -12
  209. package/client/dist/icons/cursor.svg +0 -1
  210. package/client/dist/icons/icon-128x128.png +0 -0
  211. package/client/dist/icons/icon-128x128.svg +0 -12
  212. package/client/dist/icons/icon-144x144.png +0 -0
  213. package/client/dist/icons/icon-144x144.svg +0 -12
  214. package/client/dist/icons/icon-152x152.png +0 -0
  215. package/client/dist/icons/icon-152x152.svg +0 -12
  216. package/client/dist/icons/icon-192x192.png +0 -0
  217. package/client/dist/icons/icon-192x192.svg +0 -12
  218. package/client/dist/icons/icon-384x384.png +0 -0
  219. package/client/dist/icons/icon-384x384.svg +0 -12
  220. package/client/dist/icons/icon-512x512.png +0 -0
  221. package/client/dist/icons/icon-512x512.svg +0 -12
  222. package/client/dist/icons/icon-72x72.png +0 -0
  223. package/client/dist/icons/icon-72x72.svg +0 -12
  224. package/client/dist/icons/icon-96x96.png +0 -0
  225. package/client/dist/icons/icon-96x96.svg +0 -12
  226. package/client/dist/icons/icon-template.svg +0 -12
  227. package/client/dist/index.html +0 -128
  228. package/client/dist/logo-128.png +0 -0
  229. package/client/dist/logo-256.png +0 -0
  230. package/client/dist/logo-32.png +0 -0
  231. package/client/dist/logo-512.png +0 -0
  232. package/client/dist/logo-64.png +0 -0
  233. package/client/dist/logo.svg +0 -17
  234. package/client/dist/manifest.json +0 -61
  235. package/client/dist/mcp-docs.html +0 -119
  236. package/client/dist/screenshots/cli-selection.png +0 -0
  237. package/client/dist/screenshots/desktop-main.png +0 -0
  238. package/client/dist/screenshots/mobile-chat.png +0 -0
  239. package/client/dist/screenshots/tools-modal.png +0 -0
  240. package/client/dist/sw.js +0 -19
  241. package/commands/upfynai-connect.md +0 -59
  242. package/commands/upfynai-disconnect.md +0 -31
  243. package/commands/upfynai-doctor.md +0 -99
  244. package/commands/upfynai-export.md +0 -49
  245. package/commands/upfynai-local.md +0 -82
  246. package/commands/upfynai-status.md +0 -75
  247. package/commands/upfynai-stop.md +0 -49
  248. package/commands/upfynai-uninstall.md +0 -58
  249. package/commands/upfynai.md +0 -69
  250. package/scripts/build-client.js +0 -17
  251. package/scripts/fix-node-pty.js +0 -67
  252. package/scripts/install-commands.js +0 -78
  253. package/server/claude-sdk.js +0 -714
  254. package/server/cli-ui.js +0 -785
  255. package/server/cli.js +0 -596
  256. package/server/constants/config.js +0 -31
  257. package/server/cursor-cli.js +0 -270
  258. package/server/database/auth.db +0 -0
  259. package/server/database/db.js +0 -822
  260. package/server/database/init.sql +0 -70
  261. package/server/index.js +0 -2738
  262. package/server/load-env.js +0 -26
  263. package/server/mcp-server.js +0 -621
  264. package/server/middleware/auth.js +0 -181
  265. package/server/openai-codex.js +0 -403
  266. package/server/openrouter.js +0 -137
  267. package/server/projects.js +0 -1742
  268. package/server/relay-client.js +0 -672
  269. package/server/routes/agent.js +0 -1226
  270. package/server/routes/auth.js +0 -266
  271. package/server/routes/cli-auth.js +0 -263
  272. package/server/routes/codex.js +0 -344
  273. package/server/routes/commands.js +0 -598
  274. package/server/routes/cursor.js +0 -807
  275. package/server/routes/dashboard.js +0 -205
  276. package/server/routes/git.js +0 -1151
  277. package/server/routes/mcp-utils.js +0 -48
  278. package/server/routes/mcp.js +0 -535
  279. package/server/routes/payments.js +0 -172
  280. package/server/routes/projects.js +0 -552
  281. package/server/routes/settings.js +0 -261
  282. package/server/routes/taskmaster.js +0 -1928
  283. package/server/routes/user.js +0 -106
  284. package/server/routes/vapi-chat.js +0 -94
  285. package/server/routes/voice.js +0 -194
  286. package/server/routes/webhooks.js +0 -166
  287. package/server/routes/workflows.js +0 -118
  288. package/server/sandbox.js +0 -120
  289. package/server/services/whisperService.js +0 -84
  290. package/server/services/workflowScheduler.js +0 -186
  291. package/server/utils/commandParser.js +0 -303
  292. package/server/utils/gitConfig.js +0 -24
  293. package/server/utils/mcp-detector.js +0 -198
  294. package/server/utils/taskmaster-websocket.js +0 -129
  295. package/shared/modelConstants.js +0 -96
@@ -1,807 +0,0 @@
1
- import express from 'express';
2
- import { promises as fs } from 'fs';
3
- import path from 'path';
4
- import os from 'os';
5
- import { spawn } from 'child_process';
6
- // sqlite3 is a native module — conditionally imported (not available on Vercel)
7
- let sqlite3 = null;
8
- let sqliteOpen = null;
9
- try {
10
- sqlite3 = (await import('sqlite3')).default;
11
- sqliteOpen = (await import('sqlite')).open;
12
- } catch (e) {
13
- }
14
- import crypto from 'crypto';
15
- import { CURSOR_MODELS } from '../../shared/modelConstants.js';
16
-
17
- const router = express.Router();
18
-
19
- // GET /api/cursor/config - Read Cursor CLI configuration
20
- router.get('/config', async (req, res) => {
21
- try {
22
- const configPath = path.join(os.homedir(), '.cursor', 'cli-config.json');
23
-
24
- try {
25
- const configContent = await fs.readFile(configPath, 'utf8');
26
- const config = JSON.parse(configContent);
27
-
28
- res.json({
29
- success: true,
30
- config: config,
31
- path: configPath
32
- });
33
- } catch (error) {
34
- // Config doesn't exist or is invalid
35
- // cursor config not found
36
-
37
- // Return default config
38
- res.json({
39
- success: true,
40
- config: {
41
- version: 1,
42
- model: {
43
- modelId: CURSOR_MODELS.DEFAULT,
44
- displayName: "GPT-5"
45
- },
46
- permissions: {
47
- allow: [],
48
- deny: []
49
- }
50
- },
51
- isDefault: true
52
- });
53
- }
54
- } catch (error) {
55
- // config read error
56
- res.status(500).json({
57
- error: 'Failed to read Cursor configuration',
58
- details: 'An error occurred'
59
- });
60
- }
61
- });
62
-
63
- // POST /api/cursor/config - Update Cursor CLI configuration
64
- router.post('/config', async (req, res) => {
65
- try {
66
- const { permissions, model } = req.body;
67
- const configPath = path.join(os.homedir(), '.cursor', 'cli-config.json');
68
-
69
- // Read existing config or create default
70
- let config = {
71
- version: 1,
72
- editor: {
73
- vimMode: false
74
- },
75
- hasChangedDefaultModel: false,
76
- privacyCache: {
77
- ghostMode: false,
78
- privacyMode: 3,
79
- updatedAt: Date.now()
80
- }
81
- };
82
-
83
- try {
84
- const existing = await fs.readFile(configPath, 'utf8');
85
- config = JSON.parse(existing);
86
- } catch (error) {
87
- // Config doesn't exist, use defaults
88
- // creating new config
89
- }
90
-
91
- // Update permissions if provided
92
- if (permissions) {
93
- config.permissions = {
94
- allow: permissions.allow || [],
95
- deny: permissions.deny || []
96
- };
97
- }
98
-
99
- // Update model if provided
100
- if (model) {
101
- config.model = model;
102
- config.hasChangedDefaultModel = true;
103
- }
104
-
105
- // Ensure directory exists
106
- const configDir = path.dirname(configPath);
107
- await fs.mkdir(configDir, { recursive: true });
108
-
109
- // Write updated config
110
- await fs.writeFile(configPath, JSON.stringify(config, null, 2));
111
-
112
- res.json({
113
- success: true,
114
- config: config,
115
- message: 'Cursor configuration updated successfully'
116
- });
117
- } catch (error) {
118
- // config update error
119
- res.status(500).json({
120
- error: 'Failed to update Cursor configuration',
121
- details: 'An error occurred'
122
- });
123
- }
124
- });
125
-
126
- // GET /api/cursor/mcp - Read Cursor MCP servers configuration
127
- router.get('/mcp', async (req, res) => {
128
- try {
129
- const mcpPath = path.join(os.homedir(), '.cursor', 'mcp.json');
130
-
131
- try {
132
- const mcpContent = await fs.readFile(mcpPath, 'utf8');
133
- const mcpConfig = JSON.parse(mcpContent);
134
-
135
- // Convert to UI-friendly format
136
- const servers = [];
137
- if (mcpConfig.mcpServers && typeof mcpConfig.mcpServers === 'object') {
138
- for (const [name, config] of Object.entries(mcpConfig.mcpServers)) {
139
- const server = {
140
- id: name,
141
- name: name,
142
- type: 'stdio',
143
- scope: 'cursor',
144
- config: {},
145
- raw: config
146
- };
147
-
148
- // Determine transport type and extract config
149
- if (config.command) {
150
- server.type = 'stdio';
151
- server.config.command = config.command;
152
- server.config.args = config.args || [];
153
- server.config.env = config.env || {};
154
- } else if (config.url) {
155
- server.type = config.transport || 'http';
156
- server.config.url = config.url;
157
- server.config.headers = config.headers || {};
158
- }
159
-
160
- servers.push(server);
161
- }
162
- }
163
-
164
- res.json({
165
- success: true,
166
- servers: servers,
167
- path: mcpPath
168
- });
169
- } catch (error) {
170
- // MCP config doesn't exist
171
- // MCP config not found
172
- res.json({
173
- success: true,
174
- servers: [],
175
- isDefault: true
176
- });
177
- }
178
- } catch (error) {
179
- // MCP config read error
180
- res.status(500).json({
181
- error: 'Failed to read Cursor MCP configuration',
182
- details: 'An error occurred'
183
- });
184
- }
185
- });
186
-
187
- // POST /api/cursor/mcp/add - Add MCP server to Cursor configuration
188
- router.post('/mcp/add', async (req, res) => {
189
- try {
190
- const { name, type = 'stdio', command, args = [], url, headers = {}, env = {} } = req.body;
191
- const mcpPath = path.join(os.homedir(), '.cursor', 'mcp.json');
192
-
193
- // adding MCP server
194
-
195
- // Read existing config or create new
196
- let mcpConfig = { mcpServers: {} };
197
-
198
- try {
199
- const existing = await fs.readFile(mcpPath, 'utf8');
200
- mcpConfig = JSON.parse(existing);
201
- if (!mcpConfig.mcpServers) {
202
- mcpConfig.mcpServers = {};
203
- }
204
- } catch (error) {
205
- // creating new MCP config
206
- }
207
-
208
- // Build server config based on type
209
- let serverConfig = {};
210
-
211
- if (type === 'stdio') {
212
- serverConfig = {
213
- command: command,
214
- args: args,
215
- env: env
216
- };
217
- } else if (type === 'http' || type === 'sse') {
218
- serverConfig = {
219
- url: url,
220
- transport: type,
221
- headers: headers
222
- };
223
- }
224
-
225
- // Add server to config
226
- mcpConfig.mcpServers[name] = serverConfig;
227
-
228
- // Ensure directory exists
229
- const mcpDir = path.dirname(mcpPath);
230
- await fs.mkdir(mcpDir, { recursive: true });
231
-
232
- // Write updated config
233
- await fs.writeFile(mcpPath, JSON.stringify(mcpConfig, null, 2));
234
-
235
- res.json({
236
- success: true,
237
- message: `MCP server "${name}" added to Cursor configuration`,
238
- config: mcpConfig
239
- });
240
- } catch (error) {
241
- // MCP server add error
242
- res.status(500).json({
243
- error: 'Failed to add MCP server',
244
- details: 'An error occurred'
245
- });
246
- }
247
- });
248
-
249
- // DELETE /api/cursor/mcp/:name - Remove MCP server from Cursor configuration
250
- router.delete('/mcp/:name', async (req, res) => {
251
- try {
252
- const { name } = req.params;
253
- const mcpPath = path.join(os.homedir(), '.cursor', 'mcp.json');
254
-
255
- // removing MCP server
256
-
257
- // Read existing config
258
- let mcpConfig = { mcpServers: {} };
259
-
260
- try {
261
- const existing = await fs.readFile(mcpPath, 'utf8');
262
- mcpConfig = JSON.parse(existing);
263
- } catch (error) {
264
- return res.status(404).json({
265
- error: 'Cursor MCP configuration not found'
266
- });
267
- }
268
-
269
- // Check if server exists
270
- if (!mcpConfig.mcpServers || !mcpConfig.mcpServers[name]) {
271
- return res.status(404).json({
272
- error: `MCP server "${name}" not found in Cursor configuration`
273
- });
274
- }
275
-
276
- // Remove server from config
277
- delete mcpConfig.mcpServers[name];
278
-
279
- // Write updated config
280
- await fs.writeFile(mcpPath, JSON.stringify(mcpConfig, null, 2));
281
-
282
- res.json({
283
- success: true,
284
- message: `MCP server "${name}" removed from Cursor configuration`,
285
- config: mcpConfig
286
- });
287
- } catch (error) {
288
- // MCP server remove error
289
- res.status(500).json({
290
- error: 'Failed to remove MCP server',
291
- details: 'An error occurred'
292
- });
293
- }
294
- });
295
-
296
- // POST /api/cursor/mcp/add-json - Add MCP server using JSON format
297
- router.post('/mcp/add-json', async (req, res) => {
298
- try {
299
- const { name, jsonConfig } = req.body;
300
- const mcpPath = path.join(os.homedir(), '.cursor', 'mcp.json');
301
-
302
- // adding MCP server via JSON
303
-
304
- // Validate and parse JSON config
305
- let parsedConfig;
306
- try {
307
- parsedConfig = typeof jsonConfig === 'string' ? JSON.parse(jsonConfig) : jsonConfig;
308
- } catch (parseError) {
309
- return res.status(400).json({
310
- error: 'Invalid JSON configuration',
311
- details: parseError.message
312
- });
313
- }
314
-
315
- // Read existing config or create new
316
- let mcpConfig = { mcpServers: {} };
317
-
318
- try {
319
- const existing = await fs.readFile(mcpPath, 'utf8');
320
- mcpConfig = JSON.parse(existing);
321
- if (!mcpConfig.mcpServers) {
322
- mcpConfig.mcpServers = {};
323
- }
324
- } catch (error) {
325
- // creating new MCP config
326
- }
327
-
328
- // Add server to config
329
- mcpConfig.mcpServers[name] = parsedConfig;
330
-
331
- // Ensure directory exists
332
- const mcpDir = path.dirname(mcpPath);
333
- await fs.mkdir(mcpDir, { recursive: true });
334
-
335
- // Write updated config
336
- await fs.writeFile(mcpPath, JSON.stringify(mcpConfig, null, 2));
337
-
338
- res.json({
339
- success: true,
340
- message: `MCP server "${name}" added to Cursor configuration via JSON`,
341
- config: mcpConfig
342
- });
343
- } catch (error) {
344
- // MCP server JSON add error
345
- res.status(500).json({
346
- error: 'Failed to add MCP server',
347
- details: 'An error occurred'
348
- });
349
- }
350
- });
351
-
352
- // GET /api/cursor/sessions - Get Cursor sessions from SQLite database
353
- router.get('/sessions', async (req, res) => {
354
- try {
355
- const { projectPath } = req.query;
356
-
357
- // Calculate cwdID hash for the project path (Cursor uses MD5 hash)
358
- const cwdId = crypto.createHash('md5').update(projectPath || process.cwd()).digest('hex');
359
- const cursorChatsPath = path.join(os.homedir(), '.cursor', 'chats', cwdId);
360
-
361
-
362
- // Check if the directory exists
363
- try {
364
- await fs.access(cursorChatsPath);
365
- } catch (error) {
366
- // No sessions for this project
367
- return res.json({
368
- success: true,
369
- sessions: [],
370
- cwdId: cwdId,
371
- path: cursorChatsPath
372
- });
373
- }
374
-
375
- // List all session directories
376
- const sessionDirs = await fs.readdir(cursorChatsPath);
377
- const sessions = [];
378
-
379
- for (const sessionId of sessionDirs) {
380
- const sessionPath = path.join(cursorChatsPath, sessionId);
381
- const storeDbPath = path.join(sessionPath, 'store.db');
382
- let dbStatMtimeMs = null;
383
-
384
- try {
385
- // Check if store.db exists
386
- await fs.access(storeDbPath);
387
-
388
- // Capture store.db mtime as a reliable fallback timestamp (last activity)
389
- try {
390
- const stat = await fs.stat(storeDbPath);
391
- dbStatMtimeMs = stat.mtimeMs;
392
- } catch (_) {}
393
-
394
- // Open SQLite database
395
- if (!sqliteOpen || !sqlite3) {
396
- continue; // Skip on Vercel where native modules aren't available
397
- }
398
- const db = await sqliteOpen({
399
- filename: storeDbPath,
400
- driver: sqlite3.Database,
401
- mode: sqlite3.OPEN_READONLY
402
- });
403
-
404
- // Get metadata from meta table
405
- const metaRows = await db.all(`
406
- SELECT key, value FROM meta
407
- `);
408
-
409
- let sessionData = {
410
- id: sessionId,
411
- name: 'Untitled Session',
412
- createdAt: null,
413
- mode: null,
414
- projectPath: projectPath,
415
- lastMessage: null,
416
- messageCount: 0
417
- };
418
-
419
- // Parse meta table entries
420
- for (const row of metaRows) {
421
- if (row.value) {
422
- try {
423
- // Try to decode as hex-encoded JSON
424
- const hexMatch = row.value.toString().match(/^[0-9a-fA-F]+$/);
425
- if (hexMatch) {
426
- const jsonStr = Buffer.from(row.value, 'hex').toString('utf8');
427
- const data = JSON.parse(jsonStr);
428
-
429
- if (row.key === 'agent') {
430
- sessionData.name = data.name || sessionData.name;
431
- // Normalize createdAt to ISO string in milliseconds
432
- let createdAt = data.createdAt;
433
- if (typeof createdAt === 'number') {
434
- if (createdAt < 1e12) {
435
- createdAt = createdAt * 1000; // seconds -> ms
436
- }
437
- sessionData.createdAt = new Date(createdAt).toISOString();
438
- } else if (typeof createdAt === 'string') {
439
- const n = Number(createdAt);
440
- if (!Number.isNaN(n)) {
441
- const ms = n < 1e12 ? n * 1000 : n;
442
- sessionData.createdAt = new Date(ms).toISOString();
443
- } else {
444
- // Assume it's already an ISO/date string
445
- const d = new Date(createdAt);
446
- sessionData.createdAt = isNaN(d.getTime()) ? null : d.toISOString();
447
- }
448
- } else {
449
- sessionData.createdAt = sessionData.createdAt || null;
450
- }
451
- sessionData.mode = data.mode;
452
- sessionData.agentId = data.agentId;
453
- sessionData.latestRootBlobId = data.latestRootBlobId;
454
- }
455
- } else {
456
- // If not hex, use raw value for simple keys
457
- if (row.key === 'name') {
458
- sessionData.name = row.value.toString();
459
- }
460
- }
461
- } catch (e) {
462
- // meta parse error
463
- }
464
- }
465
- }
466
-
467
- // Get message count from JSON blobs only (actual messages, not DAG structure)
468
- try {
469
- const blobCount = await db.get(`
470
- SELECT COUNT(*) as count
471
- FROM blobs
472
- WHERE substr(data, 1, 1) = X'7B'
473
- `);
474
- sessionData.messageCount = blobCount.count;
475
-
476
- // Get the most recent JSON blob for preview (actual message, not DAG structure)
477
- const lastBlob = await db.get(`
478
- SELECT data FROM blobs
479
- WHERE substr(data, 1, 1) = X'7B'
480
- ORDER BY rowid DESC
481
- LIMIT 1
482
- `);
483
-
484
- if (lastBlob && lastBlob.data) {
485
- try {
486
- // Try to extract readable preview from blob (may contain binary with embedded JSON)
487
- const raw = lastBlob.data.toString('utf8');
488
- let preview = '';
489
- // Attempt direct JSON parse
490
- try {
491
- const parsed = JSON.parse(raw);
492
- if (parsed?.content) {
493
- if (Array.isArray(parsed.content)) {
494
- const firstText = parsed.content.find(p => p?.type === 'text' && p.text)?.text || '';
495
- preview = firstText;
496
- } else if (typeof parsed.content === 'string') {
497
- preview = parsed.content;
498
- }
499
- }
500
- } catch (_) {}
501
- if (!preview) {
502
- // Strip non-printable and try to find JSON chunk
503
- const cleaned = raw.replace(/[^\x09\x0A\x0D\x20-\x7E]/g, '');
504
- const s = cleaned;
505
- const start = s.indexOf('{');
506
- const end = s.lastIndexOf('}');
507
- if (start !== -1 && end > start) {
508
- const jsonStr = s.slice(start, end + 1);
509
- try {
510
- const parsed = JSON.parse(jsonStr);
511
- if (parsed?.content) {
512
- if (Array.isArray(parsed.content)) {
513
- const firstText = parsed.content.find(p => p?.type === 'text' && p.text)?.text || '';
514
- preview = firstText;
515
- } else if (typeof parsed.content === 'string') {
516
- preview = parsed.content;
517
- }
518
- }
519
- } catch (_) {
520
- preview = s;
521
- }
522
- } else {
523
- preview = s;
524
- }
525
- }
526
- if (preview && preview.length > 0) {
527
- sessionData.lastMessage = preview.substring(0, 100) + (preview.length > 100 ? '...' : '');
528
- }
529
- } catch (e) {
530
- // blob parse error
531
- }
532
- }
533
- } catch (e) {
534
- // blobs read error
535
- }
536
-
537
- await db.close();
538
-
539
- // Finalize createdAt: use parsed meta value when valid, else fall back to store.db mtime
540
- if (!sessionData.createdAt) {
541
- if (dbStatMtimeMs && Number.isFinite(dbStatMtimeMs)) {
542
- sessionData.createdAt = new Date(dbStatMtimeMs).toISOString();
543
- }
544
- }
545
-
546
- sessions.push(sessionData);
547
-
548
- } catch (error) {
549
- // session read error
550
- }
551
- }
552
-
553
- // Fallback: ensure createdAt is a valid ISO string (use session directory mtime as last resort)
554
- for (const s of sessions) {
555
- if (!s.createdAt) {
556
- try {
557
- const sessionDir = path.join(cursorChatsPath, s.id);
558
- const st = await fs.stat(sessionDir);
559
- s.createdAt = new Date(st.mtimeMs).toISOString();
560
- } catch {
561
- s.createdAt = new Date().toISOString();
562
- }
563
- }
564
- }
565
- // Sort sessions by creation date (newest first)
566
- sessions.sort((a, b) => {
567
- if (!a.createdAt) return 1;
568
- if (!b.createdAt) return -1;
569
- return new Date(b.createdAt) - new Date(a.createdAt);
570
- });
571
-
572
- res.json({
573
- success: true,
574
- sessions: sessions,
575
- cwdId: cwdId,
576
- path: cursorChatsPath
577
- });
578
-
579
- } catch (error) {
580
- // sessions read error
581
- res.status(500).json({
582
- error: 'Failed to read Cursor sessions',
583
- details: 'An error occurred'
584
- });
585
- }
586
- });
587
-
588
- // GET /api/cursor/sessions/:sessionId - Get specific Cursor session from SQLite
589
- router.get('/sessions/:sessionId', async (req, res) => {
590
- try {
591
- const { sessionId } = req.params;
592
- const { projectPath } = req.query;
593
-
594
- // Calculate cwdID hash for the project path
595
- const cwdId = crypto.createHash('md5').update(projectPath || process.cwd()).digest('hex');
596
- const storeDbPath = path.join(os.homedir(), '.cursor', 'chats', cwdId, sessionId, 'store.db');
597
-
598
-
599
- // Open SQLite database (requires native sqlite3 module)
600
- if (!sqliteOpen || !sqlite3) {
601
- return res.status(503).json({ error: 'SQLite not available on this deployment' });
602
- }
603
- const db = await sqliteOpen({
604
- filename: storeDbPath,
605
- driver: sqlite3.Database,
606
- mode: sqlite3.OPEN_READONLY
607
- });
608
-
609
- // Get all blobs to build the DAG structure
610
- const allBlobs = await db.all(`
611
- SELECT rowid, id, data FROM blobs
612
- `);
613
-
614
- // Build the DAG structure from parent-child relationships
615
- const blobMap = new Map(); // id -> blob data
616
- const parentRefs = new Map(); // blob id -> [parent blob ids]
617
- const childRefs = new Map(); // blob id -> [child blob ids]
618
- const jsonBlobs = []; // Clean JSON messages
619
-
620
- for (const blob of allBlobs) {
621
- blobMap.set(blob.id, blob);
622
-
623
- // Check if this is a JSON blob (actual message) or protobuf (DAG structure)
624
- if (blob.data && blob.data[0] === 0x7B) { // Starts with '{' - JSON blob
625
- try {
626
- const parsed = JSON.parse(blob.data.toString('utf8'));
627
- jsonBlobs.push({ ...blob, parsed });
628
- } catch (e) {
629
- // JSON blob parse failed
630
- }
631
- } else if (blob.data) { // Protobuf blob - extract parent references
632
- const parents = [];
633
- let i = 0;
634
-
635
- // Scan for parent references (0x0A 0x20 followed by 32-byte hash)
636
- while (i < blob.data.length - 33) {
637
- if (blob.data[i] === 0x0A && blob.data[i+1] === 0x20) {
638
- const parentHash = blob.data.slice(i+2, i+34).toString('hex');
639
- if (blobMap.has(parentHash)) {
640
- parents.push(parentHash);
641
- }
642
- i += 34;
643
- } else {
644
- i++;
645
- }
646
- }
647
-
648
- if (parents.length > 0) {
649
- parentRefs.set(blob.id, parents);
650
- // Update child references
651
- for (const parentId of parents) {
652
- if (!childRefs.has(parentId)) {
653
- childRefs.set(parentId, []);
654
- }
655
- childRefs.get(parentId).push(blob.id);
656
- }
657
- }
658
- }
659
- }
660
-
661
- // Perform topological sort to get chronological order
662
- const visited = new Set();
663
- const sorted = [];
664
-
665
- // DFS-based topological sort
666
- function visit(nodeId) {
667
- if (visited.has(nodeId)) return;
668
- visited.add(nodeId);
669
-
670
- // Visit all parents first (dependencies)
671
- const parents = parentRefs.get(nodeId) || [];
672
- for (const parentId of parents) {
673
- visit(parentId);
674
- }
675
-
676
- // Add this node after all its parents
677
- const blob = blobMap.get(nodeId);
678
- if (blob) {
679
- sorted.push(blob);
680
- }
681
- }
682
-
683
- // Start with nodes that have no parents (roots)
684
- for (const blob of allBlobs) {
685
- if (!parentRefs.has(blob.id)) {
686
- visit(blob.id);
687
- }
688
- }
689
-
690
- // Visit any remaining nodes (disconnected components)
691
- for (const blob of allBlobs) {
692
- visit(blob.id);
693
- }
694
-
695
- // Now extract JSON messages in the order they appear in the sorted DAG
696
- const messageOrder = new Map(); // JSON blob id -> order index
697
- let orderIndex = 0;
698
-
699
- for (const blob of sorted) {
700
- // Check if this blob references any JSON messages
701
- if (blob.data && blob.data[0] !== 0x7B) { // Protobuf blob
702
- // Look for JSON blob references
703
- for (const jsonBlob of jsonBlobs) {
704
- try {
705
- const jsonIdBytes = Buffer.from(jsonBlob.id, 'hex');
706
- if (blob.data.includes(jsonIdBytes)) {
707
- if (!messageOrder.has(jsonBlob.id)) {
708
- messageOrder.set(jsonBlob.id, orderIndex++);
709
- }
710
- }
711
- } catch (e) {
712
- // Skip if can't convert ID
713
- }
714
- }
715
- }
716
- }
717
-
718
- // Sort JSON blobs by their appearance order in the DAG
719
- const sortedJsonBlobs = jsonBlobs.sort((a, b) => {
720
- const orderA = messageOrder.get(a.id) ?? Number.MAX_SAFE_INTEGER;
721
- const orderB = messageOrder.get(b.id) ?? Number.MAX_SAFE_INTEGER;
722
- if (orderA !== orderB) return orderA - orderB;
723
- // Fallback to rowid if not in order map
724
- return a.rowid - b.rowid;
725
- });
726
-
727
- // Use sorted JSON blobs
728
- const blobs = sortedJsonBlobs.map((blob, idx) => ({
729
- ...blob,
730
- sequence_num: idx + 1,
731
- original_rowid: blob.rowid
732
- }));
733
-
734
- // Get metadata from meta table
735
- const metaRows = await db.all(`
736
- SELECT key, value FROM meta
737
- `);
738
-
739
- // Parse metadata
740
- let metadata = {};
741
- for (const row of metaRows) {
742
- if (row.value) {
743
- try {
744
- // Try to decode as hex-encoded JSON
745
- const hexMatch = row.value.toString().match(/^[0-9a-fA-F]+$/);
746
- if (hexMatch) {
747
- const jsonStr = Buffer.from(row.value, 'hex').toString('utf8');
748
- metadata[row.key] = JSON.parse(jsonStr);
749
- } else {
750
- metadata[row.key] = row.value.toString();
751
- }
752
- } catch (e) {
753
- metadata[row.key] = row.value.toString();
754
- }
755
- }
756
- }
757
-
758
- // Extract messages from sorted JSON blobs
759
- const messages = [];
760
- for (const blob of blobs) {
761
- try {
762
- // We already parsed JSON blobs earlier
763
- const parsed = blob.parsed;
764
-
765
- if (parsed) {
766
- // Filter out ONLY system messages at the server level
767
- // Check both direct role and nested message.role
768
- const role = parsed?.role || parsed?.message?.role;
769
- if (role === 'system') {
770
- continue; // Skip only system messages
771
- }
772
- messages.push({
773
- id: blob.id,
774
- sequence: blob.sequence_num,
775
- rowid: blob.original_rowid,
776
- content: parsed
777
- });
778
- }
779
- } catch (e) {
780
- // Skip blobs that cause errors
781
- // blob skipped
782
- }
783
- }
784
-
785
- await db.close();
786
-
787
- res.json({
788
- success: true,
789
- session: {
790
- id: sessionId,
791
- projectPath: projectPath,
792
- messages: messages,
793
- metadata: metadata,
794
- cwdId: cwdId
795
- }
796
- });
797
-
798
- } catch (error) {
799
- // session read error
800
- res.status(500).json({
801
- error: 'Failed to read Cursor session',
802
- details: 'An error occurred'
803
- });
804
- }
805
- });
806
-
807
- export default router;