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,26 @@
1
+ // Load environment variables from .env before other imports execute.
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { dirname } from 'path';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+
10
+ try {
11
+ const envPath = path.join(__dirname, '../.env');
12
+ const envFile = fs.readFileSync(envPath, 'utf8');
13
+ envFile.split('\n').forEach(line => {
14
+ const trimmedLine = line.trim();
15
+ if (trimmedLine && !trimmedLine.startsWith('#')) {
16
+ const [key, ...valueParts] = trimmedLine.split('=');
17
+ if (key && valueParts.length > 0 && !process.env[key]) {
18
+ process.env[key] = valueParts.join('=').trim();
19
+ }
20
+ }
21
+ });
22
+ } catch (e) {
23
+ if (!process.env.VERCEL) {
24
+ console.log('No .env file found or error reading it:', e.message);
25
+ }
26
+ }
@@ -0,0 +1,620 @@
1
+ /**
2
+ * Upfyn-Code MCP Server
3
+ *
4
+ * Exposes the app's capabilities as MCP tools and resources so any MCP-compatible
5
+ * client (ChatGPT, Claude Desktop, Cursor, etc.) can control the app.
6
+ *
7
+ * Transport: Streamable HTTP mounted at /mcp on the Express server
8
+ *
9
+ * Tools:
10
+ * - send-prompt: Send a message to Claude and get a response
11
+ * - list-projects: List all available projects
12
+ * - list-sessions: List sessions for a project
13
+ * - get-session-messages: Get messages from a session
14
+ * - get-canvas-state: Get current canvas nodes
15
+ * - add-canvas-node: Add a node to the canvas
16
+ * - clear-canvas: Clear all canvas nodes
17
+ * - create-session: Start a new Claude session
18
+ * - abort-session: Stop an active session
19
+ * - read-file: Read a file from a project
20
+ * - list-files: List files in a project directory
21
+ *
22
+ * Resources:
23
+ * - upfynai://canvas/state: Current canvas state
24
+ * - upfynai://sessions/active: Active sessions list
25
+ */
26
+
27
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
28
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
29
+ import { z } from 'zod';
30
+ import crypto from 'crypto';
31
+ import jwt from 'jsonwebtoken';
32
+ import { userDb, apiKeysDb, relayTokensDb } from './database/db.js';
33
+
34
+ const JWT_SECRET = process.env.JWT_SECRET?.trim() || (() => { throw new Error('JWT_SECRET required'); })();
35
+
36
+ // In-memory canvas state (Excalidraw elements, synced via WebSocket with browser clients)
37
+ let canvasElements = [];
38
+ const canvasListeners = new Set();
39
+
40
+ export function getCanvasElements() {
41
+ return canvasElements;
42
+ }
43
+
44
+ export function setCanvasElements(elements) {
45
+ canvasElements = elements;
46
+ notifyCanvasListeners();
47
+ }
48
+
49
+ export function addCanvasElement(element) {
50
+ canvasElements.push(element);
51
+ notifyCanvasListeners();
52
+ }
53
+
54
+ export function clearCanvas() {
55
+ canvasElements = [];
56
+ notifyCanvasListeners();
57
+ }
58
+
59
+ export function onCanvasChange(listener) {
60
+ canvasListeners.add(listener);
61
+ return () => canvasListeners.delete(listener);
62
+ }
63
+
64
+ function notifyCanvasListeners() {
65
+ for (const listener of canvasListeners) {
66
+ try { listener(canvasElements); } catch (e) { /* ignore */ }
67
+ }
68
+ }
69
+
70
+ // Helper: create an Excalidraw rectangle + text element pair
71
+ function createExcalidrawNote(text, { x = 100, y = 100, width = 300, height = 100, label = '' } = {}) {
72
+ const id = `el-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
73
+ const textId = `${id}-text`;
74
+ const fullText = label ? `${label}\n\n${text}` : text;
75
+
76
+ const rect = {
77
+ id,
78
+ type: 'rectangle',
79
+ x,
80
+ y,
81
+ width,
82
+ height,
83
+ strokeColor: '#a855f7',
84
+ backgroundColor: '#1a1a2e',
85
+ fillStyle: 'solid',
86
+ strokeWidth: 2,
87
+ roughness: 0,
88
+ opacity: 100,
89
+ angle: 0,
90
+ groupIds: [],
91
+ roundness: { type: 3 },
92
+ boundElements: [{ id: textId, type: 'text' }],
93
+ isDeleted: false,
94
+ version: 1,
95
+ versionNonce: Math.floor(Math.random() * 1e9),
96
+ };
97
+
98
+ const textEl = {
99
+ id: textId,
100
+ type: 'text',
101
+ x: x + 10,
102
+ y: y + 10,
103
+ width: width - 20,
104
+ height: height - 20,
105
+ text: fullText,
106
+ fontSize: 16,
107
+ fontFamily: 1,
108
+ textAlign: 'left',
109
+ verticalAlign: 'top',
110
+ containerId: id,
111
+ originalText: fullText,
112
+ isDeleted: false,
113
+ version: 1,
114
+ versionNonce: Math.floor(Math.random() * 1e9),
115
+ };
116
+
117
+ return [rect, textEl];
118
+ }
119
+
120
+ /**
121
+ * Create and configure the MCP server with all tools and resources
122
+ */
123
+ export function createMcpServer({ getProjects, getSessions, getSessionMessages, queryClaudeSDK, abortClaudeSDKSession, getActiveClaudeSDKSessions, connectedClients }) {
124
+ const server = new McpServer({
125
+ name: 'upfynai-code',
126
+ version: '2.0.0',
127
+ });
128
+
129
+ // ═══════════════════════════════════════════
130
+ // TOOLS
131
+ // ═══════════════════════════════════════════
132
+
133
+ // Send a prompt to Claude
134
+ server.tool(
135
+ 'send-prompt',
136
+ 'Send a message to Claude and get a streaming response. The response will appear on the canvas and in chat.',
137
+ {
138
+ prompt: z.string().describe('The message to send to Claude'),
139
+ projectPath: z.string().optional().describe('Project directory path for context'),
140
+ sessionId: z.string().optional().describe('Session ID to resume, or omit for new session'),
141
+ model: z.string().optional().describe('Model to use (e.g. claude-sonnet-4-5-20250929)'),
142
+ },
143
+ async ({ prompt, projectPath, sessionId, model }) => {
144
+ return new Promise((resolve) => {
145
+ const responseChunks = [];
146
+ let resolved = false;
147
+
148
+ // Create a mock WebSocket writer that collects the response
149
+ const mockWs = {
150
+ readyState: 1, // WebSocket.OPEN
151
+ send: (data) => {
152
+ try {
153
+ const msg = typeof data === 'string' ? JSON.parse(data) : data;
154
+ if (msg.type === 'claude-response' && msg.data?.text) {
155
+ responseChunks.push(msg.data.text);
156
+ }
157
+ if (msg.type === 'claude-complete' && !resolved) {
158
+ resolved = true;
159
+ const fullText = responseChunks.join('');
160
+ // Add to canvas as Excalidraw elements
161
+ const yOffset = canvasElements.length * 60;
162
+ const els = createExcalidrawNote(fullText, { y: 100 + yOffset, label: 'Claude' });
163
+ els.forEach(el => addCanvasElement(el));
164
+ // Broadcast canvas update to browser clients
165
+ broadcastToClients(connectedClients, {
166
+ type: 'canvas-update',
167
+ elements: canvasElements,
168
+ });
169
+ resolve({
170
+ content: [{ type: 'text', text: fullText || 'No response received.' }],
171
+ });
172
+ }
173
+ if (msg.type === 'error' && !resolved) {
174
+ resolved = true;
175
+ resolve({
176
+ content: [{ type: 'text', text: `Error: ${msg.error || 'Unknown error'}` }],
177
+ isError: true,
178
+ });
179
+ }
180
+ } catch (e) { /* ignore parse errors */ }
181
+ },
182
+ };
183
+
184
+ // Add user prompt to canvas as Excalidraw elements
185
+ const userYOffset = canvasElements.length * 60;
186
+ const userEls = createExcalidrawNote(prompt, { y: 100 + userYOffset, label: 'You (MCP)' });
187
+ userEls.forEach(el => addCanvasElement(el));
188
+
189
+ // Broadcast the user elements
190
+ broadcastToClients(connectedClients, {
191
+ type: 'canvas-update',
192
+ elements: canvasElements,
193
+ });
194
+
195
+ const options = {
196
+ projectPath: projectPath || process.cwd(),
197
+ cwd: projectPath || process.cwd(),
198
+ sessionId: sessionId || undefined,
199
+ resume: Boolean(sessionId),
200
+ model: model || undefined,
201
+ };
202
+
203
+ queryClaudeSDK(prompt, options, mockWs).catch((err) => {
204
+ if (!resolved) {
205
+ resolved = true;
206
+ resolve({
207
+ content: [{ type: 'text', text: `SDK Error: ${err.message}` }],
208
+ isError: true,
209
+ });
210
+ }
211
+ });
212
+
213
+ // Safety timeout
214
+ setTimeout(() => {
215
+ if (!resolved) {
216
+ resolved = true;
217
+ const partial = responseChunks.join('');
218
+ resolve({
219
+ content: [{ type: 'text', text: partial || 'Response timed out after 5 minutes.' }],
220
+ });
221
+ }
222
+ }, 300000);
223
+ });
224
+ }
225
+ );
226
+
227
+ // List projects
228
+ server.tool(
229
+ 'list-projects',
230
+ 'List all available projects that Claude can work on',
231
+ {},
232
+ async () => {
233
+ try {
234
+ const projects = await getProjects();
235
+ const summary = projects.map((p) => ({
236
+ name: p.name,
237
+ displayName: p.displayName || p.name,
238
+ path: p.fullPath || p.path,
239
+ sessions: (p.sessions || []).length,
240
+ }));
241
+ return {
242
+ content: [{ type: 'text', text: JSON.stringify(summary, null, 2) }],
243
+ };
244
+ } catch (err) {
245
+ return {
246
+ content: [{ type: 'text', text: `Error listing projects: ${err.message}` }],
247
+ isError: true,
248
+ };
249
+ }
250
+ }
251
+ );
252
+
253
+ // List sessions
254
+ server.tool(
255
+ 'list-sessions',
256
+ 'List sessions for a project',
257
+ {
258
+ projectName: z.string().describe('Project name to list sessions for'),
259
+ limit: z.number().optional().describe('Max sessions to return (default 10)'),
260
+ },
261
+ async ({ projectName, limit }) => {
262
+ try {
263
+ const sessions = await getSessions(projectName, limit || 10, 0);
264
+ return {
265
+ content: [{ type: 'text', text: JSON.stringify(sessions, null, 2) }],
266
+ };
267
+ } catch (err) {
268
+ return {
269
+ content: [{ type: 'text', text: `Error: ${err.message}` }],
270
+ isError: true,
271
+ };
272
+ }
273
+ }
274
+ );
275
+
276
+ // Get session messages
277
+ server.tool(
278
+ 'get-session-messages',
279
+ 'Get message history from a specific session',
280
+ {
281
+ projectName: z.string().describe('Project name'),
282
+ sessionId: z.string().describe('Session ID'),
283
+ limit: z.number().optional().describe('Max messages (default 50)'),
284
+ },
285
+ async ({ projectName, sessionId, limit }) => {
286
+ try {
287
+ const messages = await getSessionMessages(projectName, sessionId, limit || 50, 0);
288
+ return {
289
+ content: [{ type: 'text', text: JSON.stringify(messages, null, 2) }],
290
+ };
291
+ } catch (err) {
292
+ return {
293
+ content: [{ type: 'text', text: `Error: ${err.message}` }],
294
+ isError: true,
295
+ };
296
+ }
297
+ }
298
+ );
299
+
300
+ // Get canvas state
301
+ server.tool(
302
+ 'get-canvas-state',
303
+ 'Get the current Upfyn-Canvas state including all elements',
304
+ {},
305
+ async () => {
306
+ return {
307
+ content: [{
308
+ type: 'text',
309
+ text: JSON.stringify({
310
+ elementCount: canvasElements.length,
311
+ elements: canvasElements,
312
+ }, null, 2),
313
+ }],
314
+ };
315
+ }
316
+ );
317
+
318
+ // Add canvas node (creates Upfyn-Canvas rectangle + text)
319
+ server.tool(
320
+ 'add-canvas-node',
321
+ 'Add a visual note to the Upfyn-Canvas whiteboard (rectangle with text)',
322
+ {
323
+ text: z.string().describe('Text content for the note'),
324
+ label: z.string().optional().describe('Label for the note (default: "MCP Note")'),
325
+ x: z.number().optional().describe('X position (default: 100)'),
326
+ y: z.number().optional().describe('Y position (default: auto)'),
327
+ },
328
+ async ({ text, label, x, y }) => {
329
+ const yPos = y ?? (100 + canvasElements.length * 60);
330
+ const els = createExcalidrawNote(text, { x: x ?? 100, y: yPos, label: label || 'MCP Note' });
331
+ els.forEach(el => addCanvasElement(el));
332
+ broadcastToClients(connectedClients, {
333
+ type: 'canvas-update',
334
+ elements: canvasElements,
335
+ });
336
+ return {
337
+ content: [{ type: 'text', text: `Note added to canvas: ${els[0].id}` }],
338
+ };
339
+ }
340
+ );
341
+
342
+ // Clear canvas
343
+ server.tool(
344
+ 'clear-canvas',
345
+ 'Clear all elements from the Upfyn-Canvas whiteboard',
346
+ {},
347
+ async () => {
348
+ clearCanvas();
349
+ broadcastToClients(connectedClients, {
350
+ type: 'canvas-update',
351
+ elements: [],
352
+ });
353
+ return {
354
+ content: [{ type: 'text', text: 'Canvas cleared.' }],
355
+ };
356
+ }
357
+ );
358
+
359
+ // Update full canvas scene
360
+ server.tool(
361
+ 'update-canvas-scene',
362
+ 'Replace the entire Upfyn-Canvas with new elements',
363
+ {
364
+ elements: z.array(z.object({}).passthrough()).describe('Array of canvas elements'),
365
+ },
366
+ async ({ elements }) => {
367
+ setCanvasElements(elements);
368
+ broadcastToClients(connectedClients, {
369
+ type: 'canvas-update',
370
+ elements: canvasElements,
371
+ });
372
+ return {
373
+ content: [{ type: 'text', text: `Canvas updated with ${elements.length} elements.` }],
374
+ };
375
+ }
376
+ );
377
+
378
+ // Get active sessions
379
+ server.tool(
380
+ 'get-active-sessions',
381
+ 'Get list of currently active Claude sessions',
382
+ {},
383
+ async () => {
384
+ try {
385
+ const sessions = getActiveClaudeSDKSessions();
386
+ return {
387
+ content: [{ type: 'text', text: JSON.stringify(sessions, null, 2) }],
388
+ };
389
+ } catch (err) {
390
+ return {
391
+ content: [{ type: 'text', text: `Error: ${err.message}` }],
392
+ isError: true,
393
+ };
394
+ }
395
+ }
396
+ );
397
+
398
+ // Abort session
399
+ server.tool(
400
+ 'abort-session',
401
+ 'Stop an active Claude session',
402
+ {
403
+ sessionId: z.string().describe('Session ID to abort'),
404
+ },
405
+ async ({ sessionId }) => {
406
+ try {
407
+ const result = await abortClaudeSDKSession(sessionId);
408
+ return {
409
+ content: [{ type: 'text', text: result ? `Session ${sessionId} aborted.` : `Session ${sessionId} not found or already stopped.` }],
410
+ };
411
+ } catch (err) {
412
+ return {
413
+ content: [{ type: 'text', text: `Error: ${err.message}` }],
414
+ isError: true,
415
+ };
416
+ }
417
+ }
418
+ );
419
+
420
+ // ═══════════════════════════════════════════
421
+ // RESOURCES
422
+ // ═══════════════════════════════════════════
423
+
424
+ server.resource(
425
+ 'canvas-state',
426
+ 'upfynai://canvas/state',
427
+ {
428
+ description: 'Current Upfyn-Canvas state with all elements',
429
+ mimeType: 'application/json',
430
+ },
431
+ async (uri) => ({
432
+ contents: [{
433
+ uri: uri.href,
434
+ text: JSON.stringify({ elementCount: canvasElements.length, elements: canvasElements }, null, 2),
435
+ }],
436
+ })
437
+ );
438
+
439
+ server.resource(
440
+ 'active-sessions',
441
+ 'upfynai://sessions/active',
442
+ {
443
+ description: 'Currently active Claude sessions',
444
+ mimeType: 'application/json',
445
+ },
446
+ async (uri) => ({
447
+ contents: [{
448
+ uri: uri.href,
449
+ text: JSON.stringify(getActiveClaudeSDKSessions(), null, 2),
450
+ }],
451
+ })
452
+ );
453
+
454
+ return server;
455
+ }
456
+
457
+ /**
458
+ * Mount the MCP server on an Express app at /mcp
459
+ */
460
+ export async function mountMcpServer(app, mcpServer, mcpServerFactory) {
461
+ // On Vercel serverless, in-memory session state is lost between invocations.
462
+ // Use per-request stateless MCP servers on Vercel; session-based on local.
463
+ const isServerless = !!process.env.VERCEL;
464
+ const transports = new Map();
465
+
466
+ // MCP authentication middleware — cookie → Bearer → API key → query param
467
+ const authenticateMcp = async (req, res, next) => {
468
+ // 1. Try httpOnly cookie (browser sessions)
469
+ if (req.cookies?.session) {
470
+ try {
471
+ const decoded = jwt.verify(req.cookies.session, JWT_SECRET);
472
+ const user = await userDb.getUserById(decoded.userId);
473
+ if (user) { req.user = user; return next(); }
474
+ } catch (e) { /* fall through */ }
475
+ }
476
+
477
+ // 2. Try Bearer token — supports JWT, relay token (upfyn_/rt_), or API key (up-cli-)
478
+ const authHeader = req.headers['authorization'];
479
+ const token = authHeader && authHeader.split(' ')[1];
480
+ if (token) {
481
+ // 2a. Relay token (upfyn_xxx or legacy rt_xxx) — same token used for CLI connect
482
+ if (token.startsWith('upfyn_') || token.startsWith('rt_')) {
483
+ try {
484
+ const tokenData = await relayTokensDb.validateToken(token);
485
+ if (tokenData) {
486
+ const user = await userDb.getUserById(tokenData.user_id);
487
+ if (user) { req.user = user; return next(); }
488
+ }
489
+ } catch (e) { /* fall through */ }
490
+ }
491
+ // 2b. API key (up-cli-xxx)
492
+ if (token.startsWith('up-cli-')) {
493
+ try {
494
+ const user = await apiKeysDb.validateApiKey(token);
495
+ if (user) { req.user = user; return next(); }
496
+ } catch (e) { /* fall through */ }
497
+ }
498
+ // 2c. JWT token
499
+ try {
500
+ const decoded = jwt.verify(token, JWT_SECRET);
501
+ const user = await userDb.getUserById(decoded.userId);
502
+ if (user) { req.user = user; return next(); }
503
+ } catch (e) { /* fall through */ }
504
+ }
505
+
506
+ // 3. Try API key header (MCP clients: ChatGPT, Claude Desktop, Cursor, etc.)
507
+ const apiKey = req.headers['x-api-key'];
508
+ if (apiKey) {
509
+ try {
510
+ const user = await apiKeysDb.validateApiKey(apiKey);
511
+ if (user) { req.user = user; return next(); }
512
+ } catch (e) { /* ignore */ }
513
+ }
514
+
515
+ // 4. Try query param token (SSE EventSource fallback)
516
+ if (req.query.token) {
517
+ try {
518
+ const decoded = jwt.verify(req.query.token, JWT_SECRET);
519
+ const user = await userDb.getUserById(decoded.userId);
520
+ if (user) { req.user = user; return next(); }
521
+ } catch (e) { /* ignore */ }
522
+ }
523
+
524
+ res.status(401).json({ error: 'Authentication required. Use Authorization: Bearer <jwt>, x-api-key header, or up-cli- API key.' });
525
+ };
526
+
527
+ // Handle MCP requests at /mcp endpoint
528
+ app.post('/mcp', authenticateMcp, async (req, res) => {
529
+ try {
530
+ const sessionId = req.headers['mcp-session-id'];
531
+ let transport;
532
+
533
+ if (!isServerless && sessionId && transports.has(sessionId)) {
534
+ // Local: reuse existing session transport
535
+ transport = transports.get(sessionId);
536
+ } else {
537
+ // Create a fresh MCP server + transport per request on serverless,
538
+ // or a new session on local
539
+ const server = isServerless && mcpServerFactory ? mcpServerFactory() : mcpServer;
540
+
541
+ // On serverless: no sessionIdGenerator → disables session validation
542
+ // entirely, so requests don't need the initialize handshake.
543
+ // On local: sessionIdGenerator enables session tracking.
544
+ transport = new StreamableHTTPServerTransport({
545
+ sessionIdGenerator: isServerless ? undefined : (() => crypto.randomUUID()),
546
+ stateless: isServerless,
547
+ });
548
+
549
+ transport.onclose = () => {
550
+ const sid = transport.sessionId;
551
+ if (sid) transports.delete(sid);
552
+ };
553
+
554
+ await server.connect(transport);
555
+
556
+ if (!isServerless && transport.sessionId) {
557
+ transports.set(transport.sessionId, transport);
558
+ }
559
+ }
560
+
561
+ // Express already consumed the raw body stream, so we must pass the
562
+ // parsed body as the 3rd arg to avoid "Parse error: Invalid JSON"
563
+ await transport.handleRequest(req, res, req.body);
564
+ } catch (err) {
565
+ console.error('[MCP] Error handling POST:', err.message);
566
+ if (!res.headersSent) {
567
+ res.status(500).json({ error: 'MCP server error', details: err.message });
568
+ }
569
+ }
570
+ });
571
+
572
+ // SSE stream for server-initiated messages (local only — serverless is stateless)
573
+ app.get('/mcp', authenticateMcp, async (req, res) => {
574
+ if (isServerless) {
575
+ return res.status(405).json({ error: 'SSE not supported on serverless. Use stateless POST requests.' });
576
+ }
577
+ const sessionId = req.headers['mcp-session-id'];
578
+ if (!sessionId || !transports.has(sessionId)) {
579
+ res.status(400).json({ error: 'Invalid or missing session ID' });
580
+ return;
581
+ }
582
+ const transport = transports.get(sessionId);
583
+ await transport.handleRequest(req, res);
584
+ });
585
+
586
+ // Session termination
587
+ app.delete('/mcp', authenticateMcp, async (req, res) => {
588
+ if (isServerless) {
589
+ return res.json({ ok: true });
590
+ }
591
+ const sessionId = req.headers['mcp-session-id'];
592
+ if (sessionId && transports.has(sessionId)) {
593
+ const transport = transports.get(sessionId);
594
+ await transport.handleRequest(req, res);
595
+ transports.delete(sessionId);
596
+ } else {
597
+ res.status(404).json({ error: 'Session not found' });
598
+ }
599
+ });
600
+
601
+ console.log(`${c_info('[MCP]')} MCP server mounted at /mcp (${isServerless ? 'stateless/serverless' : 'session-based'})`);
602
+ console.log(`${c_info('[MCP]')} Tools: send-prompt, list-projects, list-sessions, get-session-messages, get-canvas-state, add-canvas-node, clear-canvas, update-canvas-scene, get-active-sessions, abort-session`);
603
+ }
604
+
605
+ // Simple color helper (avoids importing from index.js)
606
+ function c_info(text) {
607
+ return `\x1b[36m${text}\x1b[0m`;
608
+ }
609
+
610
+ function broadcastToClients(clients, message) {
611
+ if (!clients || clients.size === 0) return;
612
+ const data = JSON.stringify(message);
613
+ for (const client of clients) {
614
+ try {
615
+ if (client.readyState === 1) {
616
+ client.send(data);
617
+ }
618
+ } catch (e) { /* ignore */ }
619
+ }
620
+ }