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