opencami 1.0.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 (337) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +111 -0
  3. package/bin/opencami.js +155 -0
  4. package/dist/client/apple-touch-icon-180x180.png +0 -0
  5. package/dist/client/assets/_sessionKey-B-MBYHgD.js +95 -0
  6. package/dist/client/assets/abap-BdImnpbu.js +1 -0
  7. package/dist/client/assets/actionscript-3-CfeIJUat.js +1 -0
  8. package/dist/client/assets/ada-bCR0ucgS.js +1 -0
  9. package/dist/client/assets/andromeeda-C-Jbm3Hp.js +1 -0
  10. package/dist/client/assets/angular-html-CU67Zn6k.js +1 -0
  11. package/dist/client/assets/angular-ts-BwZT4LLn.js +1 -0
  12. package/dist/client/assets/apache-Pmp26Uib.js +1 -0
  13. package/dist/client/assets/apex-D8_7TLub.js +1 -0
  14. package/dist/client/assets/apl-dKokRX4l.js +1 -0
  15. package/dist/client/assets/applescript-Co6uUVPk.js +1 -0
  16. package/dist/client/assets/ara-BRHolxvo.js +1 -0
  17. package/dist/client/assets/asciidoc-Dv7Oe6Be.js +1 -0
  18. package/dist/client/assets/asm-D_Q5rh1f.js +1 -0
  19. package/dist/client/assets/astro-CbQHKStN.js +1 -0
  20. package/dist/client/assets/aurora-x-D-2ljcwZ.js +1 -0
  21. package/dist/client/assets/awk-DMzUqQB5.js +1 -0
  22. package/dist/client/assets/ayu-dark-CmMr59Fi.js +1 -0
  23. package/dist/client/assets/ballerina-BFfxhgS-.js +1 -0
  24. package/dist/client/assets/bat-BkioyH1T.js +1 -0
  25. package/dist/client/assets/beancount-k_qm7-4y.js +1 -0
  26. package/dist/client/assets/berry-uYugtg8r.js +1 -0
  27. package/dist/client/assets/bibtex-CHM0blh-.js +1 -0
  28. package/dist/client/assets/bicep-Bmn6On1c.js +1 -0
  29. package/dist/client/assets/blade-D4QpJJKB.js +1 -0
  30. package/dist/client/assets/bsl-BO_Y6i37.js +1 -0
  31. package/dist/client/assets/button-D_9OBT_f.js +1 -0
  32. package/dist/client/assets/c-BIGW1oBm.js +1 -0
  33. package/dist/client/assets/c3-VCDPK7BO.js +1 -0
  34. package/dist/client/assets/cadence-Bv_4Rxtq.js +1 -0
  35. package/dist/client/assets/cairo-KRGpt6FW.js +1 -0
  36. package/dist/client/assets/catppuccin-frappe-DFWUc33u.js +1 -0
  37. package/dist/client/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
  38. package/dist/client/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
  39. package/dist/client/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
  40. package/dist/client/assets/clarity-D53aC0YG.js +1 -0
  41. package/dist/client/assets/clojure-P80f7IUj.js +1 -0
  42. package/dist/client/assets/cmake-D1j8_8rp.js +1 -0
  43. package/dist/client/assets/cobol-nwyudZeR.js +1 -0
  44. package/dist/client/assets/codeowners-Bp6g37R7.js +1 -0
  45. package/dist/client/assets/codeql-DsOJ9woJ.js +1 -0
  46. package/dist/client/assets/coffee-Ch7k5sss.js +1 -0
  47. package/dist/client/assets/common-lisp-Cg-RD9OK.js +1 -0
  48. package/dist/client/assets/connect-BRasuRbB.js +2 -0
  49. package/dist/client/assets/coq-DkFqJrB1.js +1 -0
  50. package/dist/client/assets/cpp-CofmeUqb.js +1 -0
  51. package/dist/client/assets/crystal-tKQVLTB8.js +1 -0
  52. package/dist/client/assets/csharp-K5feNrxe.js +1 -0
  53. package/dist/client/assets/css-DPfMkruS.js +1 -0
  54. package/dist/client/assets/csv-fuZLfV_i.js +1 -0
  55. package/dist/client/assets/cue-D82EKSYY.js +1 -0
  56. package/dist/client/assets/cypher-COkxafJQ.js +1 -0
  57. package/dist/client/assets/d-85-TOEBH.js +1 -0
  58. package/dist/client/assets/dark-plus-C3mMm8J8.js +1 -0
  59. package/dist/client/assets/dart-CF10PKvl.js +1 -0
  60. package/dist/client/assets/dax-CEL-wOlO.js +1 -0
  61. package/dist/client/assets/desktop-BmXAJ9_W.js +1 -0
  62. package/dist/client/assets/diff-D97Zzqfu.js +1 -0
  63. package/dist/client/assets/docker-BcOcwvcX.js +1 -0
  64. package/dist/client/assets/dotenv-Da5cRb03.js +1 -0
  65. package/dist/client/assets/dracula-BzJJZx-M.js +1 -0
  66. package/dist/client/assets/dracula-soft-BXkSAIEj.js +1 -0
  67. package/dist/client/assets/dream-maker-BtqSS_iP.js +1 -0
  68. package/dist/client/assets/edge-BkV0erSs.js +1 -0
  69. package/dist/client/assets/elixir-CDX3lj18.js +1 -0
  70. package/dist/client/assets/elm-DbKCFpqz.js +1 -0
  71. package/dist/client/assets/emacs-lisp-C9XAeP06.js +1 -0
  72. package/dist/client/assets/erb-BOJIQeun.js +1 -0
  73. package/dist/client/assets/erlang-DsQrWhSR.js +1 -0
  74. package/dist/client/assets/everforest-dark-BgDCqdQA.js +1 -0
  75. package/dist/client/assets/everforest-light-C8M2exoo.js +1 -0
  76. package/dist/client/assets/fennel-BYunw83y.js +1 -0
  77. package/dist/client/assets/file-explorer-screen-Daf4rIq9.js +1 -0
  78. package/dist/client/assets/files-ByeIMLfw.js +2 -0
  79. package/dist/client/assets/fish-BvzEVeQv.js +1 -0
  80. package/dist/client/assets/fluent-C4IJs8-o.js +1 -0
  81. package/dist/client/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
  82. package/dist/client/assets/fortran-free-form-BxgE0vQu.js +1 -0
  83. package/dist/client/assets/fsharp-CXgrBDvD.js +1 -0
  84. package/dist/client/assets/gdresource-B7Tvp0Sc.js +1 -0
  85. package/dist/client/assets/gdscript-DTMYz4Jt.js +1 -0
  86. package/dist/client/assets/gdshader-DkwncUOv.js +1 -0
  87. package/dist/client/assets/genie-D0YGMca9.js +1 -0
  88. package/dist/client/assets/gherkin-DyxjwDmM.js +1 -0
  89. package/dist/client/assets/git-commit-F4YmCXRG.js +1 -0
  90. package/dist/client/assets/git-rebase-r7XF79zn.js +1 -0
  91. package/dist/client/assets/github-dark-DHJKELXO.js +1 -0
  92. package/dist/client/assets/github-dark-default-Cuk6v7N8.js +1 -0
  93. package/dist/client/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  94. package/dist/client/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  95. package/dist/client/assets/github-light-DAi9KRSo.js +1 -0
  96. package/dist/client/assets/github-light-default-D7oLnXFd.js +1 -0
  97. package/dist/client/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  98. package/dist/client/assets/gleam-BspZqrRM.js +1 -0
  99. package/dist/client/assets/glimmer-js-Rg0-pVw9.js +1 -0
  100. package/dist/client/assets/glimmer-ts-U6CK756n.js +1 -0
  101. package/dist/client/assets/glsl-DplSGwfg.js +1 -0
  102. package/dist/client/assets/gn-n2N0HUVH.js +1 -0
  103. package/dist/client/assets/gnuplot-DdkO51Og.js +1 -0
  104. package/dist/client/assets/go-Dn2_MT6a.js +1 -0
  105. package/dist/client/assets/graphql-ChdNCCLP.js +1 -0
  106. package/dist/client/assets/groovy-gcz8RCvz.js +1 -0
  107. package/dist/client/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  108. package/dist/client/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  109. package/dist/client/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  110. package/dist/client/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  111. package/dist/client/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  112. package/dist/client/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  113. package/dist/client/assets/hack-CaT9iCJl.js +1 -0
  114. package/dist/client/assets/haml-B8DHNrY2.js +1 -0
  115. package/dist/client/assets/handlebars-BL8al0AC.js +1 -0
  116. package/dist/client/assets/haskell-Df6bDoY_.js +1 -0
  117. package/dist/client/assets/haxe-CzTSHFRz.js +1 -0
  118. package/dist/client/assets/hcl-BWvSN4gD.js +1 -0
  119. package/dist/client/assets/hjson-D5-asLiD.js +1 -0
  120. package/dist/client/assets/hlsl-D3lLCCz7.js +1 -0
  121. package/dist/client/assets/houston-DnULxvSX.js +1 -0
  122. package/dist/client/assets/html-GMplVEZG.js +1 -0
  123. package/dist/client/assets/html-derivative-BFtXZ54Q.js +1 -0
  124. package/dist/client/assets/http-jrhK8wxY.js +1 -0
  125. package/dist/client/assets/hurl-irOxFIW8.js +1 -0
  126. package/dist/client/assets/hxml-Bvhsp5Yf.js +1 -0
  127. package/dist/client/assets/hy-DFXneXwc.js +1 -0
  128. package/dist/client/assets/imba-DGztddWO.js +1 -0
  129. package/dist/client/assets/index-ByUDBI-n.js +14 -0
  130. package/dist/client/assets/index-DHGnKfAU.js +1 -0
  131. package/dist/client/assets/ini-BEwlwnbL.js +1 -0
  132. package/dist/client/assets/java-CylS5w8V.js +1 -0
  133. package/dist/client/assets/javascript-wDzz0qaB.js +1 -0
  134. package/dist/client/assets/jinja-4LBKfQ-Z.js +1 -0
  135. package/dist/client/assets/jison-wvAkD_A8.js +1 -0
  136. package/dist/client/assets/json-Cp-IABpG.js +1 -0
  137. package/dist/client/assets/json5-C9tS-k6U.js +1 -0
  138. package/dist/client/assets/jsonc-Des-eS-w.js +1 -0
  139. package/dist/client/assets/jsonl-DcaNXYhu.js +1 -0
  140. package/dist/client/assets/jsonnet-DFQXde-d.js +1 -0
  141. package/dist/client/assets/jssm-C2t-YnRu.js +1 -0
  142. package/dist/client/assets/jsx-g9-lgVsj.js +1 -0
  143. package/dist/client/assets/julia-CxzCAyBv.js +1 -0
  144. package/dist/client/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  145. package/dist/client/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  146. package/dist/client/assets/kanagawa-wave-DWedfzmr.js +1 -0
  147. package/dist/client/assets/kdl-DV7GczEv.js +1 -0
  148. package/dist/client/assets/keyboard-shortcuts-dialog-agsWJ36q.js +1 -0
  149. package/dist/client/assets/kotlin-BdnUsdx6.js +1 -0
  150. package/dist/client/assets/kusto-DZf3V79B.js +1 -0
  151. package/dist/client/assets/laserwave-DUszq2jm.js +1 -0
  152. package/dist/client/assets/latex-B4uzh10-.js +1 -0
  153. package/dist/client/assets/lean-BZvkOJ9d.js +1 -0
  154. package/dist/client/assets/less-B1dDrJ26.js +1 -0
  155. package/dist/client/assets/light-plus-B7mTdjB0.js +1 -0
  156. package/dist/client/assets/liquid-DYVedYrR.js +1 -0
  157. package/dist/client/assets/llvm-BtvRca6l.js +1 -0
  158. package/dist/client/assets/log-2UxHyX5q.js +1 -0
  159. package/dist/client/assets/logo-BtOb2qkB.js +1 -0
  160. package/dist/client/assets/lua-BbnMAYS6.js +1 -0
  161. package/dist/client/assets/luau-C-HG3fhB.js +1 -0
  162. package/dist/client/assets/main-BAHT5yqU.js +81 -0
  163. package/dist/client/assets/make-CHLpvVh8.js +1 -0
  164. package/dist/client/assets/markdown-Cvjx9yec.js +1 -0
  165. package/dist/client/assets/marko-DZsq8hO1.js +1 -0
  166. package/dist/client/assets/material-theme-D5KoaKCx.js +1 -0
  167. package/dist/client/assets/material-theme-darker-BfHTSMKl.js +1 -0
  168. package/dist/client/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  169. package/dist/client/assets/material-theme-ocean-CyktbL80.js +1 -0
  170. package/dist/client/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  171. package/dist/client/assets/matlab-D7o27uSR.js +1 -0
  172. package/dist/client/assets/mdc-DUICxH0z.js +1 -0
  173. package/dist/client/assets/mdx-Cmh6b_Ma.js +1 -0
  174. package/dist/client/assets/menu-BhVaz8Ly.js +20 -0
  175. package/dist/client/assets/mermaid-mWjccvbQ.js +1 -0
  176. package/dist/client/assets/min-dark-CafNBF8u.js +1 -0
  177. package/dist/client/assets/min-light-CTRr51gU.js +1 -0
  178. package/dist/client/assets/mipsasm-CKIfxQSi.js +1 -0
  179. package/dist/client/assets/mojo-B93PlW-d.js +1 -0
  180. package/dist/client/assets/monokai-D4h5O-jR.js +1 -0
  181. package/dist/client/assets/moonbit-Ba13S78F.js +1 -0
  182. package/dist/client/assets/move-Bu9oaDYs.js +1 -0
  183. package/dist/client/assets/narrat-DRg8JJMk.js +1 -0
  184. package/dist/client/assets/new-DLlBm66g.js +1 -0
  185. package/dist/client/assets/nextflow-BrzmwbiE.js +1 -0
  186. package/dist/client/assets/nginx-DknmC5AR.js +1 -0
  187. package/dist/client/assets/night-owl-C39BiMTA.js +1 -0
  188. package/dist/client/assets/nim-CVrawwO9.js +1 -0
  189. package/dist/client/assets/nix-CwoSXNpI.js +1 -0
  190. package/dist/client/assets/nord-Ddv68eIx.js +1 -0
  191. package/dist/client/assets/nushell-C-sUppwS.js +1 -0
  192. package/dist/client/assets/objective-c-DXmwc3jG.js +1 -0
  193. package/dist/client/assets/objective-cpp-CLxacb5B.js +1 -0
  194. package/dist/client/assets/ocaml-C0hk2d4L.js +1 -0
  195. package/dist/client/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  196. package/dist/client/assets/one-light-PoHY5YXO.js +1 -0
  197. package/dist/client/assets/openscad-C4EeE6gA.js +1 -0
  198. package/dist/client/assets/pascal-D93ZcfNL.js +1 -0
  199. package/dist/client/assets/perl-C0TMdlhV.js +1 -0
  200. package/dist/client/assets/php-CDn_0X-4.js +1 -0
  201. package/dist/client/assets/pkl-u5AG7uiY.js +1 -0
  202. package/dist/client/assets/plastic-3e1v2bzS.js +1 -0
  203. package/dist/client/assets/plsql-ChMvpjG-.js +1 -0
  204. package/dist/client/assets/po-BTJTHyun.js +1 -0
  205. package/dist/client/assets/poimandres-CS3Unz2-.js +1 -0
  206. package/dist/client/assets/polar-C0HS_06l.js +1 -0
  207. package/dist/client/assets/postcss-CXtECtnM.js +1 -0
  208. package/dist/client/assets/powerquery-CEu0bR-o.js +1 -0
  209. package/dist/client/assets/powershell-Dpen1YoG.js +1 -0
  210. package/dist/client/assets/prisma-Dd19v3D-.js +1 -0
  211. package/dist/client/assets/prolog-CbFg5uaA.js +1 -0
  212. package/dist/client/assets/proto-C7zT0LnQ.js +1 -0
  213. package/dist/client/assets/pug-CGlum2m_.js +1 -0
  214. package/dist/client/assets/puppet-BMWR74SV.js +1 -0
  215. package/dist/client/assets/purescript-CklMAg4u.js +1 -0
  216. package/dist/client/assets/python-B6aJPvgy.js +1 -0
  217. package/dist/client/assets/qml-3beO22l8.js +1 -0
  218. package/dist/client/assets/qmldir-C8lEn-DE.js +1 -0
  219. package/dist/client/assets/qss-IeuSbFQv.js +1 -0
  220. package/dist/client/assets/r-Dspwwk_N.js +1 -0
  221. package/dist/client/assets/racket-BqYA7rlc.js +1 -0
  222. package/dist/client/assets/raku-DXvB9xmW.js +1 -0
  223. package/dist/client/assets/razor-C1TweQQi.js +1 -0
  224. package/dist/client/assets/red-bN70gL4F.js +1 -0
  225. package/dist/client/assets/reg-C-SQnVFl.js +1 -0
  226. package/dist/client/assets/regexp-CDVJQ6XC.js +1 -0
  227. package/dist/client/assets/rel-C3B-1QV4.js +1 -0
  228. package/dist/client/assets/riscv-BM1_JUlF.js +1 -0
  229. package/dist/client/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
  230. package/dist/client/assets/rose-pine-moon-D4_iv3hh.js +1 -0
  231. package/dist/client/assets/rose-pine-qdsjHGoJ.js +1 -0
  232. package/dist/client/assets/rosmsg-BJDFO7_C.js +1 -0
  233. package/dist/client/assets/rst-B0xPkSld.js +1 -0
  234. package/dist/client/assets/ruby-BvKwtOVI.js +1 -0
  235. package/dist/client/assets/rust-B1yitclQ.js +1 -0
  236. package/dist/client/assets/sas-cz2c8ADy.js +1 -0
  237. package/dist/client/assets/sass-Cj5Yp3dK.js +1 -0
  238. package/dist/client/assets/scala-C151Ov-r.js +1 -0
  239. package/dist/client/assets/scheme-C98Dy4si.js +1 -0
  240. package/dist/client/assets/scss-OYdSNvt2.js +1 -0
  241. package/dist/client/assets/sdbl-DVxCFoDh.js +1 -0
  242. package/dist/client/assets/search-dialog-CHwnOyPS.js +1 -0
  243. package/dist/client/assets/session-export-dialog-uOlDUzgX.js +1 -0
  244. package/dist/client/assets/settings-dialog-D0aYDkAM.js +1 -0
  245. package/dist/client/assets/shaderlab-Dg9Lc6iA.js +1 -0
  246. package/dist/client/assets/shellscript-Yzrsuije.js +1 -0
  247. package/dist/client/assets/shellsession-BADoaaVG.js +1 -0
  248. package/dist/client/assets/slack-dark-BthQWCQV.js +1 -0
  249. package/dist/client/assets/slack-ochin-DqwNpetd.js +1 -0
  250. package/dist/client/assets/smalltalk-BERRCDM3.js +1 -0
  251. package/dist/client/assets/snazzy-light-Bw305WKR.js +1 -0
  252. package/dist/client/assets/solarized-dark-DXbdFlpD.js +1 -0
  253. package/dist/client/assets/solarized-light-L9t79GZl.js +1 -0
  254. package/dist/client/assets/solidity-rGO070M0.js +1 -0
  255. package/dist/client/assets/soy-Brmx7dQM.js +1 -0
  256. package/dist/client/assets/sparql-rVzFXLq3.js +1 -0
  257. package/dist/client/assets/splunk-BtCnVYZw.js +1 -0
  258. package/dist/client/assets/sql-BLtJtn59.js +1 -0
  259. package/dist/client/assets/ssh-config-_ykCGR6B.js +1 -0
  260. package/dist/client/assets/stata-BH5u7GGu.js +1 -0
  261. package/dist/client/assets/styles-7aVSlb6l.css +1 -0
  262. package/dist/client/assets/stylus-BEDo0Tqx.js +1 -0
  263. package/dist/client/assets/svelte-zxCyuUbr.js +1 -0
  264. package/dist/client/assets/swift-Dg5xB15N.js +1 -0
  265. package/dist/client/assets/synthwave-84-CbfX1IO0.js +1 -0
  266. package/dist/client/assets/system-verilog-CnnmHF94.js +1 -0
  267. package/dist/client/assets/systemd-4A_iFExJ.js +1 -0
  268. package/dist/client/assets/talonscript-CkByrt1z.js +1 -0
  269. package/dist/client/assets/tasl-QIJgUcNo.js +1 -0
  270. package/dist/client/assets/tcl-dwOrl1Do.js +1 -0
  271. package/dist/client/assets/templ-W15q3VgB.js +1 -0
  272. package/dist/client/assets/terraform-BETggiCN.js +1 -0
  273. package/dist/client/assets/tex-CvyZ59Mk.js +1 -0
  274. package/dist/client/assets/tokyo-night-hegEt444.js +1 -0
  275. package/dist/client/assets/toml-vGWfd6FD.js +1 -0
  276. package/dist/client/assets/ts-tags-zn1MmPIZ.js +1 -0
  277. package/dist/client/assets/tsv-B_m7g4N7.js +1 -0
  278. package/dist/client/assets/tsx-COt5Ahok.js +1 -0
  279. package/dist/client/assets/turtle-BsS91CYL.js +1 -0
  280. package/dist/client/assets/twig-CO9l9SDP.js +1 -0
  281. package/dist/client/assets/typescript-BPQ3VLAy.js +1 -0
  282. package/dist/client/assets/typespec-BGHnOYBU.js +1 -0
  283. package/dist/client/assets/typst-DHCkPAjA.js +1 -0
  284. package/dist/client/assets/v-BcVCzyr7.js +1 -0
  285. package/dist/client/assets/vala-CsfeWuGM.js +1 -0
  286. package/dist/client/assets/vb-D17OF-Vu.js +1 -0
  287. package/dist/client/assets/verilog-BQ8w6xss.js +1 -0
  288. package/dist/client/assets/vesper-DU1UobuO.js +1 -0
  289. package/dist/client/assets/vhdl-CeAyd5Ju.js +1 -0
  290. package/dist/client/assets/viml-CJc9bBzg.js +1 -0
  291. package/dist/client/assets/vitesse-black-Bkuqu6BP.js +1 -0
  292. package/dist/client/assets/vitesse-dark-D0r3Knsf.js +1 -0
  293. package/dist/client/assets/vitesse-light-CVO1_9PV.js +1 -0
  294. package/dist/client/assets/vue-DN_0RTcg.js +1 -0
  295. package/dist/client/assets/vue-html-AaS7Mt5G.js +1 -0
  296. package/dist/client/assets/vue-vine-CQOfvN7w.js +1 -0
  297. package/dist/client/assets/vyper-CDx5xZoG.js +1 -0
  298. package/dist/client/assets/wasm-CG6Dc4jp.js +1 -0
  299. package/dist/client/assets/wasm-MzD3tlZU.js +1 -0
  300. package/dist/client/assets/wenyan-BV7otONQ.js +1 -0
  301. package/dist/client/assets/wgsl-Dx-B1_4e.js +1 -0
  302. package/dist/client/assets/wikitext-BhOHFoWU.js +1 -0
  303. package/dist/client/assets/wit-5i3qLPDT.js +1 -0
  304. package/dist/client/assets/wolfram-lXgVvXCa.js +1 -0
  305. package/dist/client/assets/xml-sdJ4AIDG.js +1 -0
  306. package/dist/client/assets/xsl-CtQFsRM5.js +1 -0
  307. package/dist/client/assets/yaml-Buea-lGh.js +1 -0
  308. package/dist/client/assets/zenscript-DVFEvuxE.js +1 -0
  309. package/dist/client/assets/zig-VOosw3JB.js +1 -0
  310. package/dist/client/cover.jpg +0 -0
  311. package/dist/client/cover.webp +0 -0
  312. package/dist/client/favicon.svg +4 -0
  313. package/dist/client/manifest.json +40 -0
  314. package/dist/client/pwa-192x192.png +0 -0
  315. package/dist/client/pwa-512x512.png +0 -0
  316. package/dist/client/pwa-maskable-512x512.png +0 -0
  317. package/dist/client/robots.txt +3 -0
  318. package/dist/client/screenshot-file-explorer.png +0 -0
  319. package/dist/client/sw.js +165 -0
  320. package/dist/server/assets/_sessionKey-qlAPF_Ft.js +6130 -0
  321. package/dist/server/assets/_tanstack-start-manifest_v-El8F-kd-.js +4 -0
  322. package/dist/server/assets/button-DtQ3rV1m.js +53 -0
  323. package/dist/server/assets/connect-BWI_6rCm.js +80 -0
  324. package/dist/server/assets/file-explorer-screen-DJXPEG_J.js +2450 -0
  325. package/dist/server/assets/files-CONoVTGD.js +11 -0
  326. package/dist/server/assets/index-Bp8QskbI.js +28 -0
  327. package/dist/server/assets/index-COu2idHm.js +226 -0
  328. package/dist/server/assets/keyboard-shortcuts-dialog-D5hqVX2v.js +69 -0
  329. package/dist/server/assets/menu-D6n4DB0U.js +156 -0
  330. package/dist/server/assets/new-Dzk5YxE9.js +6 -0
  331. package/dist/server/assets/router-DbxyvprK.js +2749 -0
  332. package/dist/server/assets/search-dialog-JY8C3mqa.js +443 -0
  333. package/dist/server/assets/session-export-dialog-D87uafPD.js +80 -0
  334. package/dist/server/assets/settings-dialog-CBj7njLM.js +568 -0
  335. package/dist/server/assets/start-HYkvq4Ni.js +4 -0
  336. package/dist/server/server.js +1013 -0
  337. package/package.json +93 -0
@@ -0,0 +1,2749 @@
1
+ import { createRootRoute, Outlet, HeadContent, Scripts, createFileRoute, lazyRouteComponent, redirect, createRouter } from "@tanstack/react-router";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
4
+ import { randomUUID } from "node:crypto";
5
+ import WebSocket from "ws";
6
+ import { json } from "@tanstack/router-core/ssr/client";
7
+ import { readFile, mkdir, writeFile, rename, stat, readdir, rm, realpath, lstat } from "node:fs/promises";
8
+ import os from "node:os";
9
+ import path, { join, resolve, relative, extname } from "node:path";
10
+ import { posix } from "path";
11
+ const appCss = "/assets/styles-7aVSlb6l.css";
12
+ const swRegisterScript = `
13
+ (() => {
14
+ // Skip PWA service worker inside Capacitor native shell — they conflict
15
+ // with the native networking layer and caching.
16
+ if (window.Capacitor && window.Capacitor.isNativePlatform && window.Capacitor.isNativePlatform()) return;
17
+ if ('serviceWorker' in navigator) {
18
+ window.addEventListener('load', () => {
19
+ navigator.serviceWorker.register('/sw.js', { scope: '/' })
20
+ .then((reg) => {
21
+ // Auto-update: check for updates periodically
22
+ setInterval(() => reg.update(), 60 * 60 * 1000); // every hour
23
+ reg.addEventListener('updatefound', () => {
24
+ const newWorker = reg.installing;
25
+ if (newWorker) {
26
+ newWorker.addEventListener('statechange', () => {
27
+ if (newWorker.state === 'activated') {
28
+ // New version activated, could notify user here
29
+ console.log('[SW] New version activated');
30
+ }
31
+ });
32
+ }
33
+ });
34
+ })
35
+ .catch((err) => console.warn('[SW] Registration failed:', err));
36
+ });
37
+ }
38
+ })()
39
+ `;
40
+ const themeScript = `
41
+ (() => {
42
+ try {
43
+ const stored = localStorage.getItem('chat-settings')
44
+ let theme = 'system'
45
+ if (stored) {
46
+ const parsed = JSON.parse(stored)
47
+ const storedTheme = parsed?.state?.settings?.theme
48
+ if (storedTheme === 'light' || storedTheme === 'dark' || storedTheme === 'system' || storedTheme === 'chameleon') {
49
+ theme = storedTheme
50
+ }
51
+ }
52
+ const root = document.documentElement
53
+ const media = window.matchMedia('(prefers-color-scheme: dark)')
54
+ const apply = () => {
55
+ root.classList.remove('light', 'dark', 'system', 'chameleon')
56
+ root.classList.add(theme)
57
+ if (theme === 'system' && media.matches) {
58
+ root.classList.add('dark')
59
+ }
60
+ }
61
+ apply()
62
+ media.addEventListener('change', () => {
63
+ if (theme === 'system') apply()
64
+ })
65
+ } catch {}
66
+ })()
67
+ `;
68
+ const textSizeScript = `
69
+ (() => {
70
+ try {
71
+ const stored = localStorage.getItem('opencami-text-size')
72
+ const allowed = new Set(['14px', '16px', '18px', '20px'])
73
+ const value = allowed.has(stored) ? stored : '16px'
74
+ document.documentElement.style.setProperty('--opencami-text-size', value)
75
+ } catch {}
76
+ })()
77
+ `;
78
+ const Route$p = createRootRoute({
79
+ head: () => ({
80
+ meta: [
81
+ {
82
+ charSet: "utf-8"
83
+ },
84
+ {
85
+ name: "viewport",
86
+ content: "width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover"
87
+ },
88
+ {
89
+ title: "OpenCami"
90
+ },
91
+ {
92
+ name: "description",
93
+ content: "a fast web client for OpenClaw"
94
+ },
95
+ {
96
+ property: "og:image",
97
+ content: "/cover.webp"
98
+ },
99
+ {
100
+ property: "og:image:type",
101
+ content: "image/webp"
102
+ },
103
+ {
104
+ name: "twitter:card",
105
+ content: "summary_large_image"
106
+ },
107
+ {
108
+ name: "twitter:image",
109
+ content: "/cover.webp"
110
+ },
111
+ // PWA - Theme color
112
+ {
113
+ name: "theme-color",
114
+ content: "#0a0a0a"
115
+ },
116
+ // PWA - Apple iOS meta tags
117
+ {
118
+ name: "apple-mobile-web-app-capable",
119
+ content: "yes"
120
+ },
121
+ {
122
+ name: "apple-mobile-web-app-status-bar-style",
123
+ content: "black-translucent"
124
+ },
125
+ {
126
+ name: "apple-mobile-web-app-title",
127
+ content: "OpenCami"
128
+ },
129
+ // PWA - Android meta tags
130
+ {
131
+ name: "mobile-web-app-capable",
132
+ content: "yes"
133
+ }
134
+ ],
135
+ links: [
136
+ {
137
+ rel: "stylesheet",
138
+ href: appCss
139
+ },
140
+ {
141
+ rel: "icon",
142
+ type: "image/svg+xml",
143
+ href: "/favicon.svg"
144
+ },
145
+ // PWA - Apple touch icon
146
+ {
147
+ rel: "apple-touch-icon",
148
+ href: "/apple-touch-icon-180x180.png"
149
+ },
150
+ // PWA - Manifest
151
+ {
152
+ rel: "manifest",
153
+ href: "/manifest.json"
154
+ }
155
+ ]
156
+ }),
157
+ shellComponent: RootDocument,
158
+ component: RootLayout
159
+ });
160
+ const queryClient = new QueryClient();
161
+ function RootLayout() {
162
+ return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(Outlet, {}) });
163
+ }
164
+ function RootDocument({ children }) {
165
+ return /* @__PURE__ */ jsxs("html", { lang: "en", suppressHydrationWarning: true, children: [
166
+ /* @__PURE__ */ jsxs("head", { children: [
167
+ /* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: textSizeScript } }),
168
+ /* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: themeScript } }),
169
+ /* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: swRegisterScript } }),
170
+ /* @__PURE__ */ jsx(HeadContent, {})
171
+ ] }),
172
+ /* @__PURE__ */ jsxs("body", { children: [
173
+ /* @__PURE__ */ jsx("div", { className: "root", children }),
174
+ /* @__PURE__ */ jsx(Scripts, {})
175
+ ] })
176
+ ] });
177
+ }
178
+ const $$splitComponentImporter$4 = () => import("./new-Dzk5YxE9.js");
179
+ const Route$o = createFileRoute("/new")({
180
+ beforeLoad: function redirectToNewChat() {
181
+ throw redirect({
182
+ to: "/chat/$sessionKey",
183
+ params: {
184
+ sessionKey: "new"
185
+ },
186
+ replace: true
187
+ });
188
+ },
189
+ component: lazyRouteComponent($$splitComponentImporter$4, "component")
190
+ });
191
+ const $$splitComponentImporter$3 = () => import("./files-CONoVTGD.js");
192
+ const Route$n = createFileRoute("/files")({
193
+ component: lazyRouteComponent($$splitComponentImporter$3, "component")
194
+ });
195
+ const $$splitComponentImporter$2 = () => import("./connect-BWI_6rCm.js");
196
+ const Route$m = createFileRoute("/connect")({
197
+ component: lazyRouteComponent($$splitComponentImporter$2, "component")
198
+ });
199
+ const $$splitComponentImporter$1 = () => import("./index-Bp8QskbI.js");
200
+ const Route$l = createFileRoute("/")({
201
+ component: lazyRouteComponent($$splitComponentImporter$1, "component")
202
+ });
203
+ const $$splitComponentImporter = () => import("./_sessionKey-qlAPF_Ft.js").then((n) => n.$);
204
+ const Route$k = createFileRoute("/chat/$sessionKey")({
205
+ component: lazyRouteComponent($$splitComponentImporter, "component")
206
+ });
207
+ function getGatewayConfig() {
208
+ const url = process.env.CLAWDBOT_GATEWAY_URL?.trim() || "ws://127.0.0.1:18789";
209
+ const token = process.env.CLAWDBOT_GATEWAY_TOKEN?.trim() || "";
210
+ const password = process.env.CLAWDBOT_GATEWAY_PASSWORD?.trim() || "";
211
+ if (!token && !password) {
212
+ throw new Error(
213
+ "Missing gateway auth. Set CLAWDBOT_GATEWAY_TOKEN (recommended) or CLAWDBOT_GATEWAY_PASSWORD in the server environment."
214
+ );
215
+ }
216
+ return { url, token, password };
217
+ }
218
+ function buildConnectParams(token, password) {
219
+ return {
220
+ minProtocol: 3,
221
+ maxProtocol: 3,
222
+ client: {
223
+ id: "gateway-client",
224
+ displayName: "webclaw",
225
+ version: "dev",
226
+ platform: process.platform,
227
+ mode: "ui",
228
+ instanceId: randomUUID()
229
+ },
230
+ auth: {
231
+ token: token || void 0,
232
+ password: password || void 0
233
+ },
234
+ role: "operator",
235
+ scopes: ["operator.admin"]
236
+ };
237
+ }
238
+ class PersistentGatewayConnection {
239
+ ws = null;
240
+ connected = false;
241
+ connectPromise = null;
242
+ pendingRpcs = /* @__PURE__ */ new Map();
243
+ reconnectTimer = null;
244
+ reconnectDelay = 1e3;
245
+ maxReconnectDelay = 3e4;
246
+ destroyed = false;
247
+ // Event listeners keyed by sessionKey — each sessionKey can have multiple listeners
248
+ sessionListeners = /* @__PURE__ */ new Map();
249
+ // Listeners that receive ALL events (for debugging or global subscriptions)
250
+ globalListeners = /* @__PURE__ */ new Set();
251
+ // Event buffer: store recent events per sessionKey so late subscribers don't miss them
252
+ eventBuffer = /* @__PURE__ */ new Map();
253
+ get isConnected() {
254
+ return this.connected && this.ws?.readyState === WebSocket.OPEN;
255
+ }
256
+ /** Ensure the persistent connection is up and authenticated. */
257
+ async ensureConnected() {
258
+ if (this.isConnected) return;
259
+ if (this.connectPromise) return this.connectPromise;
260
+ this.connectPromise = this._connect();
261
+ try {
262
+ await this.connectPromise;
263
+ } finally {
264
+ this.connectPromise = null;
265
+ }
266
+ }
267
+ async _connect() {
268
+ if (this.destroyed) throw new Error("Connection destroyed");
269
+ const { url, token, password } = getGatewayConfig();
270
+ const ws = new WebSocket(url);
271
+ this.ws = ws;
272
+ await new Promise((resolve2, reject) => {
273
+ const onOpen = () => {
274
+ cleanup();
275
+ resolve2();
276
+ };
277
+ const onError = (err) => {
278
+ cleanup();
279
+ reject(new Error(`WS open error: ${err.message}`));
280
+ };
281
+ const cleanup = () => {
282
+ ws.off("open", onOpen);
283
+ ws.off("error", onError);
284
+ };
285
+ ws.on("open", onOpen);
286
+ ws.on("error", onError);
287
+ });
288
+ ws.on("message", (data) => this._onMessage(data));
289
+ ws.on("close", () => this._onClose());
290
+ ws.on("error", () => {
291
+ });
292
+ const connectId = randomUUID();
293
+ const connectParams = buildConnectParams(token, password);
294
+ ws.send(JSON.stringify({
295
+ type: "req",
296
+ id: connectId,
297
+ method: "connect",
298
+ params: connectParams
299
+ }));
300
+ await this._waitForRes(connectId, 1e4);
301
+ this.connected = true;
302
+ this.reconnectDelay = 1e3;
303
+ console.log("[gateway-ws] Persistent connection established");
304
+ }
305
+ _onMessage(data) {
306
+ try {
307
+ const str = typeof data === "string" ? data : data.toString();
308
+ const parsed = JSON.parse(str);
309
+ if (parsed.type === "res") {
310
+ const pending = this.pendingRpcs.get(parsed.id);
311
+ if (pending) {
312
+ this.pendingRpcs.delete(parsed.id);
313
+ clearTimeout(pending.timer);
314
+ if (parsed.ok) {
315
+ pending.resolve(parsed.payload);
316
+ } else {
317
+ pending.reject(new Error(parsed.error?.message ?? "gateway error"));
318
+ }
319
+ }
320
+ return;
321
+ }
322
+ if (parsed.type === "event") {
323
+ const event = {
324
+ event: parsed.event,
325
+ payload: parsed.payload ?? {},
326
+ seq: parsed.seq
327
+ };
328
+ const sessionKey = this._extractSessionKey(event);
329
+ for (const listener of this.globalListeners) {
330
+ try {
331
+ listener(event);
332
+ } catch {
333
+ }
334
+ }
335
+ if (sessionKey) {
336
+ const listeners = this.sessionListeners.get(sessionKey);
337
+ if (listeners && listeners.size > 0) {
338
+ for (const listener of listeners) {
339
+ try {
340
+ listener(event);
341
+ } catch {
342
+ }
343
+ }
344
+ } else {
345
+ let buf = this.eventBuffer.get(sessionKey);
346
+ if (!buf) {
347
+ const timer = setTimeout(() => {
348
+ this.eventBuffer.delete(sessionKey);
349
+ }, 1e4);
350
+ buf = { events: [], timer };
351
+ this.eventBuffer.set(sessionKey, buf);
352
+ }
353
+ buf.events.push(event);
354
+ }
355
+ }
356
+ }
357
+ } catch {
358
+ }
359
+ }
360
+ _extractSessionKey(event) {
361
+ const payload = event.payload;
362
+ if (typeof payload?.sessionKey === "string") return payload.sessionKey;
363
+ if (typeof payload?.session === "string") return payload.session;
364
+ if (payload?.data && typeof payload.data?.sessionKey === "string") {
365
+ return payload.data.sessionKey;
366
+ }
367
+ return null;
368
+ }
369
+ _onClose() {
370
+ const wasConnected = this.connected;
371
+ this.connected = false;
372
+ this.ws = null;
373
+ for (const [, pending] of this.pendingRpcs) {
374
+ clearTimeout(pending.timer);
375
+ pending.reject(new Error("Connection closed"));
376
+ }
377
+ this.pendingRpcs.clear();
378
+ if (wasConnected) {
379
+ console.log("[gateway-ws] Connection lost, scheduling reconnect...");
380
+ }
381
+ if (!this.destroyed) {
382
+ this._scheduleReconnect();
383
+ }
384
+ }
385
+ _scheduleReconnect() {
386
+ if (this.reconnectTimer) return;
387
+ const delay = this.reconnectDelay;
388
+ this.reconnectDelay = Math.min(this.reconnectDelay * 2, this.maxReconnectDelay);
389
+ console.log(`[gateway-ws] Reconnecting in ${delay}ms...`);
390
+ this.reconnectTimer = setTimeout(async () => {
391
+ this.reconnectTimer = null;
392
+ try {
393
+ await this.ensureConnected();
394
+ } catch (err) {
395
+ console.error("[gateway-ws] Reconnect failed:", err instanceof Error ? err.message : err);
396
+ }
397
+ }, delay);
398
+ }
399
+ _waitForRes(id, timeoutMs = 3e4) {
400
+ return new Promise((resolve2, reject) => {
401
+ const timer = setTimeout(() => {
402
+ this.pendingRpcs.delete(id);
403
+ reject(new Error(`RPC timeout waiting for ${id}`));
404
+ }, timeoutMs);
405
+ this.pendingRpcs.set(id, { resolve: resolve2, reject, timer });
406
+ });
407
+ }
408
+ /** Send an RPC request over the persistent connection. */
409
+ async rpc(method, params, timeoutMs = 3e4) {
410
+ await this.ensureConnected();
411
+ const id = randomUUID();
412
+ const frame = { type: "req", id, method, params };
413
+ this.ws.send(JSON.stringify(frame));
414
+ const payload = await this._waitForRes(id, timeoutMs);
415
+ return payload;
416
+ }
417
+ /** Subscribe to events for a specific sessionKey. Returns an unsubscribe function. */
418
+ subscribe(sessionKey, listener) {
419
+ let listeners = this.sessionListeners.get(sessionKey);
420
+ if (!listeners) {
421
+ listeners = /* @__PURE__ */ new Set();
422
+ this.sessionListeners.set(sessionKey, listeners);
423
+ }
424
+ listeners.add(listener);
425
+ const buf = this.eventBuffer.get(sessionKey);
426
+ if (buf) {
427
+ this.eventBuffer.delete(sessionKey);
428
+ clearTimeout(buf.timer);
429
+ for (const event of buf.events) {
430
+ try {
431
+ listener(event);
432
+ } catch {
433
+ }
434
+ }
435
+ }
436
+ return () => {
437
+ listeners.delete(listener);
438
+ if (listeners.size === 0) {
439
+ this.sessionListeners.delete(sessionKey);
440
+ }
441
+ };
442
+ }
443
+ /** Subscribe to ALL events. Returns an unsubscribe function. */
444
+ subscribeAll(listener) {
445
+ this.globalListeners.add(listener);
446
+ return () => {
447
+ this.globalListeners.delete(listener);
448
+ };
449
+ }
450
+ destroy() {
451
+ this.destroyed = true;
452
+ if (this.reconnectTimer) {
453
+ clearTimeout(this.reconnectTimer);
454
+ this.reconnectTimer = null;
455
+ }
456
+ if (this.ws) {
457
+ this.ws.close();
458
+ this.ws = null;
459
+ }
460
+ this.connected = false;
461
+ this.sessionListeners.clear();
462
+ this.globalListeners.clear();
463
+ }
464
+ }
465
+ let _instance = null;
466
+ function getPersistentConnection() {
467
+ if (!_instance) {
468
+ _instance = new PersistentGatewayConnection();
469
+ }
470
+ return _instance;
471
+ }
472
+ async function gatewayRpc(method, params) {
473
+ const conn = getPersistentConnection();
474
+ return conn.rpc(method, params);
475
+ }
476
+ function subscribeGatewayEvents(sessionKey, listener) {
477
+ const conn = getPersistentConnection();
478
+ return conn.subscribe(sessionKey, listener);
479
+ }
480
+ async function gatewayConnectCheck() {
481
+ const conn = getPersistentConnection();
482
+ await conn.ensureConnected();
483
+ }
484
+ async function ttsElevenLabs(text, apiKey, voice) {
485
+ const voiceId = voice || "21m00Tcm4TlvDq8ikWAM";
486
+ const res = await fetch(
487
+ `https://api.elevenlabs.io/v1/text-to-speech/${voiceId}`,
488
+ {
489
+ method: "POST",
490
+ headers: {
491
+ "xi-api-key": apiKey,
492
+ "Content-Type": "application/json",
493
+ Accept: "audio/mpeg"
494
+ },
495
+ body: JSON.stringify({
496
+ text: text.substring(0, 5e3),
497
+ model_id: "eleven_multilingual_v2",
498
+ voice_settings: {
499
+ stability: 0.5,
500
+ similarity_boost: 0.75
501
+ }
502
+ })
503
+ }
504
+ );
505
+ if (!res.ok) {
506
+ const err = await res.text();
507
+ throw new Error(`ElevenLabs error: ${err}`);
508
+ }
509
+ const audioBuffer = await res.arrayBuffer();
510
+ return new Response(audioBuffer, {
511
+ headers: {
512
+ "Content-Type": "audio/mpeg",
513
+ "Cache-Control": "public, max-age=3600"
514
+ }
515
+ });
516
+ }
517
+ async function ttsOpenAI(text, apiKey, voice) {
518
+ const res = await fetch("https://api.openai.com/v1/audio/speech", {
519
+ method: "POST",
520
+ headers: {
521
+ Authorization: `Bearer ${apiKey}`,
522
+ "Content-Type": "application/json"
523
+ },
524
+ body: JSON.stringify({
525
+ model: "tts-1",
526
+ input: text.substring(0, 4096),
527
+ voice: voice || "nova",
528
+ response_format: "mp3"
529
+ })
530
+ });
531
+ if (!res.ok) {
532
+ const err = await res.text();
533
+ throw new Error(`OpenAI TTS error: ${err}`);
534
+ }
535
+ const audioBuffer = await res.arrayBuffer();
536
+ return new Response(audioBuffer, {
537
+ headers: {
538
+ "Content-Type": "audio/mpeg",
539
+ "Cache-Control": "public, max-age=3600"
540
+ }
541
+ });
542
+ }
543
+ async function ttsEdge(text, voice) {
544
+ const { EdgeTTS } = await import("node-edge-tts");
545
+ const tts = new EdgeTTS();
546
+ await tts.synthesize(
547
+ text.substring(0, 5e3),
548
+ voice || "en-US-AriaNeural",
549
+ {}
550
+ );
551
+ const audioBuffer = await tts.toBuffer();
552
+ return new Response(audioBuffer, {
553
+ headers: {
554
+ "Content-Type": "audio/mpeg",
555
+ "Cache-Control": "public, max-age=3600"
556
+ }
557
+ });
558
+ }
559
+ const Route$j = createFileRoute("/api/tts")({
560
+ server: {
561
+ handlers: {
562
+ POST: async ({ request }) => {
563
+ try {
564
+ const body = await request.json().catch(() => ({}));
565
+ const text = typeof body.text === "string" ? body.text.trim() : "";
566
+ const voice = typeof body.voice === "string" ? body.voice.trim() : "";
567
+ const provider = typeof body.provider === "string" ? body.provider.trim() : "";
568
+ if (!text) {
569
+ return json(
570
+ { ok: false, error: "No text provided" },
571
+ { status: 400 }
572
+ );
573
+ }
574
+ const configRes = await gatewayRpc("config.get", {});
575
+ const ttsConfig = configRes?.config?.messages?.tts;
576
+ const env = configRes?.config?.env || {};
577
+ const elevenLabsKey = ttsConfig?.elevenlabs?.apiKey || env.ELEVENLABS_API_KEY || env.XI_API_KEY;
578
+ const openaiKey = ttsConfig?.openai?.apiKey || env.OPENAI_API_KEY;
579
+ const preferredProvider = provider || ttsConfig?.provider || "auto";
580
+ const errors = [];
581
+ if (preferredProvider === "elevenlabs" && elevenLabsKey) {
582
+ try {
583
+ return await ttsElevenLabs(text, elevenLabsKey, voice);
584
+ } catch (e) {
585
+ errors.push(
586
+ e instanceof Error ? e.message : String(e)
587
+ );
588
+ }
589
+ }
590
+ if (preferredProvider === "openai" && openaiKey) {
591
+ try {
592
+ return await ttsOpenAI(text, openaiKey, voice);
593
+ } catch (e) {
594
+ errors.push(
595
+ e instanceof Error ? e.message : String(e)
596
+ );
597
+ }
598
+ }
599
+ if (preferredProvider === "edge") {
600
+ try {
601
+ return await ttsEdge(text, voice);
602
+ } catch (e) {
603
+ errors.push(
604
+ e instanceof Error ? e.message : String(e)
605
+ );
606
+ }
607
+ }
608
+ if (preferredProvider === "auto" || errors.length > 0) {
609
+ if (elevenLabsKey) {
610
+ try {
611
+ return await ttsElevenLabs(
612
+ text,
613
+ elevenLabsKey,
614
+ voice
615
+ );
616
+ } catch (e) {
617
+ errors.push(
618
+ e instanceof Error ? e.message : String(e)
619
+ );
620
+ }
621
+ }
622
+ if (openaiKey) {
623
+ try {
624
+ return await ttsOpenAI(text, openaiKey, voice);
625
+ } catch (e) {
626
+ errors.push(
627
+ e instanceof Error ? e.message : String(e)
628
+ );
629
+ }
630
+ }
631
+ try {
632
+ return await ttsEdge(text, voice);
633
+ } catch (e) {
634
+ errors.push(
635
+ e instanceof Error ? e.message : String(e)
636
+ );
637
+ }
638
+ }
639
+ return json(
640
+ {
641
+ ok: false,
642
+ error: `All TTS providers failed: ${errors.join("; ")}`
643
+ },
644
+ { status: 502 }
645
+ );
646
+ } catch (err) {
647
+ return json(
648
+ {
649
+ ok: false,
650
+ error: err instanceof Error ? err.message : String(err)
651
+ },
652
+ { status: 500 }
653
+ );
654
+ }
655
+ }
656
+ }
657
+ }
658
+ });
659
+ const Route$i = createFileRoute("/api/stream")({
660
+ server: {
661
+ handlers: {
662
+ GET: async ({ request }) => {
663
+ const url = new URL(request.url);
664
+ const sessionKey = url.searchParams.get("sessionKey");
665
+ if (!sessionKey) {
666
+ return new Response(
667
+ JSON.stringify({ ok: false, error: "sessionKey required" }),
668
+ { status: 400, headers: { "content-type": "application/json" } }
669
+ );
670
+ }
671
+ const encoder = new TextEncoder();
672
+ let unsubscribe = null;
673
+ let closed = false;
674
+ const stream = new ReadableStream({
675
+ start(controller) {
676
+ controller.enqueue(encoder.encode(": connected\n\n"));
677
+ function sendSSE(event, data) {
678
+ if (closed) return;
679
+ try {
680
+ controller.enqueue(
681
+ encoder.encode(`event: ${event}
682
+ data: ${JSON.stringify(data)}
683
+
684
+ `)
685
+ );
686
+ } catch {
687
+ }
688
+ }
689
+ let gotAgentStream = false;
690
+ unsubscribe = subscribeGatewayEvents(sessionKey, (evt) => {
691
+ if (evt.event === "agent") {
692
+ const payload = evt.payload;
693
+ const agentStream = payload.stream;
694
+ if (agentStream === "assistant") {
695
+ gotAgentStream = true;
696
+ const data = payload.data ?? payload;
697
+ const text = typeof data.delta === "string" ? data.delta : typeof data.text === "string" ? data.text : typeof payload.text === "string" ? payload.text : typeof payload.delta === "string" ? payload.delta : "";
698
+ if (text) {
699
+ sendSSE("delta", { text, sessionKey });
700
+ }
701
+ } else if (agentStream === "tool") {
702
+ gotAgentStream = true;
703
+ const tdata = payload.data ?? payload;
704
+ sendSSE("tool", {
705
+ name: tdata.name ?? tdata.toolName ?? payload.name ?? "",
706
+ status: tdata.phase ?? tdata.status ?? payload.phase ?? "running",
707
+ id: tdata.id ?? tdata.toolCallId ?? payload.id ?? "",
708
+ sessionKey
709
+ });
710
+ } else if (agentStream === "lifecycle") {
711
+ const ldata = payload.data ?? payload;
712
+ const phase = ldata.phase ?? payload.phase;
713
+ if (phase === "end" || phase === "error") {
714
+ sendSSE("done", {
715
+ sessionKey,
716
+ status: phase,
717
+ error: phase === "error" ? payload.error : void 0
718
+ });
719
+ }
720
+ }
721
+ } else if (evt.event === "chat") {
722
+ const payload = evt.payload;
723
+ const kind = payload.kind;
724
+ if (kind === "delta" && !gotAgentStream) {
725
+ const text = typeof payload.text === "string" ? payload.text : typeof payload.delta === "string" ? payload.delta : "";
726
+ if (text) {
727
+ sendSSE("delta", { text, sessionKey });
728
+ }
729
+ } else if (kind === "final") {
730
+ sendSSE("done", { sessionKey, status: "end" });
731
+ }
732
+ }
733
+ });
734
+ },
735
+ cancel() {
736
+ closed = true;
737
+ if (unsubscribe) {
738
+ unsubscribe();
739
+ unsubscribe = null;
740
+ }
741
+ }
742
+ });
743
+ if (request.signal) {
744
+ request.signal.addEventListener("abort", () => {
745
+ closed = true;
746
+ if (unsubscribe) {
747
+ unsubscribe();
748
+ unsubscribe = null;
749
+ }
750
+ });
751
+ }
752
+ return new Response(stream, {
753
+ headers: {
754
+ "content-type": "text/event-stream",
755
+ "cache-control": "no-cache, no-transform",
756
+ connection: "keep-alive",
757
+ "x-accel-buffering": "no"
758
+ }
759
+ });
760
+ }
761
+ }
762
+ }
763
+ });
764
+ function deriveFriendlyIdFromKey(key) {
765
+ if (typeof key !== "string" || key.trim().length === 0) return "main";
766
+ const parts = key.split(":");
767
+ const tail = parts[parts.length - 1];
768
+ return tail && tail.trim().length > 0 ? tail.trim() : key;
769
+ }
770
+ function normalizeSessions(payload) {
771
+ const sessions = Array.isArray(
772
+ payload.sessions
773
+ ) ? payload.sessions : [];
774
+ const normalized = sessions.map((session) => {
775
+ const rawKey = session.key;
776
+ const key = typeof rawKey === "string" ? rawKey : "";
777
+ const rawFriendly = session.friendlyId;
778
+ const friendlyIdFromPayload = typeof rawFriendly === "string" ? rawFriendly.trim() : "";
779
+ const friendlyId = friendlyIdFromPayload.length > 0 ? friendlyIdFromPayload : deriveFriendlyIdFromKey(key);
780
+ return {
781
+ ...session,
782
+ key,
783
+ friendlyId
784
+ };
785
+ });
786
+ return { sessions: normalized };
787
+ }
788
+ const Route$h = createFileRoute("/api/sessions")({
789
+ server: {
790
+ handlers: {
791
+ GET: async () => {
792
+ try {
793
+ const payload = await gatewayRpc(
794
+ "sessions.list",
795
+ {
796
+ limit: 50,
797
+ includeLastMessage: true,
798
+ includeDerivedTitles: true
799
+ }
800
+ );
801
+ return json(normalizeSessions(payload));
802
+ } catch (err) {
803
+ return json(
804
+ {
805
+ error: err instanceof Error ? err.message : String(err)
806
+ },
807
+ { status: 500 }
808
+ );
809
+ }
810
+ },
811
+ POST: async ({ request }) => {
812
+ try {
813
+ const body = await request.json().catch(() => ({}));
814
+ const requestedLabel = typeof body.label === "string" ? body.label.trim() : "";
815
+ const label = requestedLabel || void 0;
816
+ const friendlyId = randomUUID();
817
+ const params = { key: friendlyId };
818
+ if (label) params.label = label;
819
+ const payload = await gatewayRpc(
820
+ "sessions.patch",
821
+ params
822
+ );
823
+ const sessionKeyRaw = payload.key;
824
+ const sessionKey = typeof sessionKeyRaw === "string" && sessionKeyRaw.trim().length > 0 ? sessionKeyRaw.trim() : "";
825
+ if (sessionKey.length === 0) {
826
+ throw new Error("gateway returned an invalid response");
827
+ }
828
+ await gatewayRpc("sessions.resolve", {
829
+ key: friendlyId,
830
+ includeUnknown: true,
831
+ includeGlobal: true
832
+ }).catch(() => ({ ok: false }));
833
+ return json({
834
+ ok: true,
835
+ sessionKey,
836
+ friendlyId,
837
+ entry: payload.entry
838
+ });
839
+ } catch (err) {
840
+ return json(
841
+ {
842
+ ok: false,
843
+ error: err instanceof Error ? err.message : String(err)
844
+ },
845
+ { status: 500 }
846
+ );
847
+ }
848
+ },
849
+ PATCH: async ({ request }) => {
850
+ try {
851
+ const body = await request.json().catch(() => ({}));
852
+ const rawSessionKey = typeof body.sessionKey === "string" ? body.sessionKey.trim() : "";
853
+ const rawFriendlyId = typeof body.friendlyId === "string" ? body.friendlyId.trim() : "";
854
+ const label = typeof body.label === "string" ? body.label.trim() : void 0;
855
+ let sessionKey = rawSessionKey;
856
+ const friendlyId = rawFriendlyId;
857
+ if (friendlyId) {
858
+ const resolved = await gatewayRpc(
859
+ "sessions.resolve",
860
+ {
861
+ key: friendlyId,
862
+ includeUnknown: true,
863
+ includeGlobal: true
864
+ }
865
+ );
866
+ const resolvedKey = typeof resolved.key === "string" ? resolved.key.trim() : "";
867
+ if (resolvedKey.length > 0) sessionKey = resolvedKey;
868
+ }
869
+ if (!sessionKey) {
870
+ return json(
871
+ { ok: false, error: "sessionKey required" },
872
+ { status: 400 }
873
+ );
874
+ }
875
+ const params = { key: sessionKey };
876
+ if (label) params.label = label;
877
+ const payload = await gatewayRpc(
878
+ "sessions.patch",
879
+ params
880
+ );
881
+ return json({
882
+ ok: true,
883
+ sessionKey,
884
+ entry: payload.entry
885
+ });
886
+ } catch (err) {
887
+ return json(
888
+ {
889
+ ok: false,
890
+ error: err instanceof Error ? err.message : String(err)
891
+ },
892
+ { status: 500 }
893
+ );
894
+ }
895
+ },
896
+ DELETE: async ({ request }) => {
897
+ try {
898
+ const url = new URL(request.url);
899
+ const rawSessionKey = url.searchParams.get("sessionKey") ?? "";
900
+ const rawFriendlyId = url.searchParams.get("friendlyId") ?? "";
901
+ let sessionKey = rawSessionKey.trim();
902
+ const friendlyId = rawFriendlyId.trim();
903
+ if (friendlyId) {
904
+ const resolved = await gatewayRpc(
905
+ "sessions.resolve",
906
+ {
907
+ key: friendlyId,
908
+ includeUnknown: true,
909
+ includeGlobal: true
910
+ }
911
+ );
912
+ const resolvedKey = typeof resolved.key === "string" ? resolved.key.trim() : "";
913
+ if (resolvedKey.length > 0) sessionKey = resolvedKey;
914
+ }
915
+ if (!sessionKey) {
916
+ return json(
917
+ { ok: false, error: "sessionKey required" },
918
+ { status: 400 }
919
+ );
920
+ }
921
+ await gatewayRpc("sessions.delete", { key: sessionKey });
922
+ if (friendlyId && friendlyId !== sessionKey) {
923
+ await gatewayRpc("sessions.delete", { key: friendlyId }).catch(
924
+ () => ({})
925
+ );
926
+ }
927
+ return json({ ok: true, sessionKey });
928
+ } catch (err) {
929
+ return json(
930
+ {
931
+ ok: false,
932
+ error: err instanceof Error ? err.message : String(err)
933
+ },
934
+ { status: 500 }
935
+ );
936
+ }
937
+ }
938
+ }
939
+ }
940
+ });
941
+ const Route$g = createFileRoute("/api/send")({
942
+ server: {
943
+ handlers: {
944
+ POST: async ({ request }) => {
945
+ try {
946
+ const body = await request.json().catch(() => ({}));
947
+ const rawSessionKey = typeof body.sessionKey === "string" ? body.sessionKey.trim() : "";
948
+ const friendlyId = typeof body.friendlyId === "string" ? body.friendlyId.trim() : "";
949
+ const message = String(body.message ?? "");
950
+ const thinking = typeof body.thinking === "string" ? body.thinking : void 0;
951
+ const rawAttachments = body.attachments;
952
+ const attachments = Array.isArray(rawAttachments) ? rawAttachments.filter(
953
+ (a) => typeof a === "object" && a !== null && typeof a.mimeType === "string" && typeof a.content === "string"
954
+ ) : void 0;
955
+ if (!message.trim() && (!attachments || attachments.length === 0)) {
956
+ return json(
957
+ { ok: false, error: "message required" },
958
+ { status: 400 }
959
+ );
960
+ }
961
+ let sessionKey = rawSessionKey.length > 0 ? rawSessionKey : "";
962
+ if (!sessionKey && friendlyId) {
963
+ const resolved = await gatewayRpc(
964
+ "sessions.resolve",
965
+ {
966
+ key: friendlyId,
967
+ includeUnknown: true,
968
+ includeGlobal: true
969
+ }
970
+ );
971
+ const resolvedKey = typeof resolved.key === "string" ? resolved.key.trim() : "";
972
+ if (resolvedKey.length === 0) {
973
+ return json(
974
+ { ok: false, error: "session not found" },
975
+ { status: 404 }
976
+ );
977
+ }
978
+ sessionKey = resolvedKey;
979
+ }
980
+ if (sessionKey.length === 0) {
981
+ sessionKey = "main";
982
+ }
983
+ const res = await gatewayRpc("chat.send", {
984
+ sessionKey,
985
+ message,
986
+ thinking,
987
+ // model, // Gateway doesn't support model override yet
988
+ attachments,
989
+ deliver: false,
990
+ timeoutMs: 12e4,
991
+ idempotencyKey: typeof body.idempotencyKey === "string" ? body.idempotencyKey : randomUUID()
992
+ });
993
+ return json({ ok: true, ...res, sessionKey });
994
+ } catch (err) {
995
+ return json(
996
+ {
997
+ ok: false,
998
+ error: err instanceof Error ? err.message : String(err)
999
+ },
1000
+ { status: 500 }
1001
+ );
1002
+ }
1003
+ }
1004
+ }
1005
+ }
1006
+ });
1007
+ const Route$f = createFileRoute("/api/ping")({
1008
+ server: {
1009
+ handlers: {
1010
+ GET: async () => {
1011
+ try {
1012
+ await gatewayConnectCheck();
1013
+ return json({ ok: true });
1014
+ } catch (err) {
1015
+ return json(
1016
+ {
1017
+ ok: false,
1018
+ error: err instanceof Error ? err.message : String(err)
1019
+ },
1020
+ { status: 503 }
1021
+ );
1022
+ }
1023
+ }
1024
+ }
1025
+ }
1026
+ });
1027
+ const categories = { "core": [{ "id": "cami", "name": "Cami", "emoji": "🦎", "description": "Adaptive AI chameleon companion" }, { "id": "chameleon-agent", "name": "Chameleon Agent", "emoji": "🌀", "description": "Meta-adaptive agent" }, { "id": "professor-stein", "name": "Professor Stein", "emoji": "🎓", "description": "Academic educator & researcher" }, { "id": "dev", "name": "Dev", "emoji": "💻", "description": "Senior programmer & code expert" }, { "id": "flash", "name": "Flash", "emoji": "⚡", "description": "Quick answers & fast problem solver" }], "creative": [{ "id": "luna", "name": "Luna", "emoji": "🌙", "description": "Creative writer & storyteller" }], "curator": [{ "id": "vibe", "name": "Vibe", "emoji": "🎵", "description": "Music curator & playlist expert" }], "learning": [{ "id": "herr-mueller", "name": "Herr Müller", "emoji": "🇩🇪", "description": "German language teacher" }, { "id": "scholar", "name": "Scholar", "emoji": "📚", "description": "Research assistant & academic guide" }, { "id": "lingua", "name": "Lingua", "emoji": "🌍", "description": "Multilingual language coach" }], "lifestyle": [{ "id": "chef-marco", "name": "Chef Marco", "emoji": "👨‍🍳", "description": "Italian cooking expert" }, { "id": "fit", "name": "Fit", "emoji": "💪", "description": "Fitness trainer & health coach" }, { "id": "zen", "name": "Zen", "emoji": "🧘", "description": "Mindfulness & meditation guide" }], "professional": [{ "id": "cyberguard", "name": "Cyberguard", "emoji": "🛡️", "description": "Cybersecurity expert" }, { "id": "dataviz", "name": "DataViz", "emoji": "📊", "description": "Data visualization specialist" }, { "id": "career-coach", "name": "Career Coach", "emoji": "🎯", "description": "Career guidance & interview prep" }, { "id": "legal-guide", "name": "Legal Guide", "emoji": "⚖️", "description": "Legal information assistant" }, { "id": "startup-sam", "name": "Startup Sam", "emoji": "🚀", "description": "Startup advisor & entrepreneur" }, { "id": "dr-med", "name": "Dr. Med", "emoji": "🩺", "description": "Medical information educator" }, { "id": "wordsmith", "name": "Wordsmith", "emoji": "✍️", "description": "Writing coach & editor" }] };
1028
+ const personasData = {
1029
+ categories
1030
+ };
1031
+ const Route$e = createFileRoute("/api/personas")({
1032
+ server: {
1033
+ handlers: {
1034
+ GET: async () => {
1035
+ try {
1036
+ const res = await gatewayRpc("config.get", {});
1037
+ const workspace = res.config?.agents?.defaults?.workspace || "/root/clawd";
1038
+ const skillJson = await readFile(
1039
+ `${workspace}/skills/personas/skill.json`,
1040
+ "utf-8"
1041
+ );
1042
+ const skill = JSON.parse(skillJson);
1043
+ return json({
1044
+ ok: true,
1045
+ personas: personasData.categories,
1046
+ available: true,
1047
+ skillVersion: skill.version
1048
+ });
1049
+ } catch {
1050
+ return json({
1051
+ ok: true,
1052
+ personas: {},
1053
+ available: false
1054
+ });
1055
+ }
1056
+ }
1057
+ }
1058
+ }
1059
+ });
1060
+ function resolveSessionsDir() {
1061
+ const agentId = (process.env.CLAWDBOT_AGENT_ID || "main").trim() || "main";
1062
+ const stateDir = (process.env.CLAWDBOT_STATE_DIR || path.join(os.homedir(), ".clawdbot")).trim();
1063
+ return {
1064
+ agentId,
1065
+ stateDir,
1066
+ sessionsDir: path.join(stateDir, "agents", agentId, "sessions"),
1067
+ storePath: path.join(
1068
+ stateDir,
1069
+ "agents",
1070
+ agentId,
1071
+ "sessions",
1072
+ "sessions.json"
1073
+ )
1074
+ };
1075
+ }
1076
+ const Route$d = createFileRoute("/api/paths")({
1077
+ server: {
1078
+ handlers: {
1079
+ GET: () => {
1080
+ return json(resolveSessionsDir());
1081
+ }
1082
+ }
1083
+ }
1084
+ });
1085
+ function parseModelName(modelId) {
1086
+ if (modelId.includes("hf:")) {
1087
+ const match = modelId.match(/hf:[^/]+\/(.+)$/);
1088
+ if (match) {
1089
+ return match[1].replace(/-/g, " ");
1090
+ }
1091
+ }
1092
+ const segments = modelId.split("/");
1093
+ const model = segments[segments.length - 1];
1094
+ return model.split("-").map((word) => {
1095
+ if (["gpt", "ai", "api", "glm"].includes(word.toLowerCase())) {
1096
+ return word.toUpperCase();
1097
+ }
1098
+ return word.charAt(0).toUpperCase() + word.slice(1);
1099
+ }).join(" ");
1100
+ }
1101
+ const Route$c = createFileRoute("/api/models")({
1102
+ server: {
1103
+ handlers: {
1104
+ GET: async () => {
1105
+ try {
1106
+ const res = await gatewayRpc("config.get", {});
1107
+ const models = [];
1108
+ if (res.config?.agents?.defaults?.models) {
1109
+ const agentModels = res.config.agents.defaults.models;
1110
+ for (const [modelId, modelConfig] of Object.entries(agentModels)) {
1111
+ const parsedName = parseModelName(modelId);
1112
+ models.push({
1113
+ id: modelId,
1114
+ name: modelConfig.alias ? `${parsedName} (${modelConfig.alias})` : parsedName,
1115
+ provider: modelId.split("/")[0]
1116
+ });
1117
+ }
1118
+ }
1119
+ if (models.length === 0 && res.config?.chat?.models && Array.isArray(res.config.chat.models)) {
1120
+ for (const model of res.config.chat.models) {
1121
+ if (model.enabled !== false && model.id) {
1122
+ models.push({
1123
+ id: model.id,
1124
+ name: model.name || parseModelName(model.id),
1125
+ provider: model.provider
1126
+ });
1127
+ }
1128
+ }
1129
+ }
1130
+ if (models.length === 0 && res.config?.model?.allowed) {
1131
+ for (const modelId of res.config.model.allowed) {
1132
+ models.push({
1133
+ id: modelId,
1134
+ name: parseModelName(modelId)
1135
+ });
1136
+ }
1137
+ }
1138
+ const defaultModel = res.config?.agents?.defaults?.model?.primary || res.config?.chat?.defaultModel || res.config?.model?.defaultModel || models[0]?.id || "";
1139
+ return json({
1140
+ ok: true,
1141
+ models,
1142
+ defaultModel
1143
+ });
1144
+ } catch (err) {
1145
+ console.error("[models] Error fetching models:", err);
1146
+ return json({
1147
+ ok: true,
1148
+ models: [
1149
+ {
1150
+ id: "default",
1151
+ name: "Default Model"
1152
+ }
1153
+ ],
1154
+ defaultModel: "default"
1155
+ });
1156
+ }
1157
+ }
1158
+ }
1159
+ }
1160
+ });
1161
+ const DEFAULT_BASE_URL = "https://api.openai.com/v1";
1162
+ const DEFAULT_TIMEOUT_MS = 1e4;
1163
+ const MODEL_FALLBACK_CHAIN = [
1164
+ "gpt-4.1-nano",
1165
+ "gpt-4o-mini",
1166
+ "gpt-3.5-turbo"
1167
+ ];
1168
+ async function chatCompletion(messages, options) {
1169
+ const {
1170
+ apiKey,
1171
+ baseUrl = DEFAULT_BASE_URL,
1172
+ model,
1173
+ timeoutMs = DEFAULT_TIMEOUT_MS,
1174
+ maxTokens = 100
1175
+ } = options;
1176
+ const modelsToTry = model ? [model] : MODEL_FALLBACK_CHAIN;
1177
+ let lastError = null;
1178
+ for (const currentModel of modelsToTry) {
1179
+ const controller = new AbortController();
1180
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
1181
+ try {
1182
+ const response = await fetch(`${baseUrl}/chat/completions`, {
1183
+ method: "POST",
1184
+ headers: {
1185
+ "Content-Type": "application/json",
1186
+ "Authorization": `Bearer ${apiKey}`
1187
+ },
1188
+ body: JSON.stringify({
1189
+ model: currentModel,
1190
+ messages,
1191
+ max_tokens: maxTokens,
1192
+ temperature: 0.7
1193
+ }),
1194
+ signal: controller.signal
1195
+ });
1196
+ clearTimeout(timeoutId);
1197
+ if (!response.ok) {
1198
+ const errorText = await response.text();
1199
+ if (response.status === 404 || errorText.includes("model_not_found")) {
1200
+ console.log(`[llm-client] Model ${currentModel} not available, trying next...`);
1201
+ lastError = new Error(`Model ${currentModel} not found`);
1202
+ continue;
1203
+ }
1204
+ throw new Error(`OpenAI API error: ${response.status} ${errorText}`);
1205
+ }
1206
+ const data = await response.json();
1207
+ const content = data.choices[0]?.message?.content?.trim() || "";
1208
+ if (content) {
1209
+ return content;
1210
+ }
1211
+ lastError = new Error(`Model ${currentModel} returned empty response`);
1212
+ continue;
1213
+ } catch (error) {
1214
+ clearTimeout(timeoutId);
1215
+ if (error instanceof Error && error.name === "AbortError") {
1216
+ lastError = new Error("OpenAI API request timed out");
1217
+ continue;
1218
+ }
1219
+ lastError = error instanceof Error ? error : new Error(String(error));
1220
+ continue;
1221
+ }
1222
+ }
1223
+ throw lastError || new Error("All models failed");
1224
+ }
1225
+ async function generateSessionTitle(message, options) {
1226
+ const systemPrompt = `Generate a concise 3-6 word title for this conversation.
1227
+ Rules:
1228
+ - No quotes or punctuation at the end
1229
+ - Capture the main topic/intent
1230
+ - Be specific, not generic
1231
+ - Use title case`;
1232
+ return chatCompletion(
1233
+ [
1234
+ { role: "system", content: systemPrompt },
1235
+ { role: "user", content: message }
1236
+ ],
1237
+ { ...options, maxTokens: 25 }
1238
+ );
1239
+ }
1240
+ async function generateFollowUps(conversationContext, options) {
1241
+ const systemPrompt = `Based on this conversation, suggest 3 natural follow-up questions the user might ask.
1242
+ Rules:
1243
+ - Each question max 10 words
1244
+ - Make them specific to the conversation context
1245
+ - Vary the types: clarification, deeper dive, related topic
1246
+ - Return ONLY a JSON array of 3 strings, nothing else`;
1247
+ const response = await chatCompletion(
1248
+ [
1249
+ { role: "system", content: systemPrompt },
1250
+ { role: "user", content: conversationContext }
1251
+ ],
1252
+ { ...options, maxTokens: 150 }
1253
+ );
1254
+ try {
1255
+ let jsonStr = response.trim();
1256
+ if (jsonStr.startsWith("```")) {
1257
+ jsonStr = jsonStr.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "");
1258
+ }
1259
+ const parsed = JSON.parse(jsonStr);
1260
+ if (Array.isArray(parsed) && parsed.length > 0) {
1261
+ return parsed.slice(0, 3).map(String);
1262
+ }
1263
+ } catch {
1264
+ }
1265
+ return [];
1266
+ }
1267
+ async function testApiKey(apiKey) {
1268
+ try {
1269
+ await chatCompletion(
1270
+ [{ role: "user", content: "Hi" }],
1271
+ { apiKey, maxTokens: 1, timeoutMs: 5e3 }
1272
+ );
1273
+ return true;
1274
+ } catch {
1275
+ return false;
1276
+ }
1277
+ }
1278
+ function getApiKey(request) {
1279
+ const headerKey = request.headers.get("X-OpenAI-API-Key");
1280
+ if (headerKey?.trim()) {
1281
+ return headerKey.trim();
1282
+ }
1283
+ const envKey = process.env.OPENAI_API_KEY?.trim();
1284
+ if (envKey) {
1285
+ return envKey;
1286
+ }
1287
+ return null;
1288
+ }
1289
+ function generateHeuristicTitle(message) {
1290
+ let text = message.replace(/```[\s\S]*?```/g, " ");
1291
+ text = text.replace(/`[^`]+`/g, " ");
1292
+ text = text.replace(/https?:\/\/[^\s]+/g, " ");
1293
+ text = text.replace(/[^\w\s.,!?'-]/g, " ");
1294
+ text = text.replace(/\s+/g, " ").trim();
1295
+ const words = text.split(/\s+/).filter((word) => {
1296
+ if (word.length <= 2 && !["AI", "ML", "UI", "UX", "API", "CSS", "JS"].includes(word.toUpperCase())) {
1297
+ return false;
1298
+ }
1299
+ return true;
1300
+ });
1301
+ const titleWords = words.slice(0, 6);
1302
+ let title = titleWords.join(" ");
1303
+ title = title.replace(/[.,!?]+$/, "");
1304
+ if (title.length > 60) {
1305
+ title = title.slice(0, 57) + "...";
1306
+ }
1307
+ return title || message.slice(0, 50);
1308
+ }
1309
+ const Route$b = createFileRoute("/api/llm-features")({
1310
+ server: {
1311
+ handlers: {
1312
+ /**
1313
+ * GET /api/llm-features - Check LLM features status
1314
+ */
1315
+ GET: async () => {
1316
+ try {
1317
+ const hasEnvKey = Boolean(process.env.OPENAI_API_KEY?.trim());
1318
+ return json({
1319
+ ok: true,
1320
+ hasEnvKey
1321
+ });
1322
+ } catch (err) {
1323
+ return json({
1324
+ ok: false,
1325
+ hasEnvKey: false,
1326
+ error: err instanceof Error ? err.message : String(err)
1327
+ });
1328
+ }
1329
+ },
1330
+ /**
1331
+ * POST /api/llm-features - Handle LLM feature requests
1332
+ *
1333
+ * Request body should include an "action" field:
1334
+ * - action: "title" - Generate session title
1335
+ * - action: "followups" - Generate follow-up suggestions
1336
+ * - action: "test" - Test API key validity
1337
+ */
1338
+ POST: async ({ request }) => {
1339
+ try {
1340
+ const body = await request.json().catch(() => ({}));
1341
+ const action = body.action;
1342
+ switch (action) {
1343
+ case "title": {
1344
+ const { message } = body;
1345
+ if (!message || typeof message !== "string" || message.trim().length < 3) {
1346
+ return json({
1347
+ ok: false,
1348
+ error: "Message is required and must be at least 3 characters"
1349
+ });
1350
+ }
1351
+ const apiKey = getApiKey(request);
1352
+ if (!apiKey) {
1353
+ const title = generateHeuristicTitle(message);
1354
+ return json({
1355
+ ok: true,
1356
+ title,
1357
+ source: "heuristic"
1358
+ });
1359
+ }
1360
+ try {
1361
+ const title = await generateSessionTitle(message, { apiKey });
1362
+ return json({
1363
+ ok: true,
1364
+ title,
1365
+ source: "llm"
1366
+ });
1367
+ } catch (err) {
1368
+ console.error("[llm-features] Title generation error:", err);
1369
+ const title = generateHeuristicTitle(message);
1370
+ return json({
1371
+ ok: true,
1372
+ title,
1373
+ source: "heuristic",
1374
+ error: err instanceof Error ? err.message : "LLM error, used heuristic"
1375
+ });
1376
+ }
1377
+ }
1378
+ case "followups": {
1379
+ const { conversationContext } = body;
1380
+ if (!conversationContext || typeof conversationContext !== "string" || conversationContext.trim().length < 10) {
1381
+ return json({
1382
+ ok: true,
1383
+ suggestions: [],
1384
+ source: "heuristic"
1385
+ });
1386
+ }
1387
+ const apiKey = getApiKey(request);
1388
+ if (!apiKey) {
1389
+ return json({
1390
+ ok: true,
1391
+ suggestions: [],
1392
+ source: "heuristic"
1393
+ });
1394
+ }
1395
+ try {
1396
+ const suggestions = await generateFollowUps(conversationContext, { apiKey });
1397
+ return json({
1398
+ ok: true,
1399
+ suggestions,
1400
+ source: "llm"
1401
+ });
1402
+ } catch (err) {
1403
+ console.error("[llm-features] Follow-ups generation error:", err);
1404
+ return json({
1405
+ ok: true,
1406
+ suggestions: [],
1407
+ source: "heuristic",
1408
+ error: err instanceof Error ? err.message : "LLM error"
1409
+ });
1410
+ }
1411
+ }
1412
+ case "test": {
1413
+ const headerKey = request.headers.get("X-OpenAI-API-Key")?.trim();
1414
+ if (!headerKey) {
1415
+ return json({
1416
+ ok: false,
1417
+ error: "API key required in X-OpenAI-API-Key header"
1418
+ });
1419
+ }
1420
+ try {
1421
+ const valid = await testApiKey(headerKey);
1422
+ return json({
1423
+ ok: true,
1424
+ valid
1425
+ });
1426
+ } catch (err) {
1427
+ return json({
1428
+ ok: true,
1429
+ valid: false,
1430
+ error: err instanceof Error ? err.message : "Test failed"
1431
+ });
1432
+ }
1433
+ }
1434
+ default:
1435
+ return json({
1436
+ ok: false,
1437
+ error: `Unknown action: ${action}. Valid actions: title, followups, test`
1438
+ }, { status: 400 });
1439
+ }
1440
+ } catch (err) {
1441
+ console.error("[llm-features] Error:", err);
1442
+ return json({
1443
+ ok: false,
1444
+ error: err instanceof Error ? err.message : String(err)
1445
+ }, { status: 500 });
1446
+ }
1447
+ }
1448
+ }
1449
+ }
1450
+ });
1451
+ const Route$a = createFileRoute("/api/history")({
1452
+ server: {
1453
+ handlers: {
1454
+ GET: async ({ request }) => {
1455
+ try {
1456
+ const url = new URL(request.url);
1457
+ const limit = Number(url.searchParams.get("limit") || "200");
1458
+ const rawSessionKey = url.searchParams.get("sessionKey")?.trim();
1459
+ const friendlyId = url.searchParams.get("friendlyId")?.trim();
1460
+ let sessionKey = rawSessionKey && rawSessionKey.length > 0 ? rawSessionKey : "";
1461
+ if (!sessionKey && friendlyId) {
1462
+ const resolved = await gatewayRpc(
1463
+ "sessions.resolve",
1464
+ {
1465
+ key: friendlyId,
1466
+ includeUnknown: true,
1467
+ includeGlobal: true
1468
+ }
1469
+ );
1470
+ const resolvedKey = typeof resolved.key === "string" ? resolved.key.trim() : "";
1471
+ if (resolvedKey.length === 0) {
1472
+ return json({ error: "session not found" }, { status: 404 });
1473
+ }
1474
+ sessionKey = resolvedKey;
1475
+ }
1476
+ if (sessionKey.length === 0) {
1477
+ sessionKey = "main";
1478
+ }
1479
+ const payload = await gatewayRpc(
1480
+ "chat.history",
1481
+ {
1482
+ sessionKey,
1483
+ limit
1484
+ }
1485
+ );
1486
+ return json(payload);
1487
+ } catch (err) {
1488
+ return json(
1489
+ {
1490
+ error: err instanceof Error ? err.message : String(err)
1491
+ },
1492
+ { status: 500 }
1493
+ );
1494
+ }
1495
+ }
1496
+ }
1497
+ }
1498
+ });
1499
+ const FOLLOW_UP_SYSTEM_PROMPT = `You are a helpful assistant that generates follow-up question suggestions.
1500
+ Given the assistant's last response, generate exactly 3 short, natural follow-up questions the user might want to ask.
1501
+
1502
+ Rules:
1503
+ - Each suggestion should be a single, concise question (under 60 characters preferred)
1504
+ - Make them contextually relevant to the response
1505
+ - Vary the types: clarification, deeper exploration, practical application
1506
+ - Use natural, conversational language
1507
+ - Do not number them or add any prefix
1508
+
1509
+ Output format: Return ONLY the 3 questions, one per line, nothing else.`;
1510
+ function parseFollowUps(text) {
1511
+ const lines = text.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => line.replace(/^\d+[.)\s]+/, "").trim()).map((line) => line.replace(/^[-•*]\s*/, "").trim()).map((line) => line.replace(/^["']|["']$/g, "").trim()).filter((line) => line.length > 0 && line.length < 150);
1512
+ return lines.slice(0, 3);
1513
+ }
1514
+ const Route$9 = createFileRoute("/api/follow-ups")({
1515
+ server: {
1516
+ handlers: {
1517
+ POST: async ({ request }) => {
1518
+ try {
1519
+ const body = await request.json().catch(() => ({}));
1520
+ const responseText = typeof body.responseText === "string" ? body.responseText.trim() : "";
1521
+ if (!responseText || responseText.length < 30) {
1522
+ return json({ ok: true, suggestions: [] });
1523
+ }
1524
+ const truncatedResponse = responseText.length > 1500 ? responseText.slice(0, 1500) + "..." : responseText;
1525
+ const contextSummary = typeof body.contextSummary === "string" ? body.contextSummary.slice(0, 500) : "";
1526
+ const userPrompt = contextSummary ? `Context: ${contextSummary}
1527
+
1528
+ Assistant's response:
1529
+ ${truncatedResponse}` : `Assistant's response:
1530
+ ${truncatedResponse}`;
1531
+ const res = await gatewayRpc("chat.complete", {
1532
+ messages: [
1533
+ { role: "system", content: FOLLOW_UP_SYSTEM_PROMPT },
1534
+ { role: "user", content: userPrompt }
1535
+ ],
1536
+ maxTokens: 200,
1537
+ temperature: 0.7
1538
+ // Use session's default model (no hardcoding!)
1539
+ });
1540
+ const content = res.content || res.message?.content || res.choices?.[0]?.message?.content || "";
1541
+ const suggestions = parseFollowUps(content);
1542
+ return json({ ok: true, suggestions });
1543
+ } catch (err) {
1544
+ console.error("[follow-ups] Error generating suggestions:", err);
1545
+ return json({
1546
+ ok: false,
1547
+ error: err instanceof Error ? err.message : String(err),
1548
+ suggestions: []
1549
+ });
1550
+ }
1551
+ }
1552
+ }
1553
+ }
1554
+ });
1555
+ function createError(message, status, code) {
1556
+ const err = new Error(message);
1557
+ err.status = status;
1558
+ err.code = code;
1559
+ return err;
1560
+ }
1561
+ let _cachedRoot = null;
1562
+ function getFilesRoot() {
1563
+ if (_cachedRoot) return _cachedRoot;
1564
+ const root = process.env.FILES_ROOT?.trim();
1565
+ _cachedRoot = root ? resolve(root) : process.env.HOME || "/home";
1566
+ return _cachedRoot;
1567
+ }
1568
+ async function resolveSafePath(virtualPath) {
1569
+ const root = getFilesRoot();
1570
+ if (virtualPath.includes("\0")) {
1571
+ throw createError("Invalid path", 400, "INVALID_PATH");
1572
+ }
1573
+ const cleaned = virtualPath.replace(/^\/+/, "");
1574
+ const resolved = resolve(root, cleaned);
1575
+ const rel = relative(root, resolved);
1576
+ if (rel.startsWith("..") || resolve(root, rel) !== resolved) {
1577
+ throw createError("Path is outside the allowed directory", 403, "FORBIDDEN");
1578
+ }
1579
+ try {
1580
+ const real = await realpath(resolved);
1581
+ const realRoot = await realpath(root);
1582
+ if (!real.startsWith(realRoot + "/") && real !== realRoot) {
1583
+ throw createError("Path is outside the allowed directory", 403, "FORBIDDEN");
1584
+ }
1585
+ } catch (err) {
1586
+ if (err.code !== "ENOENT" && err.status !== 403) ;
1587
+ if (err.status === 403) throw err;
1588
+ }
1589
+ return resolved;
1590
+ }
1591
+ function classifyFile(name, isDirectory) {
1592
+ if (isDirectory) return "directory";
1593
+ const ext = extname(name).toLowerCase().slice(1);
1594
+ const imageExts = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "gif", "webp", "svg", "bmp", "ico", "tiff"]);
1595
+ const videoExts = /* @__PURE__ */ new Set(["mp4", "mkv", "avi", "mov", "wmv", "flv", "webm"]);
1596
+ const audioExts = /* @__PURE__ */ new Set(["mp3", "wav", "ogg", "flac", "aac", "m4a", "wma"]);
1597
+ const textExts = /* @__PURE__ */ new Set([
1598
+ "txt",
1599
+ "md",
1600
+ "log",
1601
+ "json",
1602
+ "xml",
1603
+ "yaml",
1604
+ "yml",
1605
+ "csv",
1606
+ "ini",
1607
+ "conf",
1608
+ "cfg",
1609
+ "js",
1610
+ "ts",
1611
+ "jsx",
1612
+ "tsx",
1613
+ "py",
1614
+ "java",
1615
+ "cpp",
1616
+ "c",
1617
+ "h",
1618
+ "css",
1619
+ "html",
1620
+ "htm",
1621
+ "php",
1622
+ "rb",
1623
+ "go",
1624
+ "rs",
1625
+ "sh",
1626
+ "bash",
1627
+ "zsh",
1628
+ "fish",
1629
+ "toml",
1630
+ "env",
1631
+ "gitignore",
1632
+ "dockerfile",
1633
+ "makefile"
1634
+ ]);
1635
+ if (imageExts.has(ext)) return "image";
1636
+ if (videoExts.has(ext)) return "video";
1637
+ if (audioExts.has(ext)) return "audio";
1638
+ if (textExts.has(ext)) return "text";
1639
+ return "blob";
1640
+ }
1641
+ async function buildFileItem(absolutePath, name, virtualPath) {
1642
+ const [stats, linkStats] = await Promise.all([
1643
+ stat(absolutePath),
1644
+ lstat(absolutePath)
1645
+ ]);
1646
+ const isDir = stats.isDirectory();
1647
+ return {
1648
+ path: virtualPath,
1649
+ name,
1650
+ size: stats.size,
1651
+ extension: isDir ? "" : extname(name).slice(1).toLowerCase(),
1652
+ modified: stats.mtime.toISOString(),
1653
+ mode: stats.mode,
1654
+ isDir,
1655
+ isSymlink: linkStats.isSymbolicLink(),
1656
+ type: classifyFile(name, isDir)
1657
+ };
1658
+ }
1659
+ async function listFiles(path2 = "/") {
1660
+ const absolutePath = await resolveSafePath(path2);
1661
+ let stats;
1662
+ try {
1663
+ stats = await stat(absolutePath);
1664
+ } catch (err) {
1665
+ if (err.code === "ENOENT") {
1666
+ throw createError(`Path not found: ${path2}`, 404, "NOT_FOUND");
1667
+ }
1668
+ throw createError(`Failed to access path: ${err.message}`, 500, "FS_ERROR");
1669
+ }
1670
+ if (!stats.isDirectory()) {
1671
+ throw createError("Path is not a directory", 400, "NOT_DIRECTORY");
1672
+ }
1673
+ let entries;
1674
+ try {
1675
+ entries = await readdir(absolutePath, { withFileTypes: true });
1676
+ } catch (err) {
1677
+ if (err.code === "EACCES") {
1678
+ throw createError("Permission denied", 403, "PERMISSION_DENIED");
1679
+ }
1680
+ throw createError(`Failed to read directory: ${err.message}`, 500, "FS_ERROR");
1681
+ }
1682
+ const visibleEntries = entries;
1683
+ const items = [];
1684
+ let numDirs = 0;
1685
+ let numFiles = 0;
1686
+ for (const entry of visibleEntries) {
1687
+ const entryPath = join(absolutePath, entry.name);
1688
+ const virtualEntryPath = path2 === "/" ? `/${entry.name}` : `${path2}/${entry.name}`;
1689
+ try {
1690
+ const item = await buildFileItem(entryPath, entry.name, virtualEntryPath);
1691
+ items.push(item);
1692
+ if (item.isDir) numDirs++;
1693
+ else numFiles++;
1694
+ } catch {
1695
+ }
1696
+ }
1697
+ items.sort((a, b) => {
1698
+ if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;
1699
+ return a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
1700
+ });
1701
+ const dirName = path2 === "/" ? "/" : path2.split("/").pop() || "/";
1702
+ return {
1703
+ items,
1704
+ path: path2,
1705
+ name: dirName,
1706
+ isDir: true,
1707
+ size: stats.size,
1708
+ modified: stats.mtime.toISOString(),
1709
+ mode: stats.mode,
1710
+ numDirs,
1711
+ numFiles,
1712
+ sorting: { by: "name", asc: true }
1713
+ };
1714
+ }
1715
+ async function getFileInfo(path2) {
1716
+ const absolutePath = await resolveSafePath(path2);
1717
+ try {
1718
+ const name = path2.split("/").pop() || "";
1719
+ return await buildFileItem(absolutePath, name, path2);
1720
+ } catch (err) {
1721
+ if (err.code === "ENOENT") {
1722
+ throw createError(`File not found: ${path2}`, 404, "NOT_FOUND");
1723
+ }
1724
+ throw createError(`Failed to get file info: ${err.message}`, 500, "FS_ERROR");
1725
+ }
1726
+ }
1727
+ async function downloadFile(path2) {
1728
+ const absolutePath = await resolveSafePath(path2);
1729
+ try {
1730
+ const buffer = await readFile(absolutePath);
1731
+ return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
1732
+ } catch (err) {
1733
+ if (err.code === "ENOENT") {
1734
+ throw createError(`File not found: ${path2}`, 404, "NOT_FOUND");
1735
+ }
1736
+ if (err.code === "EACCES") {
1737
+ throw createError("Permission denied", 403, "PERMISSION_DENIED");
1738
+ }
1739
+ throw createError(`Failed to read file: ${err.message}`, 500, "FS_ERROR");
1740
+ }
1741
+ }
1742
+ async function uploadFile(path2, content) {
1743
+ const absolutePath = await resolveSafePath(path2);
1744
+ const parentDir = absolutePath.substring(0, absolutePath.lastIndexOf("/"));
1745
+ await mkdir(parentDir, { recursive: true }).catch(() => {
1746
+ });
1747
+ try {
1748
+ await writeFile(absolutePath, Buffer.from(content));
1749
+ } catch (err) {
1750
+ if (err.code === "EACCES") {
1751
+ throw createError("Permission denied", 403, "PERMISSION_DENIED");
1752
+ }
1753
+ throw createError(`Failed to write file: ${err.message}`, 500, "FS_ERROR");
1754
+ }
1755
+ }
1756
+ async function deleteFile(path2) {
1757
+ const absolutePath = await resolveSafePath(path2);
1758
+ try {
1759
+ await rm(absolutePath, { recursive: true });
1760
+ } catch (err) {
1761
+ if (err.code === "ENOENT") {
1762
+ throw createError(`File not found: ${path2}`, 404, "NOT_FOUND");
1763
+ }
1764
+ if (err.code === "EACCES") {
1765
+ throw createError("Permission denied", 403, "PERMISSION_DENIED");
1766
+ }
1767
+ throw createError(`Failed to delete: ${err.message}`, 500, "FS_ERROR");
1768
+ }
1769
+ }
1770
+ async function createFolder(path2) {
1771
+ const absolutePath = await resolveSafePath(path2);
1772
+ try {
1773
+ await mkdir(absolutePath, { recursive: true });
1774
+ } catch (err) {
1775
+ if (err.code === "EACCES") {
1776
+ throw createError("Permission denied", 403, "PERMISSION_DENIED");
1777
+ }
1778
+ if (err.code === "EEXIST") {
1779
+ throw createError("Directory already exists", 409, "ALREADY_EXISTS");
1780
+ }
1781
+ throw createError(`Failed to create directory: ${err.message}`, 500, "FS_ERROR");
1782
+ }
1783
+ }
1784
+ async function renameFile(src, dst) {
1785
+ const absoluteSrc = await resolveSafePath(src);
1786
+ const absoluteDst = await resolveSafePath(dst);
1787
+ const parentDir = absoluteDst.substring(0, absoluteDst.lastIndexOf("/"));
1788
+ await mkdir(parentDir, { recursive: true }).catch(() => {
1789
+ });
1790
+ try {
1791
+ await rename(absoluteSrc, absoluteDst);
1792
+ } catch (err) {
1793
+ if (err.code === "ENOENT") {
1794
+ throw createError(`Source not found: ${src}`, 404, "NOT_FOUND");
1795
+ }
1796
+ if (err.code === "EACCES") {
1797
+ throw createError("Permission denied", 403, "PERMISSION_DENIED");
1798
+ }
1799
+ throw createError(`Failed to rename: ${err.message}`, 500, "FS_ERROR");
1800
+ }
1801
+ }
1802
+ function sanitizePath(path2) {
1803
+ if (typeof path2 !== "string" || path2.length === 0) {
1804
+ return "/";
1805
+ }
1806
+ let normalized = posix.normalize(path2);
1807
+ if (!normalized.startsWith("/")) {
1808
+ normalized = "/" + normalized;
1809
+ }
1810
+ const parts = normalized.split("/").filter((part) => part !== "" && part !== ".");
1811
+ const safeParts = [];
1812
+ for (const part of parts) {
1813
+ if (part === "..") {
1814
+ if (safeParts.length > 0) {
1815
+ safeParts.pop();
1816
+ }
1817
+ } else {
1818
+ safeParts.push(part);
1819
+ }
1820
+ }
1821
+ return "/" + safeParts.join("/");
1822
+ }
1823
+ function isPathSafe(path2) {
1824
+ if (typeof path2 !== "string") {
1825
+ return false;
1826
+ }
1827
+ if (path2.includes("../") || path2.includes("..\\") || path2 === "..") {
1828
+ return false;
1829
+ }
1830
+ if (path2.includes("\0")) {
1831
+ return false;
1832
+ }
1833
+ if (path2.includes("\\")) {
1834
+ return false;
1835
+ }
1836
+ const sanitized = sanitizePath(path2);
1837
+ return path2 === sanitized || path2.endsWith("/") && sanitized === path2.slice(0, -1);
1838
+ }
1839
+ function validatePath(path2, context = "Path") {
1840
+ if (!path2 || typeof path2 !== "string") {
1841
+ throw new Error(`${context} is required`);
1842
+ }
1843
+ if (!isPathSafe(path2)) {
1844
+ throw new Error(`${context} contains invalid characters or traversal attempts`);
1845
+ }
1846
+ return sanitizePath(path2);
1847
+ }
1848
+ function validateFilename(filename) {
1849
+ if (typeof filename !== "string" || filename.length === 0) {
1850
+ return false;
1851
+ }
1852
+ if (filename.includes("/") || filename.includes("\\")) {
1853
+ return false;
1854
+ }
1855
+ if (filename.includes("\0")) {
1856
+ return false;
1857
+ }
1858
+ for (let i = 0; i < filename.length; i++) {
1859
+ const code = filename.charCodeAt(i);
1860
+ if (code >= 0 && code <= 31) {
1861
+ return false;
1862
+ }
1863
+ }
1864
+ const reserved = [
1865
+ "CON",
1866
+ "PRN",
1867
+ "AUX",
1868
+ "NUL",
1869
+ "COM1",
1870
+ "COM2",
1871
+ "COM3",
1872
+ "COM4",
1873
+ "COM5",
1874
+ "COM6",
1875
+ "COM7",
1876
+ "COM8",
1877
+ "COM9",
1878
+ "LPT1",
1879
+ "LPT2",
1880
+ "LPT3",
1881
+ "LPT4",
1882
+ "LPT5",
1883
+ "LPT6",
1884
+ "LPT7",
1885
+ "LPT8",
1886
+ "LPT9"
1887
+ ];
1888
+ const nameUpper = filename.toUpperCase();
1889
+ if (reserved.includes(nameUpper) || reserved.some((res) => nameUpper.startsWith(res + "."))) {
1890
+ return false;
1891
+ }
1892
+ if (filename === "." || filename === "..") {
1893
+ return false;
1894
+ }
1895
+ return true;
1896
+ }
1897
+ const MAX_FILE_SIZE = 100 * 1024 * 1024;
1898
+ const Route$8 = createFileRoute("/api/files/upload")({
1899
+ server: {
1900
+ handlers: {
1901
+ POST: async ({ request }) => {
1902
+ try {
1903
+ const formData = await request.formData();
1904
+ const rawPath = formData.get("path");
1905
+ if (!rawPath) {
1906
+ return json(
1907
+ {
1908
+ error: "path parameter is required",
1909
+ code: "MISSING_PATH"
1910
+ },
1911
+ { status: 400 }
1912
+ );
1913
+ }
1914
+ const path2 = validatePath(rawPath, "Path parameter");
1915
+ const files = [];
1916
+ for (const [key, value] of formData.entries()) {
1917
+ if (key === "file" || key.startsWith("file")) {
1918
+ if (value instanceof File) {
1919
+ files.push(value);
1920
+ }
1921
+ }
1922
+ }
1923
+ if (files.length === 0) {
1924
+ return json(
1925
+ {
1926
+ error: "At least one file is required",
1927
+ code: "NO_FILES"
1928
+ },
1929
+ { status: 400 }
1930
+ );
1931
+ }
1932
+ const uploadedFiles = [];
1933
+ for (const file of files) {
1934
+ if (file.size > MAX_FILE_SIZE) {
1935
+ return json(
1936
+ {
1937
+ error: `File "${file.name}" is too large. Maximum size is ${MAX_FILE_SIZE / 1024 / 1024}MB`,
1938
+ code: "FILE_TOO_LARGE"
1939
+ },
1940
+ { status: 413 }
1941
+ // Payload Too Large
1942
+ );
1943
+ }
1944
+ if (!validateFilename(file.name)) {
1945
+ return json(
1946
+ {
1947
+ error: `Invalid filename: "${file.name}". Filenames cannot contain path separators or control characters`,
1948
+ code: "INVALID_FILENAME"
1949
+ },
1950
+ { status: 400 }
1951
+ );
1952
+ }
1953
+ const content = await file.arrayBuffer();
1954
+ const fullPath = path2.endsWith("/") ? `${path2}${file.name}` : `${path2}/${file.name}`;
1955
+ await uploadFile(fullPath, content);
1956
+ uploadedFiles.push({
1957
+ filename: file.name,
1958
+ size: content.byteLength,
1959
+ path: fullPath
1960
+ });
1961
+ }
1962
+ return json({
1963
+ ok: true,
1964
+ message: `${uploadedFiles.length} file(s) uploaded successfully`,
1965
+ files: uploadedFiles
1966
+ });
1967
+ } catch (err) {
1968
+ const error = err;
1969
+ if (error.message.includes("invalid characters") || error.message.includes("traversal attempts") || error.message.includes("Invalid filename")) {
1970
+ return json(
1971
+ {
1972
+ error: error.message,
1973
+ code: "VALIDATION_ERROR"
1974
+ },
1975
+ { status: 400 }
1976
+ );
1977
+ }
1978
+ const status = error.status || 500;
1979
+ const code = error.code || "INTERNAL_ERROR";
1980
+ return json(
1981
+ {
1982
+ error: error.message || "An unexpected error occurred",
1983
+ code
1984
+ },
1985
+ { status }
1986
+ );
1987
+ }
1988
+ }
1989
+ }
1990
+ }
1991
+ });
1992
+ const MAX_TEXT_SIZE$1 = 5 * 1024 * 1024;
1993
+ const Route$7 = createFileRoute("/api/files/save")({
1994
+ server: {
1995
+ handlers: {
1996
+ POST: async ({ request }) => {
1997
+ try {
1998
+ const body = await request.json().catch(() => ({}));
1999
+ const rawPath = typeof body.path === "string" ? body.path.trim() : "";
2000
+ const content = typeof body.content === "string" ? body.content : null;
2001
+ if (!rawPath) {
2002
+ return json({ error: "path is required", code: "MISSING_PATH" }, { status: 400 });
2003
+ }
2004
+ if (content === null) {
2005
+ return json({ error: "content is required", code: "MISSING_CONTENT" }, { status: 400 });
2006
+ }
2007
+ const path2 = validatePath(rawPath, "Path parameter");
2008
+ const encoded = new TextEncoder().encode(content);
2009
+ if (encoded.byteLength > MAX_TEXT_SIZE$1) {
2010
+ return json(
2011
+ { error: "Content too large (max 5MB)", code: "CONTENT_TOO_LARGE" },
2012
+ { status: 413 }
2013
+ );
2014
+ }
2015
+ await uploadFile(path2, encoded.buffer);
2016
+ return json({
2017
+ ok: true,
2018
+ message: "File saved successfully",
2019
+ path: path2,
2020
+ size: encoded.byteLength
2021
+ });
2022
+ } catch (err) {
2023
+ const error = err;
2024
+ const status = error.status || 500;
2025
+ const code = error.code || "INTERNAL_ERROR";
2026
+ return json(
2027
+ { error: error.message || "An unexpected error occurred", code },
2028
+ { status }
2029
+ );
2030
+ }
2031
+ }
2032
+ }
2033
+ }
2034
+ });
2035
+ const Route$6 = createFileRoute("/api/files/rename")({
2036
+ server: {
2037
+ handlers: {
2038
+ POST: async ({ request }) => {
2039
+ try {
2040
+ const body = await request.json().catch(() => ({}));
2041
+ const rawSrc = typeof body.src === "string" ? body.src.trim() : "";
2042
+ const rawDst = typeof body.dst === "string" ? body.dst.trim() : "";
2043
+ if (!rawSrc) {
2044
+ return json(
2045
+ {
2046
+ error: "src path is required",
2047
+ code: "MISSING_SRC_PATH"
2048
+ },
2049
+ { status: 400 }
2050
+ );
2051
+ }
2052
+ if (!rawDst) {
2053
+ return json(
2054
+ {
2055
+ error: "dst path is required",
2056
+ code: "MISSING_DST_PATH"
2057
+ },
2058
+ { status: 400 }
2059
+ );
2060
+ }
2061
+ const src = validatePath(rawSrc, "Source path");
2062
+ const dst = validatePath(rawDst, "Destination path");
2063
+ if (src === "/" || src === "") {
2064
+ return json(
2065
+ {
2066
+ error: "Cannot rename the root directory",
2067
+ code: "FORBIDDEN_RENAME_ROOT"
2068
+ },
2069
+ { status: 403 }
2070
+ );
2071
+ }
2072
+ const dstFilename = dst.split("/").pop() || "";
2073
+ if (dstFilename && !validateFilename(dstFilename)) {
2074
+ return json(
2075
+ {
2076
+ error: `Invalid destination filename: "${dstFilename}". Filenames cannot contain path separators or control characters`,
2077
+ code: "INVALID_FILENAME"
2078
+ },
2079
+ { status: 400 }
2080
+ );
2081
+ }
2082
+ let overwriteWarning = false;
2083
+ try {
2084
+ await getFileInfo(dst);
2085
+ overwriteWarning = true;
2086
+ } catch (err) {
2087
+ }
2088
+ const url = new URL(request.url);
2089
+ const allowOverwrite = url.searchParams.get("override") === "true";
2090
+ if (overwriteWarning && !allowOverwrite) {
2091
+ return json(
2092
+ {
2093
+ error: `Destination "${dst}" already exists. Use ?override=true to overwrite`,
2094
+ code: "DESTINATION_EXISTS"
2095
+ },
2096
+ { status: 409 }
2097
+ // Conflict
2098
+ );
2099
+ }
2100
+ await renameFile(src, dst);
2101
+ return json({
2102
+ ok: true,
2103
+ message: overwriteWarning ? "File renamed successfully (existing file overwritten)" : "File renamed successfully",
2104
+ src,
2105
+ dst
2106
+ });
2107
+ } catch (err) {
2108
+ const error = err;
2109
+ if (error.message.includes("invalid characters") || error.message.includes("traversal attempts") || error.message.includes("Invalid destination") || error.message.includes("Cannot rename") || error.message.includes("already exists")) {
2110
+ return json(
2111
+ {
2112
+ error: error.message,
2113
+ code: "VALIDATION_ERROR"
2114
+ },
2115
+ { status: 400 }
2116
+ );
2117
+ }
2118
+ const status = error.status || 500;
2119
+ const code = error.code || "INTERNAL_ERROR";
2120
+ return json(
2121
+ {
2122
+ error: error.message || "An unexpected error occurred",
2123
+ code
2124
+ },
2125
+ { status }
2126
+ );
2127
+ }
2128
+ }
2129
+ }
2130
+ }
2131
+ });
2132
+ const MAX_TEXT_SIZE = 5 * 1024 * 1024;
2133
+ const TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
2134
+ "txt",
2135
+ "md",
2136
+ "log",
2137
+ "json",
2138
+ "xml",
2139
+ "yaml",
2140
+ "yml",
2141
+ "csv",
2142
+ "ini",
2143
+ "conf",
2144
+ "cfg",
2145
+ "js",
2146
+ "ts",
2147
+ "jsx",
2148
+ "tsx",
2149
+ "py",
2150
+ "java",
2151
+ "cpp",
2152
+ "c",
2153
+ "h",
2154
+ "css",
2155
+ "html",
2156
+ "htm",
2157
+ "php",
2158
+ "rb",
2159
+ "go",
2160
+ "rs",
2161
+ "sh",
2162
+ "bash",
2163
+ "zsh",
2164
+ "toml",
2165
+ "env",
2166
+ "gitignore",
2167
+ "dockerfile",
2168
+ "makefile",
2169
+ "sql",
2170
+ "graphql",
2171
+ "svelte",
2172
+ "vue",
2173
+ "scss",
2174
+ "less",
2175
+ "diff",
2176
+ "patch"
2177
+ ]);
2178
+ const Route$5 = createFileRoute("/api/files/read")({
2179
+ server: {
2180
+ handlers: {
2181
+ GET: async ({ request }) => {
2182
+ try {
2183
+ const url = new URL(request.url);
2184
+ const rawPath = url.searchParams.get("path");
2185
+ if (!rawPath) {
2186
+ return new Response(
2187
+ JSON.stringify({ error: "path parameter is required", code: "MISSING_PATH" }),
2188
+ { status: 400, headers: { "Content-Type": "application/json" } }
2189
+ );
2190
+ }
2191
+ const path2 = validatePath(rawPath, "Path parameter");
2192
+ const fileInfo = await getFileInfo(path2);
2193
+ if (fileInfo.isDir) {
2194
+ return new Response(
2195
+ JSON.stringify({ error: "Cannot read a directory", code: "IS_DIRECTORY" }),
2196
+ { status: 400, headers: { "Content-Type": "application/json" } }
2197
+ );
2198
+ }
2199
+ const ext = fileInfo.extension.toLowerCase();
2200
+ if (!TEXT_EXTENSIONS.has(ext) && ext !== "") {
2201
+ return new Response(
2202
+ JSON.stringify({ error: "File type not supported for text editing", code: "UNSUPPORTED_TYPE" }),
2203
+ { status: 400, headers: { "Content-Type": "application/json" } }
2204
+ );
2205
+ }
2206
+ if (fileInfo.size > MAX_TEXT_SIZE) {
2207
+ return new Response(
2208
+ JSON.stringify({ error: "File too large for text editing (max 5MB)", code: "FILE_TOO_LARGE" }),
2209
+ { status: 413, headers: { "Content-Type": "application/json" } }
2210
+ );
2211
+ }
2212
+ const content = await downloadFile(path2);
2213
+ const text = new TextDecoder("utf-8", { fatal: false }).decode(new Uint8Array(content));
2214
+ return new Response(
2215
+ JSON.stringify({ content: text, name: fileInfo.name, extension: fileInfo.extension, size: fileInfo.size }),
2216
+ { headers: { "Content-Type": "application/json" } }
2217
+ );
2218
+ } catch (err) {
2219
+ const error = err;
2220
+ const status = error.status || 500;
2221
+ const code = error.code || "INTERNAL_ERROR";
2222
+ return new Response(
2223
+ JSON.stringify({ error: error.message || "An unexpected error occurred", code }),
2224
+ { status, headers: { "Content-Type": "application/json" } }
2225
+ );
2226
+ }
2227
+ }
2228
+ }
2229
+ }
2230
+ });
2231
+ function validateFolderName(path2) {
2232
+ const folderName = path2.split("/").pop() || "";
2233
+ if (!folderName) {
2234
+ throw new Error("Folder name cannot be empty");
2235
+ }
2236
+ const invalidChars = /[<>:"|*?]/;
2237
+ if (invalidChars.test(folderName)) {
2238
+ throw new Error(`Folder name contains invalid characters: ${folderName}`);
2239
+ }
2240
+ const systemPaths = [
2241
+ "bin",
2242
+ "boot",
2243
+ "dev",
2244
+ "etc",
2245
+ "lib",
2246
+ "lib64",
2247
+ "mnt",
2248
+ "opt",
2249
+ "proc",
2250
+ "root",
2251
+ "run",
2252
+ "sbin",
2253
+ "srv",
2254
+ "sys",
2255
+ "tmp",
2256
+ "usr",
2257
+ "var",
2258
+ "System",
2259
+ "Windows",
2260
+ "Program Files",
2261
+ "Program Files (x86)"
2262
+ ];
2263
+ if (systemPaths.includes(folderName)) {
2264
+ throw new Error(`Cannot create system directory: ${folderName}`);
2265
+ }
2266
+ if (folderName.trim() === "" || /^\.+$/.test(folderName)) {
2267
+ throw new Error("Invalid folder name");
2268
+ }
2269
+ }
2270
+ const Route$4 = createFileRoute("/api/files/mkdir")({
2271
+ server: {
2272
+ handlers: {
2273
+ POST: async ({ request }) => {
2274
+ try {
2275
+ const body = await request.json().catch(() => ({}));
2276
+ const rawPath = typeof body.path === "string" ? body.path.trim() : "";
2277
+ if (!rawPath) {
2278
+ return json(
2279
+ {
2280
+ error: "path is required",
2281
+ code: "MISSING_PATH"
2282
+ },
2283
+ { status: 400 }
2284
+ );
2285
+ }
2286
+ const path2 = validatePath(rawPath, "Path parameter");
2287
+ validateFolderName(path2);
2288
+ await createFolder(path2);
2289
+ return json({
2290
+ ok: true,
2291
+ message: "Directory created successfully",
2292
+ path: path2
2293
+ });
2294
+ } catch (err) {
2295
+ const error = err;
2296
+ if (error.message.includes("invalid characters") || error.message.includes("traversal attempts") || error.message.includes("Invalid folder") || error.message.includes("Cannot create system") || error.message.includes("Folder name")) {
2297
+ return json(
2298
+ {
2299
+ error: error.message,
2300
+ code: "VALIDATION_ERROR"
2301
+ },
2302
+ { status: 400 }
2303
+ );
2304
+ }
2305
+ const status = error.status || 500;
2306
+ const code = error.code || "INTERNAL_ERROR";
2307
+ return json(
2308
+ {
2309
+ error: error.message || "An unexpected error occurred",
2310
+ code
2311
+ },
2312
+ { status }
2313
+ );
2314
+ }
2315
+ }
2316
+ }
2317
+ }
2318
+ });
2319
+ const Route$3 = createFileRoute("/api/files/list")({
2320
+ server: {
2321
+ handlers: {
2322
+ GET: async ({ request }) => {
2323
+ try {
2324
+ const url = new URL(request.url);
2325
+ const rawPath = url.searchParams.get("path") || "/";
2326
+ const path2 = validatePath(rawPath, "Path parameter");
2327
+ const listing = await listFiles(path2);
2328
+ return json(listing);
2329
+ } catch (err) {
2330
+ const error = err;
2331
+ if (error.message.includes("invalid characters") || error.message.includes("traversal attempts")) {
2332
+ return json(
2333
+ {
2334
+ error: error.message,
2335
+ code: "INVALID_PATH"
2336
+ },
2337
+ { status: 400 }
2338
+ );
2339
+ }
2340
+ const status = error.status || 500;
2341
+ const code = error.code || "INTERNAL_ERROR";
2342
+ return json(
2343
+ {
2344
+ error: error.message || "An unexpected error occurred",
2345
+ code
2346
+ },
2347
+ { status }
2348
+ );
2349
+ }
2350
+ }
2351
+ }
2352
+ }
2353
+ });
2354
+ const Route$2 = createFileRoute("/api/files/info")({
2355
+ server: {
2356
+ handlers: {
2357
+ GET: async ({ request }) => {
2358
+ try {
2359
+ const url = new URL(request.url);
2360
+ const rawPath = url.searchParams.get("path");
2361
+ if (!rawPath) {
2362
+ return json(
2363
+ {
2364
+ error: "path parameter is required",
2365
+ code: "MISSING_PATH"
2366
+ },
2367
+ { status: 400 }
2368
+ );
2369
+ }
2370
+ const path2 = validatePath(rawPath, "Path parameter");
2371
+ const fileInfo = await getFileInfo(path2);
2372
+ return json(fileInfo);
2373
+ } catch (err) {
2374
+ const error = err;
2375
+ if (error.message.includes("invalid characters") || error.message.includes("traversal attempts")) {
2376
+ return json(
2377
+ {
2378
+ error: error.message,
2379
+ code: "INVALID_PATH"
2380
+ },
2381
+ { status: 400 }
2382
+ );
2383
+ }
2384
+ const status = error.status || 500;
2385
+ const code = error.code || "INTERNAL_ERROR";
2386
+ return json(
2387
+ {
2388
+ error: error.message || "An unexpected error occurred",
2389
+ code
2390
+ },
2391
+ { status }
2392
+ );
2393
+ }
2394
+ }
2395
+ }
2396
+ }
2397
+ });
2398
+ function getContentType(filename) {
2399
+ const ext = filename.split(".").pop()?.toLowerCase() || "";
2400
+ const mimeTypes = {
2401
+ // Text files
2402
+ "txt": "text/plain",
2403
+ "md": "text/markdown",
2404
+ "html": "text/html",
2405
+ "css": "text/css",
2406
+ "js": "text/javascript",
2407
+ "json": "application/json",
2408
+ "xml": "application/xml",
2409
+ "csv": "text/csv",
2410
+ "yaml": "application/x-yaml",
2411
+ "yml": "application/x-yaml",
2412
+ // Programming languages
2413
+ "ts": "application/typescript",
2414
+ "tsx": "application/typescript",
2415
+ "py": "text/x-python",
2416
+ // Images
2417
+ "png": "image/png",
2418
+ "jpg": "image/jpeg",
2419
+ "jpeg": "image/jpeg",
2420
+ "gif": "image/gif",
2421
+ "webp": "image/webp",
2422
+ "svg": "image/svg+xml",
2423
+ // Audio/Video
2424
+ "mp3": "audio/mpeg",
2425
+ "mp4": "video/mp4",
2426
+ // Documents
2427
+ "pdf": "application/pdf",
2428
+ "doc": "application/msword",
2429
+ "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
2430
+ "xls": "application/vnd.ms-excel",
2431
+ "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
2432
+ "ppt": "application/vnd.ms-powerpoint",
2433
+ "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
2434
+ // Archives
2435
+ "zip": "application/zip",
2436
+ "tar.gz": "application/gzip",
2437
+ "gz": "application/gzip",
2438
+ // Fonts
2439
+ "woff": "font/woff",
2440
+ "woff2": "font/woff2",
2441
+ "ttf": "font/ttf",
2442
+ "otf": "font/otf"
2443
+ };
2444
+ return mimeTypes[ext] || "application/octet-stream";
2445
+ }
2446
+ function encodeFilename(filename) {
2447
+ const encodedFilename = encodeURIComponent(filename);
2448
+ return `filename*=UTF-8''${encodedFilename}`;
2449
+ }
2450
+ function isStaticAsset(filename) {
2451
+ const ext = filename.split(".").pop()?.toLowerCase() || "";
2452
+ const staticExts = ["png", "jpg", "jpeg", "gif", "webp", "svg", "css", "js", "woff", "woff2", "ttf", "otf"];
2453
+ return staticExts.includes(ext);
2454
+ }
2455
+ const Route$1 = createFileRoute("/api/files/download")({
2456
+ server: {
2457
+ handlers: {
2458
+ GET: async ({ request }) => {
2459
+ try {
2460
+ const url = new URL(request.url);
2461
+ const rawPath = url.searchParams.get("path");
2462
+ if (!rawPath) {
2463
+ return new Response(
2464
+ JSON.stringify({
2465
+ error: "path parameter is required",
2466
+ code: "MISSING_PATH"
2467
+ }),
2468
+ {
2469
+ status: 400,
2470
+ headers: { "Content-Type": "application/json" }
2471
+ }
2472
+ );
2473
+ }
2474
+ const path2 = validatePath(rawPath, "Path parameter");
2475
+ const fileInfo = await getFileInfo(path2);
2476
+ const content = await downloadFile(path2);
2477
+ const contentType = getContentType(fileInfo.name);
2478
+ const contentDisposition = `attachment; ${encodeFilename(fileInfo.name)}`;
2479
+ const headers = {
2480
+ "Content-Type": contentType,
2481
+ "Content-Disposition": contentDisposition,
2482
+ "Content-Length": content.byteLength.toString()
2483
+ };
2484
+ if (isStaticAsset(fileInfo.name)) {
2485
+ headers["Cache-Control"] = "public, max-age=31536000";
2486
+ } else {
2487
+ headers["Cache-Control"] = "no-cache";
2488
+ }
2489
+ return new Response(content, { headers });
2490
+ } catch (err) {
2491
+ const error = err;
2492
+ if (error.message.includes("invalid characters") || error.message.includes("traversal attempts")) {
2493
+ return new Response(
2494
+ JSON.stringify({
2495
+ error: error.message,
2496
+ code: "INVALID_PATH"
2497
+ }),
2498
+ {
2499
+ status: 400,
2500
+ headers: { "Content-Type": "application/json" }
2501
+ }
2502
+ );
2503
+ }
2504
+ const status = error.status || 500;
2505
+ const code = error.code || "INTERNAL_ERROR";
2506
+ return new Response(
2507
+ JSON.stringify({
2508
+ error: error.message || "An unexpected error occurred",
2509
+ code
2510
+ }),
2511
+ {
2512
+ status,
2513
+ headers: { "Content-Type": "application/json" }
2514
+ }
2515
+ );
2516
+ }
2517
+ }
2518
+ }
2519
+ }
2520
+ });
2521
+ const Route = createFileRoute("/api/files/delete")({
2522
+ server: {
2523
+ handlers: {
2524
+ DELETE: async ({ request }) => {
2525
+ try {
2526
+ const url = new URL(request.url);
2527
+ const rawPath = url.searchParams.get("path");
2528
+ if (!rawPath) {
2529
+ return json(
2530
+ {
2531
+ error: "path parameter is required",
2532
+ code: "MISSING_PATH"
2533
+ },
2534
+ { status: 400 }
2535
+ );
2536
+ }
2537
+ const path2 = validatePath(rawPath, "Path parameter");
2538
+ if (path2 === "/" || path2 === "") {
2539
+ return json(
2540
+ {
2541
+ error: "Cannot delete the root directory",
2542
+ code: "FORBIDDEN_DELETE_ROOT"
2543
+ },
2544
+ { status: 403 }
2545
+ // Forbidden
2546
+ );
2547
+ }
2548
+ await deleteFile(path2);
2549
+ return json({
2550
+ ok: true,
2551
+ message: "File deleted successfully",
2552
+ path: path2
2553
+ });
2554
+ } catch (err) {
2555
+ const error = err;
2556
+ if (error.message.includes("invalid characters") || error.message.includes("traversal attempts") || error.message.includes("Cannot delete")) {
2557
+ return json(
2558
+ {
2559
+ error: error.message,
2560
+ code: "VALIDATION_ERROR"
2561
+ },
2562
+ { status: 400 }
2563
+ );
2564
+ }
2565
+ const status = error.status || 500;
2566
+ const code = error.code || "INTERNAL_ERROR";
2567
+ return json(
2568
+ {
2569
+ error: error.message || "An unexpected error occurred",
2570
+ code
2571
+ },
2572
+ { status }
2573
+ );
2574
+ }
2575
+ }
2576
+ }
2577
+ }
2578
+ });
2579
+ const NewRoute = Route$o.update({
2580
+ id: "/new",
2581
+ path: "/new",
2582
+ getParentRoute: () => Route$p
2583
+ });
2584
+ const FilesRoute = Route$n.update({
2585
+ id: "/files",
2586
+ path: "/files",
2587
+ getParentRoute: () => Route$p
2588
+ });
2589
+ const ConnectRoute = Route$m.update({
2590
+ id: "/connect",
2591
+ path: "/connect",
2592
+ getParentRoute: () => Route$p
2593
+ });
2594
+ const IndexRoute = Route$l.update({
2595
+ id: "/",
2596
+ path: "/",
2597
+ getParentRoute: () => Route$p
2598
+ });
2599
+ const ChatSessionKeyRoute = Route$k.update({
2600
+ id: "/chat/$sessionKey",
2601
+ path: "/chat/$sessionKey",
2602
+ getParentRoute: () => Route$p
2603
+ });
2604
+ const ApiTtsRoute = Route$j.update({
2605
+ id: "/api/tts",
2606
+ path: "/api/tts",
2607
+ getParentRoute: () => Route$p
2608
+ });
2609
+ const ApiStreamRoute = Route$i.update({
2610
+ id: "/api/stream",
2611
+ path: "/api/stream",
2612
+ getParentRoute: () => Route$p
2613
+ });
2614
+ const ApiSessionsRoute = Route$h.update({
2615
+ id: "/api/sessions",
2616
+ path: "/api/sessions",
2617
+ getParentRoute: () => Route$p
2618
+ });
2619
+ const ApiSendRoute = Route$g.update({
2620
+ id: "/api/send",
2621
+ path: "/api/send",
2622
+ getParentRoute: () => Route$p
2623
+ });
2624
+ const ApiPingRoute = Route$f.update({
2625
+ id: "/api/ping",
2626
+ path: "/api/ping",
2627
+ getParentRoute: () => Route$p
2628
+ });
2629
+ const ApiPersonasRoute = Route$e.update({
2630
+ id: "/api/personas",
2631
+ path: "/api/personas",
2632
+ getParentRoute: () => Route$p
2633
+ });
2634
+ const ApiPathsRoute = Route$d.update({
2635
+ id: "/api/paths",
2636
+ path: "/api/paths",
2637
+ getParentRoute: () => Route$p
2638
+ });
2639
+ const ApiModelsRoute = Route$c.update({
2640
+ id: "/api/models",
2641
+ path: "/api/models",
2642
+ getParentRoute: () => Route$p
2643
+ });
2644
+ const ApiLlmFeaturesRoute = Route$b.update({
2645
+ id: "/api/llm-features",
2646
+ path: "/api/llm-features",
2647
+ getParentRoute: () => Route$p
2648
+ });
2649
+ const ApiHistoryRoute = Route$a.update({
2650
+ id: "/api/history",
2651
+ path: "/api/history",
2652
+ getParentRoute: () => Route$p
2653
+ });
2654
+ const ApiFollowUpsRoute = Route$9.update({
2655
+ id: "/api/follow-ups",
2656
+ path: "/api/follow-ups",
2657
+ getParentRoute: () => Route$p
2658
+ });
2659
+ const ApiFilesUploadRoute = Route$8.update({
2660
+ id: "/api/files/upload",
2661
+ path: "/api/files/upload",
2662
+ getParentRoute: () => Route$p
2663
+ });
2664
+ const ApiFilesSaveRoute = Route$7.update({
2665
+ id: "/api/files/save",
2666
+ path: "/api/files/save",
2667
+ getParentRoute: () => Route$p
2668
+ });
2669
+ const ApiFilesRenameRoute = Route$6.update({
2670
+ id: "/api/files/rename",
2671
+ path: "/api/files/rename",
2672
+ getParentRoute: () => Route$p
2673
+ });
2674
+ const ApiFilesReadRoute = Route$5.update({
2675
+ id: "/api/files/read",
2676
+ path: "/api/files/read",
2677
+ getParentRoute: () => Route$p
2678
+ });
2679
+ const ApiFilesMkdirRoute = Route$4.update({
2680
+ id: "/api/files/mkdir",
2681
+ path: "/api/files/mkdir",
2682
+ getParentRoute: () => Route$p
2683
+ });
2684
+ const ApiFilesListRoute = Route$3.update({
2685
+ id: "/api/files/list",
2686
+ path: "/api/files/list",
2687
+ getParentRoute: () => Route$p
2688
+ });
2689
+ const ApiFilesInfoRoute = Route$2.update({
2690
+ id: "/api/files/info",
2691
+ path: "/api/files/info",
2692
+ getParentRoute: () => Route$p
2693
+ });
2694
+ const ApiFilesDownloadRoute = Route$1.update({
2695
+ id: "/api/files/download",
2696
+ path: "/api/files/download",
2697
+ getParentRoute: () => Route$p
2698
+ });
2699
+ const ApiFilesDeleteRoute = Route.update({
2700
+ id: "/api/files/delete",
2701
+ path: "/api/files/delete",
2702
+ getParentRoute: () => Route$p
2703
+ });
2704
+ const rootRouteChildren = {
2705
+ IndexRoute,
2706
+ ConnectRoute,
2707
+ FilesRoute,
2708
+ NewRoute,
2709
+ ApiFollowUpsRoute,
2710
+ ApiHistoryRoute,
2711
+ ApiLlmFeaturesRoute,
2712
+ ApiModelsRoute,
2713
+ ApiPathsRoute,
2714
+ ApiPersonasRoute,
2715
+ ApiPingRoute,
2716
+ ApiSendRoute,
2717
+ ApiSessionsRoute,
2718
+ ApiStreamRoute,
2719
+ ApiTtsRoute,
2720
+ ChatSessionKeyRoute,
2721
+ ApiFilesDeleteRoute,
2722
+ ApiFilesDownloadRoute,
2723
+ ApiFilesInfoRoute,
2724
+ ApiFilesListRoute,
2725
+ ApiFilesMkdirRoute,
2726
+ ApiFilesReadRoute,
2727
+ ApiFilesRenameRoute,
2728
+ ApiFilesSaveRoute,
2729
+ ApiFilesUploadRoute
2730
+ };
2731
+ const routeTree = Route$p._addFileChildren(rootRouteChildren)._addFileTypes();
2732
+ const getRouter = () => {
2733
+ const router2 = createRouter({
2734
+ routeTree,
2735
+ context: {},
2736
+ scrollRestoration: true,
2737
+ defaultPreloadStaleTime: 0
2738
+ });
2739
+ return router2;
2740
+ };
2741
+ const router = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2742
+ __proto__: null,
2743
+ getRouter
2744
+ }, Symbol.toStringTag, { value: "Module" }));
2745
+ export {
2746
+ Route$l as R,
2747
+ Route$k as a,
2748
+ router as r
2749
+ };