auvezy-terminal-remote 0.7.6 → 0.8.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 (374) hide show
  1. package/dist/cli.js +1614 -289
  2. package/frontend-dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  3. package/frontend-dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  4. package/frontend-dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  5. package/frontend-dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  6. package/frontend-dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  7. package/frontend-dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  8. package/frontend-dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  9. package/frontend-dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  10. package/frontend-dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  11. package/frontend-dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  12. package/frontend-dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  13. package/frontend-dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  14. package/frontend-dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  15. package/frontend-dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  16. package/frontend-dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  17. package/frontend-dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  18. package/frontend-dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  19. package/frontend-dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  20. package/frontend-dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  21. package/frontend-dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  22. package/frontend-dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  23. package/frontend-dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  24. package/frontend-dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  25. package/frontend-dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  26. package/frontend-dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  27. package/frontend-dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  28. package/frontend-dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  29. package/frontend-dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  30. package/frontend-dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  31. package/frontend-dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  32. package/frontend-dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  33. package/frontend-dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  34. package/frontend-dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  35. package/frontend-dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  36. package/frontend-dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  37. package/frontend-dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  38. package/frontend-dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  39. package/frontend-dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  40. package/frontend-dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  41. package/frontend-dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  42. package/frontend-dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  43. package/frontend-dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  44. package/frontend-dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  45. package/frontend-dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  46. package/frontend-dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  47. package/frontend-dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  48. package/frontend-dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  49. package/frontend-dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  50. package/frontend-dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  51. package/frontend-dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  52. package/frontend-dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  53. package/frontend-dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  54. package/frontend-dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  55. package/frontend-dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  56. package/frontend-dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  57. package/frontend-dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  58. package/frontend-dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  59. package/frontend-dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  60. package/frontend-dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  61. package/frontend-dist/assets/MarkdownPreview-CF6sudmV.js +293 -0
  62. package/frontend-dist/assets/MarkdownPreview-CKe8gJP-.css +1 -0
  63. package/frontend-dist/assets/abap-BdImnpbu.js +1 -0
  64. package/frontend-dist/assets/actionscript-3-CoDkCxhg.js +1 -0
  65. package/frontend-dist/assets/ada-bCR0ucgS.js +1 -0
  66. package/frontend-dist/assets/andromeeda-C4gqWexZ.js +1 -0
  67. package/frontend-dist/assets/angular-html-DA-rfuFy.js +1 -0
  68. package/frontend-dist/assets/angular-ts-BrjP3tb8.js +1 -0
  69. package/frontend-dist/assets/apache-Pmp26Uib.js +1 -0
  70. package/frontend-dist/assets/apex-Dqspr-GT.js +1 -0
  71. package/frontend-dist/assets/apl-CORt7UWP.js +1 -0
  72. package/frontend-dist/assets/applescript-Co6uUVPk.js +1 -0
  73. package/frontend-dist/assets/ara-BRHolxvo.js +1 -0
  74. package/frontend-dist/assets/asciidoc-Ve4PFQV2.js +1 -0
  75. package/frontend-dist/assets/asm-D_Q5rh1f.js +1 -0
  76. package/frontend-dist/assets/astro-HNnZUWAn.js +1 -0
  77. package/frontend-dist/assets/aurora-x-D-2ljcwZ.js +1 -0
  78. package/frontend-dist/assets/awk-DMzUqQB5.js +1 -0
  79. package/frontend-dist/assets/ayu-dark-DYE7WIF3.js +1 -0
  80. package/frontend-dist/assets/ayu-light-BA47KaF1.js +1 -0
  81. package/frontend-dist/assets/ayu-mirage-32ctXXKs.js +1 -0
  82. package/frontend-dist/assets/ballerina-BFfxhgS-.js +1 -0
  83. package/frontend-dist/assets/bat-BkioyH1T.js +1 -0
  84. package/frontend-dist/assets/beancount-k_qm7-4y.js +1 -0
  85. package/frontend-dist/assets/berry-uYugtg8r.js +1 -0
  86. package/frontend-dist/assets/bibtex-CHM0blh-.js +1 -0
  87. package/frontend-dist/assets/bicep-Bmn6On1c.js +1 -0
  88. package/frontend-dist/assets/bird2-BIv1doCn.js +1 -0
  89. package/frontend-dist/assets/blade-2xfisSek.js +1 -0
  90. package/frontend-dist/assets/bsl-BO_Y6i37.js +1 -0
  91. package/frontend-dist/assets/c-BIGW1oBm.js +1 -0
  92. package/frontend-dist/assets/c3-MRO5bC_T.js +1 -0
  93. package/frontend-dist/assets/cadence-Bv_4Rxtq.js +1 -0
  94. package/frontend-dist/assets/cairo-KRGpt6FW.js +1 -0
  95. package/frontend-dist/assets/catppuccin-frappe-DFWUc33u.js +1 -0
  96. package/frontend-dist/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
  97. package/frontend-dist/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
  98. package/frontend-dist/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
  99. package/frontend-dist/assets/clarity-D53aC0YG.js +1 -0
  100. package/frontend-dist/assets/clojure-P80f7IUj.js +1 -0
  101. package/frontend-dist/assets/cmake-D1j8_8rp.js +1 -0
  102. package/frontend-dist/assets/cobol-nBiQ_Alo.js +1 -0
  103. package/frontend-dist/assets/codeowners-Bp6g37R7.js +1 -0
  104. package/frontend-dist/assets/codeql-DsOJ9woJ.js +1 -0
  105. package/frontend-dist/assets/coffee-Ch7k5sss.js +1 -0
  106. package/frontend-dist/assets/common-lisp-Cg-RD9OK.js +1 -0
  107. package/frontend-dist/assets/coq-DkFqJrB1.js +1 -0
  108. package/frontend-dist/assets/cpp-UfJy6YNI.js +1 -0
  109. package/frontend-dist/assets/crystal-DGywbUpC.js +1 -0
  110. package/frontend-dist/assets/csharp-DSvCPggb.js +1 -0
  111. package/frontend-dist/assets/css-CLj8gQPS.js +1 -0
  112. package/frontend-dist/assets/csv-fuZLfV_i.js +1 -0
  113. package/frontend-dist/assets/cue-D82EKSYY.js +1 -0
  114. package/frontend-dist/assets/cypher-COkxafJQ.js +1 -0
  115. package/frontend-dist/assets/d-85-TOEBH.js +1 -0
  116. package/frontend-dist/assets/dark-plus-C3mMm8J8.js +1 -0
  117. package/frontend-dist/assets/dart-bE4Kk8sk.js +1 -0
  118. package/frontend-dist/assets/dax-CEL-wOlO.js +1 -0
  119. package/frontend-dist/assets/desktop-BmXAJ9_W.js +1 -0
  120. package/frontend-dist/assets/diff-D97Zzqfu.js +1 -0
  121. package/frontend-dist/assets/docker-BcOcwvcX.js +1 -0
  122. package/frontend-dist/assets/dotenv-Da5cRb03.js +1 -0
  123. package/frontend-dist/assets/dracula-BzJJZx-M.js +1 -0
  124. package/frontend-dist/assets/dracula-soft-BXkSAIEj.js +1 -0
  125. package/frontend-dist/assets/dream-maker-BtqSS_iP.js +1 -0
  126. package/frontend-dist/assets/edge-FbVlp4U3.js +1 -0
  127. package/frontend-dist/assets/elixir-CkH2-t6x.js +1 -0
  128. package/frontend-dist/assets/elm-DbKCFpqz.js +1 -0
  129. package/frontend-dist/assets/emacs-lisp-CXvaQtF9.js +1 -0
  130. package/frontend-dist/assets/erb-Dm6A9KJ5.js +1 -0
  131. package/frontend-dist/assets/erlang-DsQrWhSR.js +1 -0
  132. package/frontend-dist/assets/{eruda-Chf2H6-5.js → eruda-I4dOyDju.js} +1 -1
  133. package/frontend-dist/assets/everforest-dark-BgDCqdQA.js +1 -0
  134. package/frontend-dist/assets/everforest-light-C8M2exoo.js +1 -0
  135. package/frontend-dist/assets/fennel-BYunw83y.js +1 -0
  136. package/frontend-dist/assets/fish-BvzEVeQv.js +1 -0
  137. package/frontend-dist/assets/fluent-C4IJs8-o.js +1 -0
  138. package/frontend-dist/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
  139. package/frontend-dist/assets/fortran-free-form-BxgE0vQu.js +1 -0
  140. package/frontend-dist/assets/fsharp-CXgrBDvD.js +1 -0
  141. package/frontend-dist/assets/gdresource-BOOCDP_w.js +1 -0
  142. package/frontend-dist/assets/gdscript-C5YyOfLZ.js +1 -0
  143. package/frontend-dist/assets/gdshader-DkwncUOv.js +1 -0
  144. package/frontend-dist/assets/genie-D0YGMca9.js +1 -0
  145. package/frontend-dist/assets/gherkin-DyxjwDmM.js +1 -0
  146. package/frontend-dist/assets/git-commit-F4YmCXRG.js +1 -0
  147. package/frontend-dist/assets/git-rebase-r7XF79zn.js +1 -0
  148. package/frontend-dist/assets/github-dark-DHJKELXO.js +1 -0
  149. package/frontend-dist/assets/github-dark-default-Cuk6v7N8.js +1 -0
  150. package/frontend-dist/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  151. package/frontend-dist/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  152. package/frontend-dist/assets/github-light-DAi9KRSo.js +1 -0
  153. package/frontend-dist/assets/github-light-default-D7oLnXFd.js +1 -0
  154. package/frontend-dist/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  155. package/frontend-dist/assets/gleam-BspZqrRM.js +1 -0
  156. package/frontend-dist/assets/glimmer-js-ByusRIyA.js +1 -0
  157. package/frontend-dist/assets/glimmer-ts-BfAWNZQY.js +1 -0
  158. package/frontend-dist/assets/glsl-DplSGwfg.js +1 -0
  159. package/frontend-dist/assets/gn-n2N0HUVH.js +1 -0
  160. package/frontend-dist/assets/gnuplot-DdkO51Og.js +1 -0
  161. package/frontend-dist/assets/go-C27-OAKa.js +1 -0
  162. package/frontend-dist/assets/graphql-ChdNCCLP.js +1 -0
  163. package/frontend-dist/assets/groovy-gcz8RCvz.js +1 -0
  164. package/frontend-dist/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  165. package/frontend-dist/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  166. package/frontend-dist/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  167. package/frontend-dist/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  168. package/frontend-dist/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  169. package/frontend-dist/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  170. package/frontend-dist/assets/hack-DbPARsA_.js +1 -0
  171. package/frontend-dist/assets/haml-D5jkg6IW.js +1 -0
  172. package/frontend-dist/assets/handlebars-BpdQsYii.js +1 -0
  173. package/frontend-dist/assets/haskell-Df6bDoY_.js +1 -0
  174. package/frontend-dist/assets/haxe-CzTSHFRz.js +1 -0
  175. package/frontend-dist/assets/hcl-BWvSN4gD.js +1 -0
  176. package/frontend-dist/assets/hjson-D5-asLiD.js +1 -0
  177. package/frontend-dist/assets/hlsl-D3lLCCz7.js +1 -0
  178. package/frontend-dist/assets/horizon-BUw7H-hv.js +1 -0
  179. package/frontend-dist/assets/horizon-bright-CUuTKBJd.js +1 -0
  180. package/frontend-dist/assets/houston-DnULxvSX.js +1 -0
  181. package/frontend-dist/assets/html-derivative-DlHx6ybY.js +1 -0
  182. package/frontend-dist/assets/html-pp8916En.js +1 -0
  183. package/frontend-dist/assets/http-jrhK8wxY.js +1 -0
  184. package/frontend-dist/assets/hurl-irOxFIW8.js +1 -0
  185. package/frontend-dist/assets/hxml-Bvhsp5Yf.js +1 -0
  186. package/frontend-dist/assets/hy-DFXneXwc.js +1 -0
  187. package/frontend-dist/assets/imba-DGztddWO.js +1 -0
  188. package/frontend-dist/assets/index-3yH0kVT5.css +32 -0
  189. package/frontend-dist/assets/index-DNdXwx-1.js +153 -0
  190. package/frontend-dist/assets/index-QyYOrA8J.js +391 -0
  191. package/frontend-dist/assets/index-XrxXnMBj.js +1 -0
  192. package/frontend-dist/assets/ini-BEwlwnbL.js +1 -0
  193. package/frontend-dist/assets/java-CylS5w8V.js +1 -0
  194. package/frontend-dist/assets/javascript-wDzz0qaB.js +1 -0
  195. package/frontend-dist/assets/jinja-f2NsQr07.js +1 -0
  196. package/frontend-dist/assets/jison-wvAkD_A8.js +1 -0
  197. package/frontend-dist/assets/json-Cp-IABpG.js +1 -0
  198. package/frontend-dist/assets/json5-C9tS-k6U.js +1 -0
  199. package/frontend-dist/assets/jsonc-Des-eS-w.js +1 -0
  200. package/frontend-dist/assets/jsonl-DcaNXYhu.js +1 -0
  201. package/frontend-dist/assets/jsonnet-DFQXde-d.js +1 -0
  202. package/frontend-dist/assets/jssm-C2t-YnRu.js +1 -0
  203. package/frontend-dist/assets/jsx-g9-lgVsj.js +1 -0
  204. package/frontend-dist/assets/julia-D7OTSIA_.js +1 -0
  205. package/frontend-dist/assets/just-CUsbIsdP.js +1 -0
  206. package/frontend-dist/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  207. package/frontend-dist/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  208. package/frontend-dist/assets/kanagawa-wave-DWedfzmr.js +1 -0
  209. package/frontend-dist/assets/kdl-DV7GczEv.js +1 -0
  210. package/frontend-dist/assets/kotlin-BdnUsdx6.js +1 -0
  211. package/frontend-dist/assets/kusto-wEQ09or8.js +1 -0
  212. package/frontend-dist/assets/laserwave-DUszq2jm.js +1 -0
  213. package/frontend-dist/assets/latex-CaSxy8MP.js +1 -0
  214. package/frontend-dist/assets/lean-BZvkOJ9d.js +1 -0
  215. package/frontend-dist/assets/less-B1dDrJ26.js +1 -0
  216. package/frontend-dist/assets/light-plus-B7mTdjB0.js +1 -0
  217. package/frontend-dist/assets/liquid-C0sCDyMI.js +1 -0
  218. package/frontend-dist/assets/llvm-DjAJT7YJ.js +1 -0
  219. package/frontend-dist/assets/log-2UxHyX5q.js +1 -0
  220. package/frontend-dist/assets/logo-BtOb2qkB.js +1 -0
  221. package/frontend-dist/assets/lua-BaeVxFsk.js +1 -0
  222. package/frontend-dist/assets/luau-KW6xsasC.js +1 -0
  223. package/frontend-dist/assets/make-CHLpvVh8.js +1 -0
  224. package/frontend-dist/assets/markdown-Cvjx9yec.js +1 -0
  225. package/frontend-dist/assets/marko-DjSrsDqO.js +1 -0
  226. package/frontend-dist/assets/material-theme-D5KoaKCx.js +1 -0
  227. package/frontend-dist/assets/material-theme-darker-BfHTSMKl.js +1 -0
  228. package/frontend-dist/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  229. package/frontend-dist/assets/material-theme-ocean-CyktbL80.js +1 -0
  230. package/frontend-dist/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  231. package/frontend-dist/assets/matlab-D7o27uSR.js +1 -0
  232. package/frontend-dist/assets/mdc-DTYItulj.js +1 -0
  233. package/frontend-dist/assets/mdx-Cmh6b_Ma.js +1 -0
  234. package/frontend-dist/assets/mermaid-mWjccvbQ.js +1 -0
  235. package/frontend-dist/assets/min-dark-CafNBF8u.js +1 -0
  236. package/frontend-dist/assets/min-light-CTRr51gU.js +1 -0
  237. package/frontend-dist/assets/mipsasm-CKIfxQSi.js +1 -0
  238. package/frontend-dist/assets/mojo-rZm6bMo-.js +1 -0
  239. package/frontend-dist/assets/monokai-D4h5O-jR.js +1 -0
  240. package/frontend-dist/assets/moonbit-_H4v1dQx.js +1 -0
  241. package/frontend-dist/assets/move-IF9eRakj.js +1 -0
  242. package/frontend-dist/assets/narrat-DRg8JJMk.js +1 -0
  243. package/frontend-dist/assets/nextflow-C-mBbutL.js +1 -0
  244. package/frontend-dist/assets/nextflow-groovy-vE_lwT2v.js +1 -0
  245. package/frontend-dist/assets/nginx-BpAMiNFr.js +1 -0
  246. package/frontend-dist/assets/night-owl-C39BiMTA.js +1 -0
  247. package/frontend-dist/assets/night-owl-light-CMTm3GFP.js +1 -0
  248. package/frontend-dist/assets/nim-BIad80T-.js +1 -0
  249. package/frontend-dist/assets/nix-CwoSXNpI.js +1 -0
  250. package/frontend-dist/assets/nord-Ddv68eIx.js +1 -0
  251. package/frontend-dist/assets/nushell-Cz2AlsmD.js +1 -0
  252. package/frontend-dist/assets/objective-c-DXmwc3jG.js +1 -0
  253. package/frontend-dist/assets/objective-cpp-CLxacb5B.js +1 -0
  254. package/frontend-dist/assets/ocaml-C0hk2d4L.js +1 -0
  255. package/frontend-dist/assets/odin-BBf5iR-q.js +1 -0
  256. package/frontend-dist/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  257. package/frontend-dist/assets/one-light-C3Wv6jpd.js +1 -0
  258. package/frontend-dist/assets/openscad-C4EeE6gA.js +1 -0
  259. package/frontend-dist/assets/pascal-D93ZcfNL.js +1 -0
  260. package/frontend-dist/assets/perl-B9cMNwum.js +1 -0
  261. package/frontend-dist/assets/php-Csjmro_R.js +1 -0
  262. package/frontend-dist/assets/pkl-u5AG7uiY.js +1 -0
  263. package/frontend-dist/assets/plastic-3e1v2bzS.js +1 -0
  264. package/frontend-dist/assets/plsql-ChMvpjG-.js +1 -0
  265. package/frontend-dist/assets/po-BTJTHyun.js +1 -0
  266. package/frontend-dist/assets/poimandres-CS3Unz2-.js +1 -0
  267. package/frontend-dist/assets/polar-C0HS_06l.js +1 -0
  268. package/frontend-dist/assets/postcss-CXtECtnM.js +1 -0
  269. package/frontend-dist/assets/powerquery-CEu0bR-o.js +1 -0
  270. package/frontend-dist/assets/powershell-Dpen1YoG.js +1 -0
  271. package/frontend-dist/assets/prisma-Dd19v3D-.js +1 -0
  272. package/frontend-dist/assets/prolog-CbFg5uaA.js +1 -0
  273. package/frontend-dist/assets/proto-C7zT0LnQ.js +1 -0
  274. package/frontend-dist/assets/pug-DKIMFp6K.js +1 -0
  275. package/frontend-dist/assets/puppet-BMWR74SV.js +1 -0
  276. package/frontend-dist/assets/purescript-CklMAg4u.js +1 -0
  277. package/frontend-dist/assets/python-B6aJPvgy.js +1 -0
  278. package/frontend-dist/assets/qml-3beO22l8.js +1 -0
  279. package/frontend-dist/assets/qmldir-C8lEn-DE.js +1 -0
  280. package/frontend-dist/assets/qss-IeuSbFQv.js +1 -0
  281. package/frontend-dist/assets/r-Dspwwk_N.js +1 -0
  282. package/frontend-dist/assets/racket-BqYA7rlc.js +1 -0
  283. package/frontend-dist/assets/raku-DXvB9xmW.js +1 -0
  284. package/frontend-dist/assets/razor-BjBPvh-w.js +1 -0
  285. package/frontend-dist/assets/red-bN70gL4F.js +1 -0
  286. package/frontend-dist/assets/reg-C-SQnVFl.js +1 -0
  287. package/frontend-dist/assets/regexp-CDVJQ6XC.js +1 -0
  288. package/frontend-dist/assets/rel-C3B-1QV4.js +1 -0
  289. package/frontend-dist/assets/riscv-BM1_JUlF.js +1 -0
  290. package/frontend-dist/assets/ron-D8l8udqQ.js +1 -0
  291. package/frontend-dist/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
  292. package/frontend-dist/assets/rose-pine-moon-D4_iv3hh.js +1 -0
  293. package/frontend-dist/assets/rose-pine-qdsjHGoJ.js +1 -0
  294. package/frontend-dist/assets/rosmsg-BJDFO7_C.js +1 -0
  295. package/frontend-dist/assets/rst-CpCqk9r5.js +1 -0
  296. package/frontend-dist/assets/ruby-DyJCeAvU.js +1 -0
  297. package/frontend-dist/assets/rust-B1yitclQ.js +1 -0
  298. package/frontend-dist/assets/sas-DEy46yEz.js +1 -0
  299. package/frontend-dist/assets/sass-Cj5Yp3dK.js +1 -0
  300. package/frontend-dist/assets/scala-C151Ov-r.js +1 -0
  301. package/frontend-dist/assets/scheme-C98Dy4si.js +1 -0
  302. package/frontend-dist/assets/scss-D5BDwBP9.js +1 -0
  303. package/frontend-dist/assets/sdbl-DVxCFoDh.js +1 -0
  304. package/frontend-dist/assets/shaderlab-Dg9Lc6iA.js +1 -0
  305. package/frontend-dist/assets/shellscript-Yzrsuije.js +1 -0
  306. package/frontend-dist/assets/shellsession-BADoaaVG.js +1 -0
  307. package/frontend-dist/assets/slack-dark-BthQWCQV.js +1 -0
  308. package/frontend-dist/assets/slack-ochin-DqwNpetd.js +1 -0
  309. package/frontend-dist/assets/smalltalk-BERRCDM3.js +1 -0
  310. package/frontend-dist/assets/snazzy-light-Bw305WKR.js +1 -0
  311. package/frontend-dist/assets/solarized-dark-DXbdFlpD.js +1 -0
  312. package/frontend-dist/assets/solarized-light-L9t79GZl.js +1 -0
  313. package/frontend-dist/assets/solidity-rGO070M0.js +1 -0
  314. package/frontend-dist/assets/soy-8wufbnw4.js +1 -0
  315. package/frontend-dist/assets/sparql-rVzFXLq3.js +1 -0
  316. package/frontend-dist/assets/splunk-BtCnVYZw.js +1 -0
  317. package/frontend-dist/assets/sql-CRqJ_cUM.js +1 -0
  318. package/frontend-dist/assets/ssh-config-_ykCGR6B.js +1 -0
  319. package/frontend-dist/assets/stata-DI20mbqo.js +1 -0
  320. package/frontend-dist/assets/stylus-BEDo0Tqx.js +1 -0
  321. package/frontend-dist/assets/surrealql-Bq5Q-fJD.js +1 -0
  322. package/frontend-dist/assets/svelte-Cy7k_4gC.js +1 -0
  323. package/frontend-dist/assets/swift-D82vCrfD.js +1 -0
  324. package/frontend-dist/assets/synthwave-84-CbfX1IO0.js +1 -0
  325. package/frontend-dist/assets/system-verilog-CnnmHF94.js +1 -0
  326. package/frontend-dist/assets/systemd-4A_iFExJ.js +1 -0
  327. package/frontend-dist/assets/talonscript-CkByrt1z.js +1 -0
  328. package/frontend-dist/assets/tasl-QIJgUcNo.js +1 -0
  329. package/frontend-dist/assets/tcl-dwOrl1Do.js +1 -0
  330. package/frontend-dist/assets/templ-DhtptRzy.js +1 -0
  331. package/frontend-dist/assets/terraform-BETggiCN.js +1 -0
  332. package/frontend-dist/assets/tex-idrVyKtj.js +1 -0
  333. package/frontend-dist/assets/tokyo-night-hegEt444.js +1 -0
  334. package/frontend-dist/assets/toml-vGWfd6FD.js +1 -0
  335. package/frontend-dist/assets/ts-tags-D351s5mN.js +1 -0
  336. package/frontend-dist/assets/tsv-B_m7g4N7.js +1 -0
  337. package/frontend-dist/assets/tsx-COt5Ahok.js +1 -0
  338. package/frontend-dist/assets/turtle-BsS91CYL.js +1 -0
  339. package/frontend-dist/assets/twig-CW1WmMYd.js +1 -0
  340. package/frontend-dist/assets/typescript-BPQ3VLAy.js +1 -0
  341. package/frontend-dist/assets/typespec-CAFt9gP4.js +1 -0
  342. package/frontend-dist/assets/typst-DHCkPAjA.js +1 -0
  343. package/frontend-dist/assets/v-BcVCzyr7.js +1 -0
  344. package/frontend-dist/assets/vala-CsfeWuGM.js +1 -0
  345. package/frontend-dist/assets/vb-D17OF-Vu.js +1 -0
  346. package/frontend-dist/assets/verilog-BQ8w6xss.js +1 -0
  347. package/frontend-dist/assets/vesper-DRje8inN.js +1 -0
  348. package/frontend-dist/assets/vhdl-CeAyd5Ju.js +1 -0
  349. package/frontend-dist/assets/viml-CJc9bBzg.js +1 -0
  350. package/frontend-dist/assets/vitesse-black-Bkuqu6BP.js +1 -0
  351. package/frontend-dist/assets/vitesse-dark-D0r3Knsf.js +1 -0
  352. package/frontend-dist/assets/vitesse-light-CVO1_9PV.js +1 -0
  353. package/frontend-dist/assets/vue-D2xRrEX4.js +1 -0
  354. package/frontend-dist/assets/vue-html-AaS7Mt5G.js +1 -0
  355. package/frontend-dist/assets/vue-vine-BoDAl6tE.js +1 -0
  356. package/frontend-dist/assets/vyper-CDx5xZoG.js +1 -0
  357. package/frontend-dist/assets/wasm-CG6Dc4jp.js +1 -0
  358. package/frontend-dist/assets/wasm-MzD3tlZU.js +1 -0
  359. package/frontend-dist/assets/wenyan-BV7otONQ.js +1 -0
  360. package/frontend-dist/assets/wgsl-Dx-B1_4e.js +1 -0
  361. package/frontend-dist/assets/wikitext-BhOHFoWU.js +1 -0
  362. package/frontend-dist/assets/wit-5i3qLPDT.js +1 -0
  363. package/frontend-dist/assets/wolfram-lXgVvXCa.js +1 -0
  364. package/frontend-dist/assets/xml-sdJ4AIDG.js +1 -0
  365. package/frontend-dist/assets/xsl-CtQFsRM5.js +1 -0
  366. package/frontend-dist/assets/yaml-Buea-lGh.js +1 -0
  367. package/frontend-dist/assets/zenscript-DVFEvuxE.js +1 -0
  368. package/frontend-dist/assets/zig-VOosw3JB.js +1 -0
  369. package/frontend-dist/index.html +2 -2
  370. package/frontend-dist/manifest.webmanifest +1 -1
  371. package/frontend-dist/sw.js +1 -1
  372. package/package.json +1 -1
  373. package/frontend-dist/assets/index-B7bzacGC.css +0 -32
  374. package/frontend-dist/assets/index-DkZHNqNf.js +0 -359
package/dist/cli.js CHANGED
@@ -75,26 +75,24 @@ function ensureDefaultUserConfig(input) {
75
75
  const workdirAllow = normalizeStringArray(src.workdirAllow);
76
76
  const workdirDeny = src.workdirDeny === void 0 || !Array.isArray(src.workdirDeny) ? [...DEFAULT_WORKDIR_DENY] : normalizeStringArray(src.workdirDeny) ?? [];
77
77
  const rawDisplay = src.display;
78
- const fsMinRaw = rawDisplay?.fontSizeMin;
79
- const fsMaxRaw = rawDisplay?.fontSizeMax;
80
- let fontSizeMin = typeof fsMinRaw === "number" && Number.isFinite(fsMinRaw) && fsMinRaw >= FONT_SIZE_FLOOR && fsMinRaw <= FONT_SIZE_CEIL ? Math.trunc(fsMinRaw) : DEFAULT_DISPLAY.fontSizeMin;
81
- let fontSizeMax = typeof fsMaxRaw === "number" && Number.isFinite(fsMaxRaw) && fsMaxRaw >= FONT_SIZE_FLOOR && fsMaxRaw <= FONT_SIZE_CEIL ? Math.trunc(fsMaxRaw) : DEFAULT_DISPLAY.fontSizeMax;
78
+ let fontSizeMin = normalizeBoundedNumber(rawDisplay?.fontSizeMin, FONT_SIZE_FLOOR, FONT_SIZE_CEIL, DEFAULT_DISPLAY.fontSizeMin, { truncate: true });
79
+ let fontSizeMax = normalizeBoundedNumber(rawDisplay?.fontSizeMax, FONT_SIZE_FLOOR, FONT_SIZE_CEIL, DEFAULT_DISPLAY.fontSizeMax, { truncate: true });
82
80
  if (fontSizeMin > fontSizeMax) {
83
81
  [fontSizeMin, fontSizeMax] = [fontSizeMax, fontSizeMin];
84
82
  }
85
83
  const legacyTargetCols = rawDisplay?.targetCols;
86
- const colsRaw = rawDisplay?.maxCols ?? legacyTargetCols;
87
- const maxCols = typeof colsRaw === "number" && Number.isFinite(colsRaw) && colsRaw >= 0 && colsRaw <= 500 ? Math.trunc(colsRaw) : DEFAULT_DISPLAY.maxCols;
88
- const lsRaw = rawDisplay?.letterSpacing;
89
- const letterSpacing = typeof lsRaw === "number" && Number.isFinite(lsRaw) && lsRaw >= -4 && lsRaw <= 8 ? lsRaw : DEFAULT_DISPLAY.letterSpacing;
84
+ const maxCols = normalizeBoundedNumber(rawDisplay?.maxCols ?? legacyTargetCols, 0, 500, DEFAULT_DISPLAY.maxCols, { truncate: true });
85
+ const letterSpacing = normalizeBoundedNumber(rawDisplay?.letterSpacing, -4, 8, DEFAULT_DISPLAY.letterSpacing);
90
86
  const themeRaw = rawDisplay?.theme;
91
87
  const theme = themeRaw === "dark" || themeRaw === "light" || themeRaw === "dark-ansi" || themeRaw === "light-ansi" || themeRaw === "dark-daltonized" || themeRaw === "light-daltonized" || themeRaw === "auto" ? themeRaw : DEFAULT_DISPLAY.theme;
88
+ const markdownPreview = typeof rawDisplay?.markdownPreview === "boolean" ? rawDisplay.markdownPreview : DEFAULT_DISPLAY.markdownPreview;
92
89
  const display = {
93
90
  fontSizeMin,
94
91
  fontSizeMax,
95
92
  maxCols,
96
93
  letterSpacing,
97
- theme
94
+ theme,
95
+ markdownPreview
98
96
  };
99
97
  const rawIntegrations = src.integrations;
100
98
  const ccUserEvents = rawIntegrations?.perModule?.["claude-code"]?.events ?? {};
@@ -139,6 +137,13 @@ function normalizeStringArray(input) {
139
137
  }
140
138
  return out;
141
139
  }
140
+ function normalizeBoundedNumber(input, min, max, fallback, opts = {}) {
141
+ if (typeof input !== "number" || !Number.isFinite(input))
142
+ return fallback;
143
+ if (input < min || input > max)
144
+ return fallback;
145
+ return opts.truncate ? Math.trunc(input) : input;
146
+ }
142
147
  var SHORTCUT_GROUPS, DEFAULT_SHORTCUTS, COMMAND_GROUPS, DEFAULT_COMMANDS, DEFAULT_INTEGRATIONS, DEFAULT_INPUT, DEFAULT_DISPLAY, FONT_SIZE_FLOOR, FONT_SIZE_CEIL, DEFAULT_WORKDIR_DENY;
143
148
  var init_defaults = __esm({
144
149
  "shared/dist/defaults.js"() {
@@ -357,8 +362,9 @@ var init_defaults = __esm({
357
362
  maxCols: 0,
358
363
  // 0 = 关闭自适应
359
364
  letterSpacing: 0,
360
- theme: "auto"
365
+ theme: "auto",
361
366
  // 跟随系统亮暗模式:dark → Campbell, light → Solarized Light
367
+ markdownPreview: true
362
368
  };
363
369
  FONT_SIZE_FLOOR = 6;
364
370
  FONT_SIZE_CEIL = 32;
@@ -419,6 +425,14 @@ var init_errors = __esm({
419
425
  ErrorCode2["PUSH_SEND_FAILED"] = "PUSH_SEND_FAILED";
420
426
  ErrorCode2["HOOK_INVALID_PAYLOAD"] = "HOOK_INVALID_PAYLOAD";
421
427
  ErrorCode2["HOOK_NON_LOCALHOST"] = "HOOK_NON_LOCALHOST";
428
+ ErrorCode2["BAD_REQUEST"] = "BAD_REQUEST";
429
+ ErrorCode2["PATH_NOT_FOUND"] = "PATH_NOT_FOUND";
430
+ ErrorCode2["PATH_FORBIDDEN"] = "PATH_FORBIDDEN";
431
+ ErrorCode2["FILE_TOO_LARGE"] = "FILE_TOO_LARGE";
432
+ ErrorCode2["FILE_BINARY"] = "FILE_BINARY";
433
+ ErrorCode2["FILE_TYPE_FORBID"] = "FILE_TYPE_FORBID";
434
+ ErrorCode2["SEARCH_INVALID_Q"] = "SEARCH_INVALID_Q";
435
+ ErrorCode2["SEARCH_TIMEOUT"] = "SEARCH_TIMEOUT";
422
436
  ErrorCode2["INTERNAL_ERROR"] = "INTERNAL_ERROR";
423
437
  ErrorCode2["NOT_IMPLEMENTED"] = "NOT_IMPLEMENTED";
424
438
  })(ErrorCode || (ErrorCode = {}));
@@ -450,6 +464,26 @@ var init_html_injection = __esm({
450
464
  }
451
465
  });
452
466
 
467
+ // shared/dist/files.js
468
+ function isSearchMode(v) {
469
+ return typeof v === "string" && SEARCH_MODES.includes(v);
470
+ }
471
+ var SEARCH_MODES, FILE_READ_MAX_BYTES, FILE_RAW_MAX_BYTES, SEARCH_MAX_Q_LENGTH, SEARCH_MAX_NAME_RESULTS, SEARCH_MAX_CONTENT_RESULTS, SEARCH_FILE_TIMEOUT_MS, SEARCH_TOTAL_TIMEOUT_MS, SEARCH_CONCURRENCY;
472
+ var init_files = __esm({
473
+ "shared/dist/files.js"() {
474
+ "use strict";
475
+ SEARCH_MODES = ["name", "content", "both"];
476
+ FILE_READ_MAX_BYTES = 2 * 1024 * 1024;
477
+ FILE_RAW_MAX_BYTES = 8 * 1024 * 1024;
478
+ SEARCH_MAX_Q_LENGTH = 200;
479
+ SEARCH_MAX_NAME_RESULTS = 100;
480
+ SEARCH_MAX_CONTENT_RESULTS = 200;
481
+ SEARCH_FILE_TIMEOUT_MS = 100;
482
+ SEARCH_TOTAL_TIMEOUT_MS = 5e3;
483
+ SEARCH_CONCURRENCY = 8;
484
+ }
485
+ });
486
+
453
487
  // shared/dist/index.js
454
488
  var init_dist = __esm({
455
489
  "shared/dist/index.js"() {
@@ -462,11 +496,12 @@ var init_dist = __esm({
462
496
  init_action_tree_defaults();
463
497
  init_errors();
464
498
  init_html_injection();
499
+ init_files();
465
500
  }
466
501
  });
467
502
 
468
503
  // backend/dist/errors.js
469
- var AppError, AuthError, PtyError, ConfigError, InstanceError, LockError, HookError, PushError;
504
+ var AppError, AuthError, PtyError, ConfigError, InstanceError, LockError, HookError, PushError, FileError;
470
505
  var init_errors2 = __esm({
471
506
  "backend/dist/errors.js"() {
472
507
  "use strict";
@@ -531,6 +566,11 @@ Caused by: ${cause.stack}`;
531
566
  super(code, message, httpStatus, cause);
532
567
  }
533
568
  };
569
+ FileError = class extends AppError {
570
+ constructor(code, message, httpStatus = 400, cause) {
571
+ super(code, message, httpStatus, cause);
572
+ }
573
+ };
534
574
  }
535
575
  });
536
576
 
@@ -1352,7 +1392,7 @@ function getEntryUrl(req, subPath = "") {
1352
1392
  function isFromBroker(req) {
1353
1393
  return getInstanceFromHeaders(req.headers) !== null;
1354
1394
  }
1355
- var HEADER_FORWARDED_INSTANCE, HEADER_FORWARDED_PATH, HEADER_FORWARDED_HOST, HEADER_FORWARDED_PROTO, HEADER_FORWARDED_FOR;
1395
+ var HEADER_FORWARDED_INSTANCE, HEADER_FORWARDED_PATH, HEADER_FORWARDED_HOST, HEADER_FORWARDED_PROTO, HEADER_FORWARDED_FOR, HEADER_ATR_ERROR;
1356
1396
  var init_forwarded_headers = __esm({
1357
1397
  "backend/dist/broker/forwarded-headers.js"() {
1358
1398
  "use strict";
@@ -1361,6 +1401,7 @@ var init_forwarded_headers = __esm({
1361
1401
  HEADER_FORWARDED_HOST = "x-forwarded-host";
1362
1402
  HEADER_FORWARDED_PROTO = "x-forwarded-proto";
1363
1403
  HEADER_FORWARDED_FOR = "x-forwarded-for";
1404
+ HEADER_ATR_ERROR = "X-ATR-Error";
1364
1405
  }
1365
1406
  });
1366
1407
 
@@ -1556,79 +1597,1493 @@ function collectEndpoints(port, displayIp) {
1556
1597
  continue;
1557
1598
  ipv6KeptForIface = true;
1558
1599
  }
1559
- const kind = classify(ip, info.family);
1560
- out.push({ host: ip, port, kind, interface: ifname });
1600
+ const kind = classify(ip, info.family);
1601
+ out.push({ host: ip, port, kind, interface: ifname });
1602
+ }
1603
+ }
1604
+ if (!out.some((e) => e.kind === "loopback")) {
1605
+ out.push({ host: "127.0.0.1", port, kind: "loopback" });
1606
+ }
1607
+ const order = {
1608
+ lan: 0,
1609
+ tailscale: 1,
1610
+ other: 2,
1611
+ ipv6: 3,
1612
+ loopback: 4
1613
+ };
1614
+ out.sort((a, b) => {
1615
+ if (a.kind !== b.kind)
1616
+ return order[a.kind] - order[b.kind];
1617
+ if (a.host === displayIp)
1618
+ return -1;
1619
+ if (b.host === displayIp)
1620
+ return 1;
1621
+ return 0;
1622
+ });
1623
+ let defaultIdx = out.findIndex((e) => e.host === displayIp);
1624
+ if (defaultIdx === -1) {
1625
+ defaultIdx = out.findIndex((e) => e.kind !== "loopback");
1626
+ }
1627
+ if (defaultIdx === -1 && out.length > 0)
1628
+ defaultIdx = 0;
1629
+ if (defaultIdx >= 0)
1630
+ out[defaultIdx].isDefault = true;
1631
+ return out;
1632
+ }
1633
+ function classify(ip, family) {
1634
+ if (isLoopbackIp(ip))
1635
+ return "loopback";
1636
+ if (family === "IPv6")
1637
+ return "ipv6";
1638
+ if (isTailscaleIp(ip))
1639
+ return "tailscale";
1640
+ if (isPrivateIp(ip))
1641
+ return "lan";
1642
+ if (isLinkLocal(ip))
1643
+ return "other";
1644
+ return "other";
1645
+ }
1646
+ var init_share_routes = __esm({
1647
+ "backend/dist/api/share-routes.js"() {
1648
+ "use strict";
1649
+ init_network();
1650
+ }
1651
+ });
1652
+
1653
+ // backend/dist/api/workdir-policy-routes.js
1654
+ import { Router as Router8 } from "express";
1655
+ function createWorkdirPolicyRoutes(authModule, snapshot) {
1656
+ const router = Router8();
1657
+ router.get("/workdir-policy", authModule.requireAuth, (_req, res) => {
1658
+ const s = snapshot();
1659
+ res.json({ ok: true, allow: s.allow });
1660
+ });
1661
+ return router;
1662
+ }
1663
+ var init_workdir_policy_routes = __esm({
1664
+ "backend/dist/api/workdir-policy-routes.js"() {
1665
+ "use strict";
1666
+ }
1667
+ });
1668
+
1669
+ // backend/dist/auth/rate-limiter.js
1670
+ var RateLimiter;
1671
+ var init_rate_limiter = __esm({
1672
+ "backend/dist/auth/rate-limiter.js"() {
1673
+ "use strict";
1674
+ init_logger();
1675
+ RateLimiter = class {
1676
+ entries = /* @__PURE__ */ new Map();
1677
+ maxAttempts;
1678
+ windowMs;
1679
+ cleanupTimer = null;
1680
+ /**
1681
+ * @param maxAttempts 窗口内最大允许次数
1682
+ * @param windowMs 窗口长度(毫秒),默认 60s
1683
+ */
1684
+ constructor(maxAttempts, windowMs = 6e4) {
1685
+ if (!Number.isInteger(maxAttempts) || maxAttempts <= 0) {
1686
+ throw new Error("RateLimiter: maxAttempts \u5FC5\u987B\u662F\u6B63\u6574\u6570");
1687
+ }
1688
+ this.maxAttempts = maxAttempts;
1689
+ this.windowMs = windowMs;
1690
+ this.cleanupTimer = setInterval(() => this.cleanup(), windowMs * 2);
1691
+ if (typeof this.cleanupTimer.unref === "function") {
1692
+ this.cleanupTimer.unref();
1693
+ }
1694
+ }
1695
+ /**
1696
+ * 尝试一次请求,自动累加计数
1697
+ *
1698
+ * @returns true 通过 / false 已超限被拒
1699
+ */
1700
+ attempt(ip) {
1701
+ const now = Date.now();
1702
+ const entry = this.entries.get(ip);
1703
+ if (!entry || now >= entry.resetAt) {
1704
+ this.entries.set(ip, { count: 1, resetAt: now + this.windowMs });
1705
+ return true;
1706
+ }
1707
+ entry.count++;
1708
+ if (entry.count > this.maxAttempts) {
1709
+ logger.warn({ ip, count: entry.count, max: this.maxAttempts }, "\u8BA4\u8BC1\u901F\u7387\u8D85\u9650");
1710
+ return false;
1711
+ }
1712
+ return true;
1713
+ }
1714
+ /** 当前窗口内剩余次数 */
1715
+ remaining(ip) {
1716
+ const now = Date.now();
1717
+ const entry = this.entries.get(ip);
1718
+ if (!entry || now >= entry.resetAt)
1719
+ return this.maxAttempts;
1720
+ return Math.max(0, this.maxAttempts - entry.count);
1721
+ }
1722
+ /**
1723
+ * 重置某 IP 的计数(认证成功后清零)
1724
+ *
1725
+ * 让合法用户不会因为之前误输导致后续尝试被限流
1726
+ */
1727
+ reset(ip) {
1728
+ this.entries.delete(ip);
1729
+ }
1730
+ /** 清理过期 entry(避免内存膨胀) */
1731
+ cleanup() {
1732
+ const now = Date.now();
1733
+ for (const [ip, entry] of this.entries) {
1734
+ if (now >= entry.resetAt) {
1735
+ this.entries.delete(ip);
1736
+ }
1737
+ }
1738
+ }
1739
+ /** 销毁定时器 */
1740
+ destroy() {
1741
+ if (this.cleanupTimer) {
1742
+ clearInterval(this.cleanupTimer);
1743
+ this.cleanupTimer = null;
1744
+ }
1745
+ }
1746
+ };
1747
+ }
1748
+ });
1749
+
1750
+ // backend/dist/constants.js
1751
+ var WS_FLUSH_INTERVAL_MS, WS_MAX_CHUNK_BYTES, WS_HIGH_WATERMARK_BYTES, FILE_LOCK_RETRIES, FILE_LOCK_RETRY_INTERVAL_MS, FILE_LOCK_STALE_MS, FILE_RATE_LIMIT_PER_MIN, SEARCH_RATE_LIMIT_PER_MIN, PTY_DEFAULT_COLS, PTY_DEFAULT_ROWS, PTY_TERM_NAME, DOUBLE_PULSE_DELAY_MS, SHUTDOWN_WS_FLUSH_DELAY_MS, SHUTDOWN_FORCE_EXIT_MS, DOUBLE_CTRL_C_WINDOW_MS, PORT_FINDER_MAX_ATTEMPTS, STOP_INSTANCE_GRACE_MS, STOP_INSTANCE_POLL_INTERVAL_MS, ATTACH_RECONNECT_DELAYS_MS;
1752
+ var init_constants2 = __esm({
1753
+ "backend/dist/constants.js"() {
1754
+ "use strict";
1755
+ WS_FLUSH_INTERVAL_MS = 16;
1756
+ WS_MAX_CHUNK_BYTES = 32 * 1024;
1757
+ WS_HIGH_WATERMARK_BYTES = 256 * 1024;
1758
+ FILE_LOCK_RETRIES = 50;
1759
+ FILE_LOCK_RETRY_INTERVAL_MS = 50;
1760
+ FILE_LOCK_STALE_MS = 1e4;
1761
+ FILE_RATE_LIMIT_PER_MIN = 600;
1762
+ SEARCH_RATE_LIMIT_PER_MIN = 60;
1763
+ PTY_DEFAULT_COLS = 80;
1764
+ PTY_DEFAULT_ROWS = 24;
1765
+ PTY_TERM_NAME = "xterm-256color";
1766
+ DOUBLE_PULSE_DELAY_MS = 50;
1767
+ SHUTDOWN_WS_FLUSH_DELAY_MS = 500;
1768
+ SHUTDOWN_FORCE_EXIT_MS = 2e3;
1769
+ DOUBLE_CTRL_C_WINDOW_MS = 500;
1770
+ PORT_FINDER_MAX_ATTEMPTS = 100;
1771
+ STOP_INSTANCE_GRACE_MS = 3e3;
1772
+ STOP_INSTANCE_POLL_INTERVAL_MS = 100;
1773
+ ATTACH_RECONNECT_DELAYS_MS = [1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
1774
+ }
1775
+ });
1776
+
1777
+ // backend/dist/utils/workdir-policy.js
1778
+ import picomatch from "picomatch";
1779
+ function checkWorkdir(cwd, allow, deny) {
1780
+ const norm = normalizePath(cwd);
1781
+ const opts = { dot: true };
1782
+ if (deny && deny.length > 0) {
1783
+ for (const pattern of deny) {
1784
+ if (picomatch(pattern, opts)(norm)) {
1785
+ return {
1786
+ reason: `cwd "${cwd}" \u547D\u4E2D\u9ED1\u540D\u5355 pattern\uFF1A${pattern}`,
1787
+ matchedPattern: pattern
1788
+ };
1789
+ }
1790
+ }
1791
+ }
1792
+ if (allow && allow.length > 0) {
1793
+ let hit = false;
1794
+ for (const pattern of allow) {
1795
+ if (picomatch(pattern, opts)(norm)) {
1796
+ hit = true;
1797
+ break;
1798
+ }
1799
+ }
1800
+ if (!hit) {
1801
+ return {
1802
+ reason: `cwd "${cwd}" \u672A\u547D\u4E2D\u4EFB\u4F55\u767D\u540D\u5355 pattern\uFF1A[${allow.join(", ")}]`,
1803
+ matchedPattern: ""
1804
+ };
1805
+ }
1806
+ }
1807
+ return null;
1808
+ }
1809
+ function normalizePath(p) {
1810
+ return p.replace(/\\/g, "/");
1811
+ }
1812
+ var init_workdir_policy = __esm({
1813
+ "backend/dist/utils/workdir-policy.js"() {
1814
+ "use strict";
1815
+ }
1816
+ });
1817
+
1818
+ // backend/dist/files/path-resolver.js
1819
+ import { realpathSync } from "node:fs";
1820
+ import { isAbsolute, relative as relativePath, resolve as resolvePath } from "node:path";
1821
+ function resolveSafePath(cwd, input, policy) {
1822
+ const raw = input && input.length > 0 ? input : ".";
1823
+ const abs = isAbsolute(raw) ? raw : resolvePath(cwd, raw);
1824
+ let real;
1825
+ try {
1826
+ real = realpathSync(abs);
1827
+ } catch (err) {
1828
+ throw new FileError(ErrorCode.PATH_NOT_FOUND, `path not found: ${abs}`, 404, err);
1829
+ }
1830
+ const cwdReal = realpathSync(cwd);
1831
+ if (!isWithin(cwdReal, real)) {
1832
+ throw new FileError(ErrorCode.PATH_FORBIDDEN, `path outside instance cwd: ${real}`, 403);
1833
+ }
1834
+ const verdict = checkWorkdir(real, policy.allow, policy.deny);
1835
+ if (verdict !== null) {
1836
+ throw new FileError(ErrorCode.PATH_FORBIDDEN, `path forbidden: ${verdict.reason}`, 403);
1837
+ }
1838
+ return real;
1839
+ }
1840
+ function isWithin(parent, child) {
1841
+ if (parent === child)
1842
+ return true;
1843
+ const rel = relativePath(parent, child);
1844
+ if (rel === "" || rel === ".")
1845
+ return true;
1846
+ if (isAbsolute(rel))
1847
+ return false;
1848
+ if (rel.startsWith(".."))
1849
+ return false;
1850
+ return true;
1851
+ }
1852
+ var init_path_resolver = __esm({
1853
+ "backend/dist/files/path-resolver.js"() {
1854
+ "use strict";
1855
+ init_dist();
1856
+ init_errors2();
1857
+ init_workdir_policy();
1858
+ }
1859
+ });
1860
+
1861
+ // backend/dist/files/mime-detect.js
1862
+ import { basename as basename2, extname } from "node:path";
1863
+ function detectMime(filename) {
1864
+ const base = basename2(filename);
1865
+ const special = lookupSpecial(base);
1866
+ if (special) {
1867
+ return { mime: special.mime, previewable: special.previewable, lang: special.lang };
1868
+ }
1869
+ const ext = extname(base).toLowerCase();
1870
+ const lang = LANG_MAP[ext] ?? "txt";
1871
+ if (ext in IMAGE_EXT_TO_MIME) {
1872
+ return { mime: IMAGE_EXT_TO_MIME[ext], previewable: "image", lang };
1873
+ }
1874
+ if (ext in TEXT_EXT_TO_MIME) {
1875
+ return { mime: TEXT_EXT_TO_MIME[ext], previewable: "text", lang };
1876
+ }
1877
+ return { mime: "application/octet-stream", previewable: "none", lang };
1878
+ }
1879
+ function lookupSpecial(base) {
1880
+ if (base in SPECIAL_NAMES)
1881
+ return SPECIAL_NAMES[base];
1882
+ const ext = extname(base).toLowerCase();
1883
+ if (ext === "" || ext === ".md" || ext === ".markdown" || ext === ".txt") {
1884
+ const stem = base.slice(0, base.length - ext.length);
1885
+ const upper = stem.toUpperCase();
1886
+ if (upper === "README" || upper === "CHANGELOG" || upper === "LICENSE" || upper === "COPYING" || upper === "AUTHORS" || upper === "CONTRIBUTORS" || upper === "NOTICE" || upper === "TODO") {
1887
+ const isMd = ext === ".md" || ext === ".markdown";
1888
+ const baseEntry = SPECIAL_NAMES[upper];
1889
+ if (baseEntry) {
1890
+ return isMd ? { ...baseEntry, lang: "markdown", mime: "text/markdown" } : baseEntry;
1891
+ }
1892
+ }
1893
+ }
1894
+ return null;
1895
+ }
1896
+ var SPECIAL_NAMES, IMAGE_EXT_TO_MIME, TEXT_EXT_TO_MIME, LANG_MAP;
1897
+ var init_mime_detect = __esm({
1898
+ "backend/dist/files/mime-detect.js"() {
1899
+ "use strict";
1900
+ SPECIAL_NAMES = {
1901
+ // ─── 构建/容器 ───
1902
+ "Makefile": { mime: "text/x-makefile", lang: "makefile", previewable: "text" },
1903
+ "GNUmakefile": { mime: "text/x-makefile", lang: "makefile", previewable: "text" },
1904
+ "Dockerfile": { mime: "text/x-dockerfile", lang: "docker", previewable: "text" },
1905
+ "Containerfile": { mime: "text/x-dockerfile", lang: "docker", previewable: "text" },
1906
+ "CMakeLists.txt": { mime: "text/plain", lang: "cmake", previewable: "text" },
1907
+ // ─── 包管理 / 工程 ───
1908
+ "package.json": { mime: "application/json", lang: "json", previewable: "text" },
1909
+ "package-lock.json": { mime: "application/json", lang: "json", previewable: "text" },
1910
+ "tsconfig.json": { mime: "application/json", lang: "jsonc", previewable: "text" },
1911
+ "tsconfig.base.json": { mime: "application/json", lang: "jsonc", previewable: "text" },
1912
+ "jsconfig.json": { mime: "application/json", lang: "jsonc", previewable: "text" },
1913
+ "turbo.json": { mime: "application/json", lang: "jsonc", previewable: "text" },
1914
+ "nx.json": { mime: "application/json", lang: "json", previewable: "text" },
1915
+ "lerna.json": { mime: "application/json", lang: "json", previewable: "text" },
1916
+ "biome.json": { mime: "application/json", lang: "jsonc", previewable: "text" },
1917
+ "composer.json": { mime: "application/json", lang: "json", previewable: "text" },
1918
+ "composer.lock": { mime: "application/json", lang: "json", previewable: "text" },
1919
+ "pnpm-workspace.yaml": { mime: "application/yaml", lang: "yaml", previewable: "text" },
1920
+ "pnpm-lock.yaml": { mime: "application/yaml", lang: "yaml", previewable: "text" },
1921
+ "yarn.lock": { mime: "text/plain", lang: "yaml", previewable: "text" },
1922
+ "bun.lockb": { mime: "application/octet-stream", lang: "txt", previewable: "none" },
1923
+ "bun.lock": { mime: "text/plain", lang: "toml", previewable: "text" },
1924
+ // shiki 没有 go-mod grammar,降级 txt(纯文本仍可读,只是无着色)
1925
+ "go.mod": { mime: "text/x-go-mod", lang: "txt", previewable: "text" },
1926
+ "go.sum": { mime: "text/plain", lang: "txt", previewable: "text" },
1927
+ "Cargo.toml": { mime: "application/toml", lang: "toml", previewable: "text" },
1928
+ "Cargo.lock": { mime: "application/toml", lang: "toml", previewable: "text" },
1929
+ "pyproject.toml": { mime: "application/toml", lang: "toml", previewable: "text" },
1930
+ "poetry.lock": { mime: "application/toml", lang: "toml", previewable: "text" },
1931
+ "Pipfile": { mime: "application/toml", lang: "toml", previewable: "text" },
1932
+ "Pipfile.lock": { mime: "application/json", lang: "json", previewable: "text" },
1933
+ "requirements.txt": { mime: "text/plain", lang: "txt", previewable: "text" },
1934
+ "requirements-dev.txt": { mime: "text/plain", lang: "txt", previewable: "text" },
1935
+ "Rakefile": { mime: "text/x-ruby", lang: "ruby", previewable: "text" },
1936
+ "Gemfile": { mime: "text/x-ruby", lang: "ruby", previewable: "text" },
1937
+ "Gemfile.lock": { mime: "text/plain", lang: "txt", previewable: "text" },
1938
+ "Procfile": { mime: "text/plain", lang: "txt", previewable: "text" },
1939
+ "Brewfile": { mime: "text/x-ruby", lang: "ruby", previewable: "text" },
1940
+ "Vagrantfile": { mime: "text/x-ruby", lang: "ruby", previewable: "text" },
1941
+ "Justfile": { mime: "text/x-just", lang: "just", previewable: "text" },
1942
+ "justfile": { mime: "text/x-just", lang: "just", previewable: "text" },
1943
+ "Taskfile.yml": { mime: "application/yaml", lang: "yaml", previewable: "text" },
1944
+ "Taskfile.yaml": { mime: "application/yaml", lang: "yaml", previewable: "text" },
1945
+ // ─── 配置 dotfile ───
1946
+ ".gitignore": { mime: "text/x-gitignore", lang: "txt", previewable: "text" },
1947
+ ".gitattributes": { mime: "text/plain", lang: "txt", previewable: "text" },
1948
+ ".gitmodules": { mime: "text/x-properties", lang: "ini", previewable: "text" },
1949
+ ".gitconfig": { mime: "text/x-properties", lang: "ini", previewable: "text" },
1950
+ ".dockerignore": { mime: "text/x-gitignore", lang: "txt", previewable: "text" },
1951
+ ".npmignore": { mime: "text/x-gitignore", lang: "txt", previewable: "text" },
1952
+ ".eslintignore": { mime: "text/x-gitignore", lang: "txt", previewable: "text" },
1953
+ ".prettierignore": { mime: "text/x-gitignore", lang: "txt", previewable: "text" },
1954
+ ".editorconfig": { mime: "text/x-properties", lang: "ini", previewable: "text" },
1955
+ ".env": { mime: "text/plain", lang: "dotenv", previewable: "text" },
1956
+ ".env.local": { mime: "text/plain", lang: "dotenv", previewable: "text" },
1957
+ ".env.development": { mime: "text/plain", lang: "dotenv", previewable: "text" },
1958
+ ".env.production": { mime: "text/plain", lang: "dotenv", previewable: "text" },
1959
+ ".env.test": { mime: "text/plain", lang: "dotenv", previewable: "text" },
1960
+ ".env.example": { mime: "text/plain", lang: "dotenv", previewable: "text" },
1961
+ ".npmrc": { mime: "text/x-properties", lang: "ini", previewable: "text" },
1962
+ ".yarnrc": { mime: "text/plain", lang: "yaml", previewable: "text" },
1963
+ ".yarnrc.yml": { mime: "application/yaml", lang: "yaml", previewable: "text" },
1964
+ ".nvmrc": { mime: "text/plain", lang: "txt", previewable: "text" },
1965
+ ".node-version": { mime: "text/plain", lang: "txt", previewable: "text" },
1966
+ ".python-version": { mime: "text/plain", lang: "txt", previewable: "text" },
1967
+ ".ruby-version": { mime: "text/plain", lang: "txt", previewable: "text" },
1968
+ ".tool-versions": { mime: "text/plain", lang: "txt", previewable: "text" },
1969
+ ".eslintrc": { mime: "application/json", lang: "json", previewable: "text" },
1970
+ ".eslintrc.json": { mime: "application/json", lang: "json", previewable: "text" },
1971
+ ".eslintrc.js": { mime: "text/javascript", lang: "js", previewable: "text" },
1972
+ ".eslintrc.cjs": { mime: "text/javascript", lang: "js", previewable: "text" },
1973
+ ".eslintrc.yml": { mime: "application/yaml", lang: "yaml", previewable: "text" },
1974
+ ".eslintrc.yaml": { mime: "application/yaml", lang: "yaml", previewable: "text" },
1975
+ ".prettierrc": { mime: "application/json", lang: "json", previewable: "text" },
1976
+ ".prettierrc.json": { mime: "application/json", lang: "json", previewable: "text" },
1977
+ ".prettierrc.js": { mime: "text/javascript", lang: "js", previewable: "text" },
1978
+ ".prettierrc.cjs": { mime: "text/javascript", lang: "js", previewable: "text" },
1979
+ ".prettierrc.yml": { mime: "application/yaml", lang: "yaml", previewable: "text" },
1980
+ ".prettierrc.yaml": { mime: "application/yaml", lang: "yaml", previewable: "text" },
1981
+ ".stylelintrc": { mime: "application/json", lang: "json", previewable: "text" },
1982
+ ".stylelintrc.json": { mime: "application/json", lang: "json", previewable: "text" },
1983
+ ".babelrc": { mime: "application/json", lang: "json", previewable: "text" },
1984
+ ".babelrc.json": { mime: "application/json", lang: "json", previewable: "text" },
1985
+ ".swcrc": { mime: "application/json", lang: "json", previewable: "text" },
1986
+ ".huskyrc": { mime: "application/json", lang: "json", previewable: "text" },
1987
+ ".atrrc": { mime: "application/json", lang: "json", previewable: "text" },
1988
+ ".bashrc": { mime: "text/x-shellscript", lang: "bash", previewable: "text" },
1989
+ ".zshrc": { mime: "text/x-shellscript", lang: "bash", previewable: "text" },
1990
+ ".profile": { mime: "text/x-shellscript", lang: "bash", previewable: "text" },
1991
+ ".bash_profile": { mime: "text/x-shellscript", lang: "bash", previewable: "text" },
1992
+ ".zprofile": { mime: "text/x-shellscript", lang: "bash", previewable: "text" },
1993
+ ".zshenv": { mime: "text/x-shellscript", lang: "bash", previewable: "text" },
1994
+ // ─── 文档约定(无扩展或带各种扩展,通常 markdown) ───
1995
+ "README": { mime: "text/plain", lang: "markdown", previewable: "text" },
1996
+ "CHANGELOG": { mime: "text/markdown", lang: "markdown", previewable: "text" },
1997
+ "LICENSE": { mime: "text/plain", lang: "txt", previewable: "text" },
1998
+ "COPYING": { mime: "text/plain", lang: "txt", previewable: "text" },
1999
+ "AUTHORS": { mime: "text/plain", lang: "txt", previewable: "text" },
2000
+ "CONTRIBUTORS": { mime: "text/plain", lang: "txt", previewable: "text" },
2001
+ "NOTICE": { mime: "text/plain", lang: "txt", previewable: "text" },
2002
+ "TODO": { mime: "text/plain", lang: "txt", previewable: "text" }
2003
+ };
2004
+ IMAGE_EXT_TO_MIME = {
2005
+ ".png": "image/png",
2006
+ ".jpg": "image/jpeg",
2007
+ ".jpeg": "image/jpeg",
2008
+ ".jpe": "image/jpeg",
2009
+ ".jfif": "image/jpeg",
2010
+ ".gif": "image/gif",
2011
+ ".webp": "image/webp",
2012
+ ".svg": "image/svg+xml",
2013
+ ".bmp": "image/bmp",
2014
+ ".ico": "image/x-icon",
2015
+ ".avif": "image/avif",
2016
+ ".apng": "image/apng",
2017
+ ".tiff": "image/tiff",
2018
+ ".tif": "image/tiff"
2019
+ };
2020
+ TEXT_EXT_TO_MIME = {
2021
+ // 纯文本 / 文档
2022
+ ".txt": "text/plain",
2023
+ ".text": "text/plain",
2024
+ ".log": "text/plain",
2025
+ ".md": "text/markdown",
2026
+ ".markdown": "text/markdown",
2027
+ ".mkd": "text/markdown",
2028
+ ".mdx": "text/markdown",
2029
+ ".mdc": "text/markdown",
2030
+ ".rst": "text/x-rst",
2031
+ ".adoc": "text/asciidoc",
2032
+ ".asciidoc": "text/asciidoc",
2033
+ ".tex": "text/x-tex",
2034
+ ".bib": "text/x-bibtex",
2035
+ // 数据 / 配置
2036
+ ".json": "application/json",
2037
+ ".jsonc": "application/json",
2038
+ ".json5": "application/json",
2039
+ ".jsonl": "application/x-jsonlines",
2040
+ ".ndjson": "application/x-ndjson",
2041
+ ".yml": "application/yaml",
2042
+ ".yaml": "application/yaml",
2043
+ ".toml": "application/toml",
2044
+ ".ini": "text/x-properties",
2045
+ ".cfg": "text/x-properties",
2046
+ ".conf": "text/plain",
2047
+ ".properties": "text/x-properties",
2048
+ ".env": "text/plain",
2049
+ ".example": "text/plain",
2050
+ ".gitignore": "text/x-gitignore",
2051
+ ".dockerignore": "text/x-gitignore",
2052
+ ".csv": "text/csv",
2053
+ ".tsv": "text/tab-separated-values",
2054
+ ".lock": "text/plain",
2055
+ ".xml": "application/xml",
2056
+ ".xsl": "application/xml",
2057
+ ".xsd": "application/xml",
2058
+ ".plist": "application/xml",
2059
+ ".po": "text/x-gettext",
2060
+ ".pot": "text/x-gettext",
2061
+ ".proto": "text/x-protobuf",
2062
+ ".graphql": "application/graphql",
2063
+ ".gql": "application/graphql",
2064
+ // Web
2065
+ ".html": "text/html",
2066
+ ".htm": "text/html",
2067
+ ".xhtml": "application/xhtml+xml",
2068
+ ".css": "text/css",
2069
+ ".scss": "text/x-scss",
2070
+ ".sass": "text/x-sass",
2071
+ ".less": "text/x-less",
2072
+ ".styl": "text/x-stylus",
2073
+ ".vue": "text/x-vue",
2074
+ ".svelte": "text/x-svelte",
2075
+ ".astro": "text/x-astro",
2076
+ ".hbs": "text/x-handlebars",
2077
+ ".handlebars": "text/x-handlebars",
2078
+ ".pug": "text/x-pug",
2079
+ ".jade": "text/x-pug",
2080
+ ".ejs": "text/x-ejs",
2081
+ ".erb": "text/x-erb",
2082
+ ".liquid": "text/x-liquid",
2083
+ ".twig": "text/x-twig",
2084
+ ".njk": "text/x-jinja",
2085
+ ".jinja": "text/x-jinja",
2086
+ ".jinja2": "text/x-jinja",
2087
+ ".j2": "text/x-jinja",
2088
+ // JS/TS 系
2089
+ ".ts": "text/typescript",
2090
+ ".tsx": "text/tsx",
2091
+ ".mts": "text/typescript",
2092
+ ".cts": "text/typescript",
2093
+ ".js": "text/javascript",
2094
+ ".jsx": "text/jsx",
2095
+ ".mjs": "text/javascript",
2096
+ ".cjs": "text/javascript",
2097
+ ".d.ts": "text/typescript",
2098
+ // 系统/脚本
2099
+ ".sh": "text/x-shellscript",
2100
+ ".bash": "text/x-shellscript",
2101
+ ".zsh": "text/x-shellscript",
2102
+ ".fish": "text/x-shellscript",
2103
+ ".ksh": "text/x-shellscript",
2104
+ ".ps1": "text/x-powershell",
2105
+ ".psm1": "text/x-powershell",
2106
+ ".bat": "text/x-batchfile",
2107
+ ".cmd": "text/x-batchfile",
2108
+ ".awk": "text/x-awk",
2109
+ ".sed": "text/x-sed",
2110
+ ".nginx": "text/x-nginx-conf",
2111
+ ".nginxconf": "text/x-nginx-conf",
2112
+ ".service": "text/x-systemd",
2113
+ ".timer": "text/x-systemd",
2114
+ // Python / Ruby / Go / Rust / 其它语言
2115
+ ".py": "text/x-python",
2116
+ ".pyi": "text/x-python",
2117
+ ".pyw": "text/x-python",
2118
+ ".rb": "text/x-ruby",
2119
+ ".rake": "text/x-ruby",
2120
+ ".go": "text/x-go",
2121
+ ".rs": "text/x-rust",
2122
+ ".php": "text/x-php",
2123
+ ".php3": "text/x-php",
2124
+ ".phtml": "text/x-php",
2125
+ ".java": "text/x-java",
2126
+ ".kt": "text/x-kotlin",
2127
+ ".kts": "text/x-kotlin",
2128
+ ".swift": "text/x-swift",
2129
+ ".c": "text/x-c",
2130
+ ".h": "text/x-c",
2131
+ ".cc": "text/x-c++",
2132
+ ".cpp": "text/x-c++",
2133
+ ".cxx": "text/x-c++",
2134
+ ".hh": "text/x-c++",
2135
+ ".hpp": "text/x-c++",
2136
+ ".hxx": "text/x-c++",
2137
+ ".cs": "text/x-csharp",
2138
+ ".fs": "text/x-fsharp",
2139
+ ".fsx": "text/x-fsharp",
2140
+ ".m": "text/x-objective-c",
2141
+ ".mm": "text/x-objective-c++",
2142
+ ".scala": "text/x-scala",
2143
+ ".sc": "text/x-scala",
2144
+ ".ex": "text/x-elixir",
2145
+ ".exs": "text/x-elixir",
2146
+ ".erl": "text/x-erlang",
2147
+ ".hrl": "text/x-erlang",
2148
+ ".hs": "text/x-haskell",
2149
+ ".lhs": "text/x-haskell",
2150
+ ".lua": "text/x-lua",
2151
+ ".r": "text/x-r",
2152
+ ".R": "text/x-r",
2153
+ ".dart": "text/x-dart",
2154
+ ".pl": "text/x-perl",
2155
+ ".pm": "text/x-perl",
2156
+ ".groovy": "text/x-groovy",
2157
+ ".gradle": "text/x-groovy",
2158
+ ".clj": "text/x-clojure",
2159
+ ".cljs": "text/x-clojure",
2160
+ ".cljc": "text/x-clojure",
2161
+ ".lisp": "text/x-common-lisp",
2162
+ ".lsp": "text/x-common-lisp",
2163
+ ".el": "text/x-emacs-lisp",
2164
+ ".scheme": "text/x-scheme",
2165
+ ".scm": "text/x-scheme",
2166
+ ".ml": "text/x-ocaml",
2167
+ ".mli": "text/x-ocaml",
2168
+ ".jl": "text/x-julia",
2169
+ ".zig": "text/x-zig",
2170
+ ".nim": "text/x-nim",
2171
+ ".cr": "text/x-crystal",
2172
+ ".v": "text/x-v",
2173
+ ".vala": "text/x-vala",
2174
+ ".vb": "text/x-vb",
2175
+ // 数据库 / 数据
2176
+ ".sql": "application/sql",
2177
+ ".psql": "application/sql",
2178
+ ".mysql": "application/sql",
2179
+ ".prisma": "text/x-prisma",
2180
+ // 配置 / IaC
2181
+ ".nix": "text/x-nix",
2182
+ ".tf": "text/x-terraform",
2183
+ ".tfvars": "text/x-terraform",
2184
+ ".hcl": "text/x-hcl",
2185
+ ".dockerfile": "text/x-dockerfile",
2186
+ ".cmake": "text/x-cmake",
2187
+ ".make": "text/x-makefile",
2188
+ ".mk": "text/x-makefile",
2189
+ ".makefile": "text/x-makefile",
2190
+ ".gn": "text/x-gn",
2191
+ ".bzl": "text/x-bzl",
2192
+ ".bazel": "text/x-bzl",
2193
+ // 其它
2194
+ ".diff": "text/x-diff",
2195
+ ".patch": "text/x-diff",
2196
+ ".regex": "text/x-regex",
2197
+ ".http": "message/http",
2198
+ ".cmake.in": "text/x-cmake",
2199
+ ".gitcommit": "text/x-git-commit"
2200
+ };
2201
+ LANG_MAP = {
2202
+ // 纯文本 / 文档
2203
+ ".md": "markdown",
2204
+ ".markdown": "markdown",
2205
+ ".mkd": "markdown",
2206
+ ".mdx": "mdx",
2207
+ ".mdc": "mdc",
2208
+ ".rst": "rst",
2209
+ ".adoc": "asciidoc",
2210
+ ".asciidoc": "asciidoc",
2211
+ ".tex": "latex",
2212
+ ".bib": "bibtex",
2213
+ ".log": "log",
2214
+ // 数据 / 配置
2215
+ ".json": "json",
2216
+ ".jsonc": "jsonc",
2217
+ ".json5": "json5",
2218
+ ".jsonl": "jsonl",
2219
+ ".ndjson": "jsonl",
2220
+ ".yml": "yaml",
2221
+ ".yaml": "yaml",
2222
+ ".toml": "toml",
2223
+ ".ini": "ini",
2224
+ ".cfg": "ini",
2225
+ ".properties": "ini",
2226
+ ".conf": "ini",
2227
+ ".env": "dotenv",
2228
+ ".example": "dotenv",
2229
+ ".xml": "xml",
2230
+ ".xsl": "xml",
2231
+ ".xsd": "xml",
2232
+ ".plist": "xml",
2233
+ ".proto": "proto",
2234
+ ".graphql": "graphql",
2235
+ ".gql": "graphql",
2236
+ ".po": "po",
2237
+ ".pot": "po",
2238
+ // Web
2239
+ ".html": "html",
2240
+ ".htm": "html",
2241
+ ".xhtml": "html",
2242
+ ".css": "css",
2243
+ ".scss": "scss",
2244
+ ".sass": "sass",
2245
+ ".less": "less",
2246
+ ".styl": "stylus",
2247
+ ".vue": "vue",
2248
+ ".svelte": "svelte",
2249
+ ".astro": "astro",
2250
+ ".hbs": "handlebars",
2251
+ ".handlebars": "handlebars",
2252
+ ".pug": "pug",
2253
+ ".jade": "pug",
2254
+ ".erb": "erb",
2255
+ ".liquid": "liquid",
2256
+ ".twig": "twig",
2257
+ ".jinja": "jinja",
2258
+ ".jinja2": "jinja",
2259
+ ".j2": "jinja",
2260
+ ".njk": "jinja",
2261
+ // JS / TS 系
2262
+ ".ts": "ts",
2263
+ ".tsx": "tsx",
2264
+ ".mts": "ts",
2265
+ ".cts": "ts",
2266
+ ".js": "js",
2267
+ ".jsx": "jsx",
2268
+ ".mjs": "js",
2269
+ ".cjs": "js",
2270
+ ".d.ts": "ts",
2271
+ // 系统 / 脚本
2272
+ ".sh": "shell",
2273
+ ".bash": "bash",
2274
+ ".zsh": "bash",
2275
+ ".fish": "fish",
2276
+ ".ksh": "shell",
2277
+ ".ps1": "powershell",
2278
+ ".psm1": "powershell",
2279
+ ".bat": "bat",
2280
+ ".cmd": "bat",
2281
+ ".awk": "awk",
2282
+ ".nginx": "nginx",
2283
+ ".nginxconf": "nginx",
2284
+ ".service": "systemd",
2285
+ ".timer": "systemd",
2286
+ ".dockerfile": "docker",
2287
+ // 语言
2288
+ ".py": "python",
2289
+ ".pyi": "python",
2290
+ ".pyw": "python",
2291
+ ".rb": "ruby",
2292
+ ".rake": "ruby",
2293
+ ".go": "go",
2294
+ ".rs": "rust",
2295
+ ".php": "php",
2296
+ ".java": "java",
2297
+ ".kt": "kotlin",
2298
+ ".kts": "kotlin",
2299
+ ".swift": "swift",
2300
+ ".c": "c",
2301
+ ".h": "c",
2302
+ ".cc": "cpp",
2303
+ ".cpp": "cpp",
2304
+ ".cxx": "cpp",
2305
+ ".hh": "cpp",
2306
+ ".hpp": "cpp",
2307
+ ".hxx": "cpp",
2308
+ ".cs": "csharp",
2309
+ ".fs": "fsharp",
2310
+ ".fsx": "fsharp",
2311
+ ".m": "objective-c",
2312
+ ".mm": "objective-cpp",
2313
+ ".scala": "scala",
2314
+ ".sc": "scala",
2315
+ ".ex": "elixir",
2316
+ ".exs": "elixir",
2317
+ ".erl": "erlang",
2318
+ ".hrl": "erlang",
2319
+ ".hs": "haskell",
2320
+ ".lhs": "haskell",
2321
+ ".lua": "lua",
2322
+ ".r": "r",
2323
+ ".R": "r",
2324
+ ".dart": "dart",
2325
+ ".pl": "perl",
2326
+ ".pm": "perl",
2327
+ ".groovy": "groovy",
2328
+ ".gradle": "groovy",
2329
+ ".clj": "clojure",
2330
+ ".cljs": "clojure",
2331
+ ".cljc": "clojure",
2332
+ ".lisp": "common-lisp",
2333
+ ".lsp": "common-lisp",
2334
+ ".el": "emacs-lisp",
2335
+ ".scm": "scheme",
2336
+ ".ml": "ocaml",
2337
+ ".mli": "ocaml",
2338
+ ".jl": "julia",
2339
+ ".zig": "zig",
2340
+ ".nim": "nim",
2341
+ ".cr": "crystal",
2342
+ ".v": "v",
2343
+ ".vb": "vb",
2344
+ // 数据库
2345
+ ".sql": "sql",
2346
+ ".psql": "sql",
2347
+ ".mysql": "sql",
2348
+ ".prisma": "prisma",
2349
+ // IaC
2350
+ ".nix": "nix",
2351
+ ".tf": "terraform",
2352
+ ".tfvars": "terraform",
2353
+ ".hcl": "hcl",
2354
+ ".cmake": "cmake",
2355
+ ".make": "makefile",
2356
+ ".mk": "makefile",
2357
+ ".makefile": "makefile",
2358
+ // 其它
2359
+ ".diff": "diff",
2360
+ ".patch": "diff",
2361
+ ".svg": "xml",
2362
+ ".http": "http"
2363
+ };
2364
+ }
2365
+ });
2366
+
2367
+ // backend/dist/files/file-kind.js
2368
+ function getFileKind(stat3) {
2369
+ if (stat3.isSymbolicLink())
2370
+ return "symlink";
2371
+ if (stat3.isDirectory())
2372
+ return "dir";
2373
+ if (stat3.isFile())
2374
+ return "file";
2375
+ return "other";
2376
+ }
2377
+ var init_file_kind = __esm({
2378
+ "backend/dist/files/file-kind.js"() {
2379
+ "use strict";
2380
+ }
2381
+ });
2382
+
2383
+ // backend/dist/files/list-dir.js
2384
+ import { readdir, lstat } from "node:fs/promises";
2385
+ import { join } from "node:path";
2386
+ async function listDir(dirPath) {
2387
+ const dirents = await readdir(dirPath, { withFileTypes: true });
2388
+ const results = await Promise.all(dirents.map((dirent) => lstat(join(dirPath, dirent.name)).then((stat3) => {
2389
+ const kind = getFileKind(stat3);
2390
+ const entry = {
2391
+ name: dirent.name,
2392
+ kind,
2393
+ size: kind === "dir" ? 0 : stat3.size,
2394
+ mtimeMs: stat3.mtimeMs,
2395
+ hidden: dirent.name.startsWith(".")
2396
+ };
2397
+ if (kind === "file") {
2398
+ const { mime, previewable } = detectMime(dirent.name);
2399
+ entry.mime = mime;
2400
+ entry.previewable = previewable;
2401
+ }
2402
+ return entry;
2403
+ }, () => void 0)));
2404
+ return results.filter((e) => e !== void 0);
2405
+ }
2406
+ var init_list_dir = __esm({
2407
+ "backend/dist/files/list-dir.js"() {
2408
+ "use strict";
2409
+ init_mime_detect();
2410
+ init_file_kind();
2411
+ }
2412
+ });
2413
+
2414
+ // backend/dist/files/read-file.js
2415
+ import { open, stat } from "node:fs/promises";
2416
+ function probeHasAnsi(buf) {
2417
+ for (let i = 0; i < buf.length - 1; i++) {
2418
+ if (buf[i] === 27 && buf[i + 1] === 91)
2419
+ return true;
2420
+ }
2421
+ return false;
2422
+ }
2423
+ async function readTextFile(absPath) {
2424
+ const st = await stat(absPath);
2425
+ const size = st.size;
2426
+ const fh = await open(absPath, "r");
2427
+ try {
2428
+ const probeLen = Math.min(NUL_PROBE_BYTES, size);
2429
+ let hasAnsi = false;
2430
+ if (probeLen > 0) {
2431
+ const probe = Buffer.alloc(probeLen);
2432
+ await fh.read(probe, 0, probeLen, 0);
2433
+ if (probe.includes(0)) {
2434
+ throw new FileError(ErrorCode.FILE_BINARY, "file contains NUL bytes (binary)", 409);
2435
+ }
2436
+ hasAnsi = probeHasAnsi(probe);
2437
+ }
2438
+ const readLen = Math.min(size, FILE_READ_MAX_BYTES);
2439
+ const buf = Buffer.alloc(readLen);
2440
+ if (readLen > 0) {
2441
+ await fh.read(buf, 0, readLen, 0);
2442
+ }
2443
+ const content = buf.toString("utf-8");
2444
+ const truncated = size > FILE_READ_MAX_BYTES;
2445
+ if (content.length > 0) {
2446
+ let replacements = 0;
2447
+ for (const ch of content) {
2448
+ if (ch === REPLACEMENT_CHAR)
2449
+ replacements++;
2450
+ }
2451
+ const density = replacements / content.length;
2452
+ if (density > REPLACEMENT_DENSITY_LIMIT) {
2453
+ throw new FileError(ErrorCode.FILE_BINARY, `non-UTF8 content (replacement density ${(density * 100).toFixed(1)}%)`, 409);
2454
+ }
2455
+ }
2456
+ return { content, truncated, size, hasAnsi };
2457
+ } finally {
2458
+ await fh.close();
2459
+ }
2460
+ }
2461
+ var NUL_PROBE_BYTES, REPLACEMENT_CHAR, REPLACEMENT_DENSITY_LIMIT;
2462
+ var init_read_file = __esm({
2463
+ "backend/dist/files/read-file.js"() {
2464
+ "use strict";
2465
+ init_dist();
2466
+ init_errors2();
2467
+ NUL_PROBE_BYTES = 4 * 1024;
2468
+ REPLACEMENT_CHAR = "\uFFFD";
2469
+ REPLACEMENT_DENSITY_LIMIT = 0.05;
2470
+ }
2471
+ });
2472
+
2473
+ // backend/dist/files/search-engine.js
2474
+ import { opendir, open as open2, stat as stat2 } from "node:fs/promises";
2475
+ import { createInterface } from "node:readline";
2476
+ import { join as join2 } from "node:path";
2477
+ async function runSearch(opts) {
2478
+ const start = Date.now();
2479
+ let scanned = 0;
2480
+ let nameHits = 0;
2481
+ let contentHits = 0;
2482
+ let truncated = false;
2483
+ const matchers = compileMatchers(opts);
2484
+ const { nameMatch, contentMatch } = matchers;
2485
+ const queue = [];
2486
+ let walkDone = false;
2487
+ let waitResolve = null;
2488
+ let waitPromise = new Promise((r) => {
2489
+ waitResolve = r;
2490
+ });
2491
+ const wakeWorkers = () => {
2492
+ if (waitResolve) {
2493
+ const r = waitResolve;
2494
+ waitResolve = null;
2495
+ r();
2496
+ waitPromise = new Promise((rr) => {
2497
+ waitResolve = rr;
2498
+ });
2499
+ }
2500
+ };
2501
+ const openDirs = /* @__PURE__ */ new Set();
2502
+ const abortAllDirs = () => {
2503
+ for (const d of openDirs) {
2504
+ d.close().catch(() => {
2505
+ });
2506
+ }
2507
+ openDirs.clear();
2508
+ };
2509
+ const onCancel = () => {
2510
+ wakeWorkers();
2511
+ abortAllDirs();
2512
+ };
2513
+ opts.cancelSignal?.addEventListener("abort", onCancel, { once: true });
2514
+ const totalTimeoutHandle = setTimeout(onCancel, SEARCH_TOTAL_TIMEOUT_MS);
2515
+ totalTimeoutHandle.unref();
2516
+ async function walk(dir, depth) {
2517
+ if (depth > MAX_DEPTH)
2518
+ return;
2519
+ if (scanned >= MAX_ENTRIES_SCANNED) {
2520
+ truncated = true;
2521
+ return;
2522
+ }
2523
+ if (Date.now() - start > SEARCH_TOTAL_TIMEOUT_MS) {
2524
+ truncated = true;
2525
+ return;
2526
+ }
2527
+ if (opts.cancelSignal?.aborted)
2528
+ return;
2529
+ let dirh;
2530
+ try {
2531
+ dirh = await opendir(dir);
2532
+ } catch {
2533
+ return;
2534
+ }
2535
+ openDirs.add(dirh);
2536
+ if (opts.cancelSignal?.aborted) {
2537
+ openDirs.delete(dirh);
2538
+ await dirh.close().catch(() => {
2539
+ });
2540
+ return;
2541
+ }
2542
+ try {
2543
+ for await (const ent of dirh) {
2544
+ scanned++;
2545
+ if (scanned >= MAX_ENTRIES_SCANNED) {
2546
+ truncated = true;
2547
+ break;
2548
+ }
2549
+ if (Date.now() - start > SEARCH_TOTAL_TIMEOUT_MS) {
2550
+ truncated = true;
2551
+ break;
2552
+ }
2553
+ if (opts.cancelSignal?.aborted)
2554
+ break;
2555
+ const full = join2(dir, ent.name);
2556
+ if (ent.isDirectory()) {
2557
+ if (IGNORE_DIRS.has(ent.name))
2558
+ continue;
2559
+ if (checkWorkdir(full, opts.policy.allow, opts.policy.deny) !== null)
2560
+ continue;
2561
+ await walk(full, depth + 1);
2562
+ continue;
2563
+ }
2564
+ if (!ent.isFile())
2565
+ continue;
2566
+ if (opts.mode !== "content" && nameMatch(ent.name) && nameHits < SEARCH_MAX_NAME_RESULTS) {
2567
+ try {
2568
+ const st = await stat2(full);
2569
+ opts.emit({ kind: "name", path: full, size: st.size, mtimeMs: st.mtimeMs });
2570
+ nameHits++;
2571
+ } catch {
2572
+ }
2573
+ }
2574
+ if (opts.mode !== "name") {
2575
+ queue.push(full);
2576
+ wakeWorkers();
2577
+ }
2578
+ }
2579
+ } catch {
2580
+ } finally {
2581
+ openDirs.delete(dirh);
2582
+ await dirh.close().catch(() => {
2583
+ });
2584
+ }
2585
+ }
2586
+ const workers = [];
2587
+ if (opts.mode !== "name") {
2588
+ for (let i = 0; i < SEARCH_CONCURRENCY; i++) {
2589
+ workers.push((async () => {
2590
+ while (true) {
2591
+ if (contentHits >= SEARCH_MAX_CONTENT_RESULTS) {
2592
+ truncated = true;
2593
+ return;
2594
+ }
2595
+ if (Date.now() - start > SEARCH_TOTAL_TIMEOUT_MS) {
2596
+ truncated = true;
2597
+ return;
2598
+ }
2599
+ if (opts.cancelSignal?.aborted)
2600
+ return;
2601
+ const f = queue.shift();
2602
+ if (!f) {
2603
+ if (walkDone)
2604
+ return;
2605
+ await waitPromise;
2606
+ continue;
2607
+ }
2608
+ await scanFile(f);
2609
+ }
2610
+ })());
2611
+ }
2612
+ }
2613
+ try {
2614
+ await walk(opts.scope, 0);
2615
+ } finally {
2616
+ walkDone = true;
2617
+ wakeWorkers();
2618
+ }
2619
+ await Promise.all(workers);
2620
+ async function scanFile(path) {
2621
+ const fileStart = Date.now();
2622
+ let st;
2623
+ try {
2624
+ st = await stat2(path);
2625
+ } catch {
2626
+ return;
2627
+ }
2628
+ if (st.size > FILE_MAX_SCAN_BYTES)
2629
+ return;
2630
+ let fh;
2631
+ try {
2632
+ fh = await open2(path, "r");
2633
+ } catch {
2634
+ return;
2635
+ }
2636
+ let isBinary = false;
2637
+ try {
2638
+ const probeLen = Math.min(NUL_PROBE_BYTES2, st.size);
2639
+ if (probeLen > 0) {
2640
+ const buf = Buffer.alloc(probeLen);
2641
+ await fh.read(buf, 0, probeLen, 0);
2642
+ if (buf.includes(0))
2643
+ isBinary = true;
2644
+ }
2645
+ } catch {
2646
+ isBinary = true;
2647
+ }
2648
+ if (isBinary) {
2649
+ await fh.close();
2650
+ return;
2651
+ }
2652
+ await new Promise((resolveP) => {
2653
+ const stream = fh.createReadStream({ encoding: "utf-8", autoClose: true, start: 0 });
2654
+ const rl = createInterface({ input: stream, crlfDelay: Infinity });
2655
+ let lineNo = 0;
2656
+ let stopped = false;
2657
+ const stop = () => {
2658
+ if (stopped)
2659
+ return;
2660
+ stopped = true;
2661
+ rl.close();
2662
+ stream.destroy();
2663
+ resolveP();
2664
+ };
2665
+ rl.on("line", (line) => {
2666
+ lineNo++;
2667
+ if (Date.now() - fileStart > SEARCH_FILE_TIMEOUT_MS) {
2668
+ stop();
2669
+ return;
2670
+ }
2671
+ if (contentHits >= SEARCH_MAX_CONTENT_RESULTS) {
2672
+ truncated = true;
2673
+ stop();
2674
+ return;
2675
+ }
2676
+ if (opts.cancelSignal?.aborted) {
2677
+ stop();
2678
+ return;
2679
+ }
2680
+ const m = contentMatch(line);
2681
+ if (m) {
2682
+ const preview = line.length > PREVIEW_MAX_CHARS ? line.slice(0, PREVIEW_MAX_CHARS) : line;
2683
+ opts.emit({
2684
+ kind: "content",
2685
+ path,
2686
+ line: lineNo,
2687
+ preview,
2688
+ matchStart: Math.min(m.start, preview.length),
2689
+ matchEnd: Math.min(m.end, preview.length)
2690
+ });
2691
+ contentHits++;
2692
+ }
2693
+ });
2694
+ rl.on("close", () => resolveP());
2695
+ rl.on("error", () => stop());
2696
+ stream.on("error", () => stop());
2697
+ });
2698
+ }
2699
+ clearTimeout(totalTimeoutHandle);
2700
+ return {
2701
+ truncated,
2702
+ scanned,
2703
+ elapsedMs: Date.now() - start
2704
+ };
2705
+ }
2706
+ function compileMatchers(opts) {
2707
+ if (opts.regex) {
2708
+ if (opts.q.includes("\n")) {
2709
+ throw new FileError(ErrorCode.SEARCH_INVALID_Q, "cross-line regex disallowed", 400);
2710
+ }
2711
+ let re;
2712
+ try {
2713
+ re = new RegExp(opts.q, opts.caseSensitive ? "" : "i");
2714
+ } catch (err) {
2715
+ throw new FileError(ErrorCode.SEARCH_INVALID_Q, `invalid regex: ${String(err)}`, 400);
2716
+ }
2717
+ return {
2718
+ nameMatch: (n) => re.test(n),
2719
+ contentMatch: (line) => {
2720
+ const m = re.exec(line);
2721
+ re.lastIndex = 0;
2722
+ return m ? { start: m.index, end: m.index + m[0].length } : null;
2723
+ }
2724
+ };
2725
+ }
2726
+ const needle = opts.caseSensitive ? opts.q : opts.q.toLowerCase();
2727
+ return {
2728
+ nameMatch: (n) => (opts.caseSensitive ? n : n.toLowerCase()).includes(needle),
2729
+ contentMatch: (line) => {
2730
+ const hay = opts.caseSensitive ? line : line.toLowerCase();
2731
+ const idx = hay.indexOf(needle);
2732
+ return idx === -1 ? null : { start: idx, end: idx + needle.length };
2733
+ }
2734
+ };
2735
+ }
2736
+ var IGNORE_DIRS, MAX_DEPTH, MAX_ENTRIES_SCANNED, NUL_PROBE_BYTES2, PREVIEW_MAX_CHARS, FILE_MAX_SCAN_BYTES;
2737
+ var init_search_engine = __esm({
2738
+ "backend/dist/files/search-engine.js"() {
2739
+ "use strict";
2740
+ init_dist();
2741
+ init_errors2();
2742
+ init_workdir_policy();
2743
+ IGNORE_DIRS = /* @__PURE__ */ new Set([
2744
+ "node_modules",
2745
+ ".git",
2746
+ ".svn",
2747
+ ".hg",
2748
+ "dist",
2749
+ "build",
2750
+ ".next",
2751
+ ".turbo",
2752
+ ".cache",
2753
+ "target",
2754
+ ".venv",
2755
+ "__pycache__",
2756
+ ".DS_Store"
2757
+ ]);
2758
+ MAX_DEPTH = 6;
2759
+ MAX_ENTRIES_SCANNED = 5e3;
2760
+ NUL_PROBE_BYTES2 = 4 * 1024;
2761
+ PREVIEW_MAX_CHARS = 200;
2762
+ FILE_MAX_SCAN_BYTES = 2 * 1024 * 1024;
2763
+ }
2764
+ });
2765
+
2766
+ // backend/dist/api/file-routes.js
2767
+ import { Router as Router9 } from "express";
2768
+ import { createReadStream } from "node:fs";
2769
+ import { lstat as lstat2 } from "node:fs/promises";
2770
+ import { dirname as dirname3 } from "node:path";
2771
+ function createFileRoutes(opts) {
2772
+ const router = Router9();
2773
+ const { authModule, registry, workdirPolicy } = opts;
2774
+ const fileLimiter = new RateLimiter(FILE_RATE_LIMIT_PER_MIN);
2775
+ const searchLimiter = new RateLimiter(SEARCH_RATE_LIMIT_PER_MIN);
2776
+ router.get("/files/list", authModule.requireAuth, requireRate(fileLimiter), wrap(async (req, res) => {
2777
+ const tStart = Date.now();
2778
+ const ctx = await resolveContext(req, registry, workdirPolicy);
2779
+ const target = resolveSafePath(ctx.cwd, asString(req.query.path), ctx.policy);
2780
+ const entries = await listDir(target);
2781
+ const parent = computeParent(ctx.cwd, target, ctx.policy);
2782
+ const payload = {
2783
+ ok: true,
2784
+ cwd: ctx.cwd,
2785
+ path: target,
2786
+ parent,
2787
+ entries
2788
+ };
2789
+ logger.info({
2790
+ action: "list",
2791
+ instanceId: ctx.instanceId,
2792
+ path: target,
2793
+ ip: req.ip,
2794
+ elapsedMs: Date.now() - tStart
2795
+ }, "/api/files audit");
2796
+ res.json(payload);
2797
+ }));
2798
+ router.get("/files/stat", authModule.requireAuth, requireRate(fileLimiter), wrap(async (req, res) => {
2799
+ const tStart = Date.now();
2800
+ const ctx = await resolveContext(req, registry, workdirPolicy);
2801
+ const target = resolveSafePath(ctx.cwd, asString(req.query.path), ctx.policy);
2802
+ const st = await lstat2(target);
2803
+ const kind = getFileKind(st);
2804
+ const payload = {
2805
+ ok: true,
2806
+ path: target,
2807
+ kind,
2808
+ size: kind === "dir" ? 0 : st.size,
2809
+ mtimeMs: st.mtimeMs
2810
+ };
2811
+ if (kind === "file") {
2812
+ const m = detectMime(target);
2813
+ payload.mime = m.mime;
2814
+ payload.previewable = m.previewable;
2815
+ }
2816
+ logger.info({
2817
+ action: "stat",
2818
+ instanceId: ctx.instanceId,
2819
+ path: target,
2820
+ ip: req.ip,
2821
+ elapsedMs: Date.now() - tStart
2822
+ }, "/api/files audit");
2823
+ res.json(payload);
2824
+ }));
2825
+ router.get("/files/read", authModule.requireAuth, requireRate(fileLimiter), wrap(async (req, res) => {
2826
+ const tStart = Date.now();
2827
+ const ctx = await resolveContext(req, registry, workdirPolicy);
2828
+ const target = resolveSafePath(ctx.cwd, asString(req.query.path), ctx.policy);
2829
+ const st = await lstat2(target);
2830
+ if (!st.isFile()) {
2831
+ throw new FileError(ErrorCode.FILE_TYPE_FORBID, "not a regular file", 409);
2832
+ }
2833
+ const r = await readTextFile(target);
2834
+ const m = detectMime(target);
2835
+ const payload = {
2836
+ ok: true,
2837
+ path: target,
2838
+ mime: m.mime,
2839
+ content: r.content,
2840
+ truncated: r.truncated,
2841
+ size: r.size,
2842
+ lang: pickLang(m.lang, r.hasAnsi)
2843
+ };
2844
+ logger.info({
2845
+ action: "read",
2846
+ instanceId: ctx.instanceId,
2847
+ path: target,
2848
+ ip: req.ip,
2849
+ elapsedMs: Date.now() - tStart,
2850
+ size: r.size,
2851
+ truncated: r.truncated
2852
+ }, "/api/files audit");
2853
+ res.json(payload);
2854
+ }));
2855
+ router.get("/files/raw", authModule.requireAuth, requireRate(fileLimiter), async (req, res) => {
2856
+ const tStart = Date.now();
2857
+ let auditCtx;
2858
+ let auditPath;
2859
+ try {
2860
+ auditCtx = await resolveContext(req, registry, workdirPolicy);
2861
+ auditPath = resolveSafePath(auditCtx.cwd, asString(req.query.path), auditCtx.policy);
2862
+ const st = await lstat2(auditPath);
2863
+ if (!st.isFile())
2864
+ throw new FileError(ErrorCode.FILE_TYPE_FORBID, "", 409);
2865
+ if (st.size > FILE_RAW_MAX_BYTES) {
2866
+ throw new FileError(ErrorCode.FILE_TOO_LARGE, "", 413);
2867
+ }
2868
+ const { mime } = detectMime(auditPath);
2869
+ res.setHeader("Content-Type", mime);
2870
+ res.setHeader("Cache-Control", "private, max-age=0");
2871
+ res.setHeader("Content-Length", String(st.size));
2872
+ logger.info({
2873
+ action: "raw",
2874
+ instanceId: auditCtx.instanceId,
2875
+ path: auditPath,
2876
+ ip: req.ip,
2877
+ elapsedMs: Date.now() - tStart,
2878
+ size: st.size
2879
+ }, "/api/files audit");
2880
+ createReadStream(auditPath).pipe(res);
2881
+ } catch (err) {
2882
+ const code = err instanceof AppError ? err.code : ErrorCode.INTERNAL_ERROR;
2883
+ const status = err instanceof AppError ? err.httpStatus : 500;
2884
+ res.setHeader(HEADER_ATR_ERROR, String(code));
2885
+ logger.info({
2886
+ action: "raw",
2887
+ instanceId: auditCtx?.instanceId,
2888
+ path: auditPath,
2889
+ ip: req.ip,
2890
+ elapsedMs: Date.now() - tStart,
2891
+ code,
2892
+ status
2893
+ }, "/api/files audit (error)");
2894
+ res.status(status).end();
2895
+ }
2896
+ });
2897
+ router.get("/files/search", authModule.requireAuth, requireRate(searchLimiter), async (req, res) => {
2898
+ const tStart = Date.now();
2899
+ const q = asString(req.query.q);
2900
+ if (!q || q.length === 0 || q.length > SEARCH_MAX_Q_LENGTH) {
2901
+ res.status(400).json({
2902
+ error: { code: ErrorCode.BAD_REQUEST, message: "q is required (1..200)" }
2903
+ });
2904
+ return;
2905
+ }
2906
+ const modeRaw = asString(req.query.mode) ?? "name";
2907
+ if (!isSearchMode(modeRaw)) {
2908
+ res.status(400).json({
2909
+ error: { code: ErrorCode.BAD_REQUEST, message: "invalid mode" }
2910
+ });
2911
+ return;
2912
+ }
2913
+ let ctx;
2914
+ try {
2915
+ ctx = await resolveContext(req, registry, workdirPolicy);
2916
+ } catch (err) {
2917
+ if (err instanceof AppError) {
2918
+ res.status(err.httpStatus).json({ error: { code: err.code, message: err.message } });
2919
+ } else {
2920
+ res.status(500).end();
2921
+ }
2922
+ return;
2923
+ }
2924
+ let scopePath;
2925
+ try {
2926
+ scopePath = resolveSafePath(ctx.cwd, asString(req.query.scope), ctx.policy);
2927
+ const st = await lstat2(scopePath);
2928
+ if (!st.isDirectory()) {
2929
+ throw new FileError(ErrorCode.BAD_REQUEST, "scope must be a directory", 400);
2930
+ }
2931
+ } catch (err) {
2932
+ if (err instanceof AppError) {
2933
+ res.status(err.httpStatus).json({ error: { code: err.code, message: err.message } });
2934
+ } else {
2935
+ res.status(500).end();
2936
+ }
2937
+ return;
2938
+ }
2939
+ res.setHeader("Content-Type", "text/event-stream");
2940
+ res.setHeader("Cache-Control", "no-cache, no-transform");
2941
+ res.setHeader("Connection", "keep-alive");
2942
+ res.setHeader("X-Accel-Buffering", "no");
2943
+ res.flushHeaders();
2944
+ const ac = new AbortController();
2945
+ req.on("close", () => ac.abort());
2946
+ try {
2947
+ const summary = await runSearch({
2948
+ scope: scopePath,
2949
+ q,
2950
+ mode: modeRaw,
2951
+ caseSensitive: asString(req.query.caseSensitive) === "1",
2952
+ regex: asString(req.query.regex) === "1",
2953
+ policy: ctx.policy,
2954
+ cancelSignal: ac.signal,
2955
+ emit: (hit) => {
2956
+ res.write(`event: match
2957
+ data: ${JSON.stringify(hit)}
2958
+
2959
+ `);
2960
+ }
2961
+ });
2962
+ res.write(`event: done
2963
+ data: ${JSON.stringify(summary)}
2964
+
2965
+ `);
2966
+ logger.info({
2967
+ action: "search",
2968
+ instanceId: ctx.instanceId,
2969
+ path: scopePath,
2970
+ ip: req.ip,
2971
+ elapsedMs: Date.now() - tStart,
2972
+ scanned: summary.scanned,
2973
+ truncated: summary.truncated
2974
+ }, "/api/files audit");
2975
+ } catch (err) {
2976
+ const code = err instanceof AppError ? err.code : ErrorCode.INTERNAL_ERROR;
2977
+ const message = err instanceof Error ? err.message : String(err);
2978
+ res.write(`event: error
2979
+ data: ${JSON.stringify({ code, message })}
2980
+
2981
+ `);
2982
+ logger.warn({
2983
+ action: "search",
2984
+ instanceId: ctx.instanceId,
2985
+ path: scopePath,
2986
+ ip: req.ip,
2987
+ elapsedMs: Date.now() - tStart,
2988
+ code
2989
+ }, "/api/files audit (error)");
2990
+ } finally {
2991
+ res.end();
2992
+ }
2993
+ });
2994
+ return router;
2995
+ }
2996
+ function wrap(h) {
2997
+ return async (req, res, _next) => {
2998
+ try {
2999
+ await h(req, res);
3000
+ } catch (err) {
3001
+ if (err instanceof AppError) {
3002
+ res.status(err.httpStatus).json({
3003
+ error: { code: err.code, message: err.message }
3004
+ });
3005
+ return;
3006
+ }
3007
+ logger.error({ err }, "/api/files unexpected error");
3008
+ res.status(500).json({
3009
+ error: { code: ErrorCode.INTERNAL_ERROR, message: "internal error" }
3010
+ });
3011
+ }
3012
+ };
3013
+ }
3014
+ function asString(v) {
3015
+ return typeof v === "string" ? v : void 0;
3016
+ }
3017
+ function requireRate(limiter) {
3018
+ return (req, res, next) => {
3019
+ const ip = req.ip ?? "unknown";
3020
+ if (!limiter.attempt(ip)) {
3021
+ res.status(429).json({
3022
+ error: { code: ErrorCode.AUTH_RATE_LIMITED, message: "rate limited" }
3023
+ });
3024
+ return;
1561
3025
  }
3026
+ next();
3027
+ };
3028
+ }
3029
+ async function resolveContext(req, registry, workdirPolicy) {
3030
+ const instanceId = req.query.instanceId;
3031
+ if (typeof instanceId !== "string" || instanceId.length === 0) {
3032
+ throw new FileError(ErrorCode.BAD_REQUEST, "instanceId is required", 400);
1562
3033
  }
1563
- if (!out.some((e) => e.kind === "loopback")) {
1564
- out.push({ host: "127.0.0.1", port, kind: "loopback" });
3034
+ const all = await registry.list();
3035
+ const inst = all.find((i) => i.instanceId === instanceId);
3036
+ if (!inst) {
3037
+ throw new FileError(ErrorCode.INSTANCE_NOT_FOUND, `instance not found: ${instanceId}`, 404);
1565
3038
  }
1566
- const order = {
1567
- lan: 0,
1568
- tailscale: 1,
1569
- other: 2,
1570
- ipv6: 3,
1571
- loopback: 4
3039
+ const snap = workdirPolicy();
3040
+ return {
3041
+ cwd: inst.cwd,
3042
+ policy: { allow: snap.allow, deny: snap.deny },
3043
+ instanceId
1572
3044
  };
1573
- out.sort((a, b) => {
1574
- if (a.kind !== b.kind)
1575
- return order[a.kind] - order[b.kind];
1576
- if (a.host === displayIp)
1577
- return -1;
1578
- if (b.host === displayIp)
1579
- return 1;
1580
- return 0;
1581
- });
1582
- let defaultIdx = out.findIndex((e) => e.host === displayIp);
1583
- if (defaultIdx === -1) {
1584
- defaultIdx = out.findIndex((e) => e.kind !== "loopback");
1585
- }
1586
- if (defaultIdx === -1 && out.length > 0)
1587
- defaultIdx = 0;
1588
- if (defaultIdx >= 0)
1589
- out[defaultIdx].isDefault = true;
1590
- return out;
1591
3045
  }
1592
- function classify(ip, family) {
1593
- if (isLoopbackIp(ip))
1594
- return "loopback";
1595
- if (family === "IPv6")
1596
- return "ipv6";
1597
- if (isTailscaleIp(ip))
1598
- return "tailscale";
1599
- if (isPrivateIp(ip))
1600
- return "lan";
1601
- if (isLinkLocal(ip))
1602
- return "other";
1603
- return "other";
3046
+ function pickLang(baseLang, hasAnsi) {
3047
+ if (hasAnsi && (baseLang === "txt" || baseLang === "log")) {
3048
+ return "ansi";
3049
+ }
3050
+ return baseLang;
1604
3051
  }
1605
- var init_share_routes = __esm({
1606
- "backend/dist/api/share-routes.js"() {
1607
- "use strict";
1608
- init_network();
3052
+ function computeParent(cwd, current, policy) {
3053
+ if (current === cwd)
3054
+ return null;
3055
+ const parentPath = dirname3(current);
3056
+ if (parentPath === current)
3057
+ return null;
3058
+ try {
3059
+ resolveSafePath(cwd, parentPath, policy);
3060
+ return parentPath;
3061
+ } catch {
3062
+ return null;
1609
3063
  }
1610
- });
1611
-
1612
- // backend/dist/api/workdir-policy-routes.js
1613
- import { Router as Router8 } from "express";
1614
- function createWorkdirPolicyRoutes(authModule, snapshot) {
1615
- const router = Router8();
1616
- router.get("/workdir-policy", authModule.requireAuth, (_req, res) => {
1617
- const s = snapshot();
1618
- res.json({ ok: true, allow: s.allow });
1619
- });
1620
- return router;
1621
3064
  }
1622
- var init_workdir_policy_routes = __esm({
1623
- "backend/dist/api/workdir-policy-routes.js"() {
3065
+ var init_file_routes = __esm({
3066
+ "backend/dist/api/file-routes.js"() {
1624
3067
  "use strict";
3068
+ init_dist();
3069
+ init_errors2();
3070
+ init_logger();
3071
+ init_rate_limiter();
3072
+ init_forwarded_headers();
3073
+ init_constants2();
3074
+ init_path_resolver();
3075
+ init_list_dir();
3076
+ init_mime_detect();
3077
+ init_read_file();
3078
+ init_search_engine();
3079
+ init_file_kind();
1625
3080
  }
1626
3081
  });
1627
3082
 
1628
3083
  // backend/dist/api/router.js
1629
- import { Router as Router9 } from "express";
3084
+ import { Router as Router10 } from "express";
1630
3085
  function createBrokerApiRouter(opts) {
1631
- const router = Router9();
3086
+ const router = Router10();
1632
3087
  router.use(createHealthRoutes());
1633
3088
  router.use(createAuthRoutes(opts.authModule));
1634
3089
  router.use(createConfigRoutes(opts.authModule, opts.configStore));
@@ -1644,10 +3099,15 @@ function createBrokerApiRouter(opts) {
1644
3099
  displayIp: opts.displayIp
1645
3100
  }));
1646
3101
  router.use(createWorkdirPolicyRoutes(opts.authModule, opts.workdirPolicy));
3102
+ router.use(createFileRoutes({
3103
+ authModule: opts.authModule,
3104
+ registry: opts.registry,
3105
+ workdirPolicy: opts.workdirPolicy
3106
+ }));
1647
3107
  return router;
1648
3108
  }
1649
3109
  function createWorkerApiRouter(opts) {
1650
- const router = Router9();
3110
+ const router = Router10();
1651
3111
  router.use(createHealthRoutes());
1652
3112
  router.use(createHookRoutes(opts.integrations));
1653
3113
  return router;
@@ -1663,31 +3123,7 @@ var init_router = __esm({
1663
3123
  init_push_routes();
1664
3124
  init_share_routes();
1665
3125
  init_workdir_policy_routes();
1666
- }
1667
- });
1668
-
1669
- // backend/dist/constants.js
1670
- var WS_FLUSH_INTERVAL_MS, WS_MAX_CHUNK_BYTES, WS_HIGH_WATERMARK_BYTES, FILE_LOCK_RETRIES, FILE_LOCK_RETRY_INTERVAL_MS, FILE_LOCK_STALE_MS, PTY_DEFAULT_COLS, PTY_DEFAULT_ROWS, PTY_TERM_NAME, DOUBLE_PULSE_DELAY_MS, SHUTDOWN_WS_FLUSH_DELAY_MS, SHUTDOWN_FORCE_EXIT_MS, DOUBLE_CTRL_C_WINDOW_MS, PORT_FINDER_MAX_ATTEMPTS, STOP_INSTANCE_GRACE_MS, STOP_INSTANCE_POLL_INTERVAL_MS, ATTACH_RECONNECT_DELAYS_MS;
1671
- var init_constants2 = __esm({
1672
- "backend/dist/constants.js"() {
1673
- "use strict";
1674
- WS_FLUSH_INTERVAL_MS = 16;
1675
- WS_MAX_CHUNK_BYTES = 32 * 1024;
1676
- WS_HIGH_WATERMARK_BYTES = 256 * 1024;
1677
- FILE_LOCK_RETRIES = 50;
1678
- FILE_LOCK_RETRY_INTERVAL_MS = 50;
1679
- FILE_LOCK_STALE_MS = 1e4;
1680
- PTY_DEFAULT_COLS = 80;
1681
- PTY_DEFAULT_ROWS = 24;
1682
- PTY_TERM_NAME = "xterm-256color";
1683
- DOUBLE_PULSE_DELAY_MS = 50;
1684
- SHUTDOWN_WS_FLUSH_DELAY_MS = 500;
1685
- SHUTDOWN_FORCE_EXIT_MS = 2e3;
1686
- DOUBLE_CTRL_C_WINDOW_MS = 500;
1687
- PORT_FINDER_MAX_ATTEMPTS = 100;
1688
- STOP_INSTANCE_GRACE_MS = 3e3;
1689
- STOP_INSTANCE_POLL_INTERVAL_MS = 100;
1690
- ATTACH_RECONNECT_DELAYS_MS = [1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
3126
+ init_file_routes();
1691
3127
  }
1692
3128
  });
1693
3129
 
@@ -2931,87 +4367,6 @@ var init_terminal_relay = __esm({
2931
4367
  }
2932
4368
  });
2933
4369
 
2934
- // backend/dist/auth/rate-limiter.js
2935
- var RateLimiter;
2936
- var init_rate_limiter = __esm({
2937
- "backend/dist/auth/rate-limiter.js"() {
2938
- "use strict";
2939
- init_logger();
2940
- RateLimiter = class {
2941
- entries = /* @__PURE__ */ new Map();
2942
- maxAttempts;
2943
- windowMs;
2944
- cleanupTimer = null;
2945
- /**
2946
- * @param maxAttempts 窗口内最大允许次数
2947
- * @param windowMs 窗口长度(毫秒),默认 60s
2948
- */
2949
- constructor(maxAttempts, windowMs = 6e4) {
2950
- if (!Number.isInteger(maxAttempts) || maxAttempts <= 0) {
2951
- throw new Error("RateLimiter: maxAttempts \u5FC5\u987B\u662F\u6B63\u6574\u6570");
2952
- }
2953
- this.maxAttempts = maxAttempts;
2954
- this.windowMs = windowMs;
2955
- this.cleanupTimer = setInterval(() => this.cleanup(), windowMs * 2);
2956
- if (typeof this.cleanupTimer.unref === "function") {
2957
- this.cleanupTimer.unref();
2958
- }
2959
- }
2960
- /**
2961
- * 尝试一次请求,自动累加计数
2962
- *
2963
- * @returns true 通过 / false 已超限被拒
2964
- */
2965
- attempt(ip) {
2966
- const now = Date.now();
2967
- const entry = this.entries.get(ip);
2968
- if (!entry || now >= entry.resetAt) {
2969
- this.entries.set(ip, { count: 1, resetAt: now + this.windowMs });
2970
- return true;
2971
- }
2972
- entry.count++;
2973
- if (entry.count > this.maxAttempts) {
2974
- logger.warn({ ip, count: entry.count, max: this.maxAttempts }, "\u8BA4\u8BC1\u901F\u7387\u8D85\u9650");
2975
- return false;
2976
- }
2977
- return true;
2978
- }
2979
- /** 当前窗口内剩余次数 */
2980
- remaining(ip) {
2981
- const now = Date.now();
2982
- const entry = this.entries.get(ip);
2983
- if (!entry || now >= entry.resetAt)
2984
- return this.maxAttempts;
2985
- return Math.max(0, this.maxAttempts - entry.count);
2986
- }
2987
- /**
2988
- * 重置某 IP 的计数(认证成功后清零)
2989
- *
2990
- * 让合法用户不会因为之前误输导致后续尝试被限流
2991
- */
2992
- reset(ip) {
2993
- this.entries.delete(ip);
2994
- }
2995
- /** 清理过期 entry(避免内存膨胀) */
2996
- cleanup() {
2997
- const now = Date.now();
2998
- for (const [ip, entry] of this.entries) {
2999
- if (now >= entry.resetAt) {
3000
- this.entries.delete(ip);
3001
- }
3002
- }
3003
- }
3004
- /** 销毁定时器 */
3005
- destroy() {
3006
- if (this.cleanupTimer) {
3007
- clearInterval(this.cleanupTimer);
3008
- this.cleanupTimer = null;
3009
- }
3010
- }
3011
- };
3012
- }
3013
- });
3014
-
3015
4370
  // backend/dist/auth/auth-middleware.js
3016
4371
  import { timingSafeEqual } from "node:crypto";
3017
4372
  import * as cookie from "cookie";
@@ -3282,7 +4637,7 @@ var init_token_generator = __esm({
3282
4637
 
3283
4638
  // backend/dist/sessions/sessions-store.js
3284
4639
  import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync2 } from "node:fs";
3285
- import { dirname as dirname3, resolve as resolve3 } from "node:path";
4640
+ import { dirname as dirname4, resolve as resolve3 } from "node:path";
3286
4641
  import { homedir } from "node:os";
3287
4642
  function defaultSessionsPath() {
3288
4643
  return resolve3(homedir(), ATR_DATA_DIR, SESSIONS_FILENAME);
@@ -3340,7 +4695,7 @@ var init_sessions_store = __esm({
3340
4695
  sessionTtlMs;
3341
4696
  constructor(opts) {
3342
4697
  this.path = opts.path ?? defaultSessionsPath();
3343
- this.lockDir = opts.lockDir ?? resolve3(dirname3(this.path), SESSIONS_LOCK_DIRNAME);
4698
+ this.lockDir = opts.lockDir ?? resolve3(dirname4(this.path), SESSIONS_LOCK_DIRNAME);
3344
4699
  this.sessionTtlMs = opts.sessionTtlMs;
3345
4700
  }
3346
4701
  // ──────────────── 公共 API ────────────────
@@ -3464,7 +4819,7 @@ var init_sessions_store = __esm({
3464
4819
  }
3465
4820
  /** 原子写 + 确保父目录存在 */
3466
4821
  persist(data) {
3467
- const dir = dirname3(this.path);
4822
+ const dir = dirname4(this.path);
3468
4823
  if (!existsSync2(dir)) {
3469
4824
  try {
3470
4825
  mkdirSync3(dir, { recursive: true, mode: 448 });
@@ -3523,7 +4878,7 @@ var init_ws_authenticate = __esm({
3523
4878
 
3524
4879
  // backend/dist/config.js
3525
4880
  import { existsSync as existsSync3, readFileSync as readFileSync3, mkdirSync as mkdirSync4, copyFileSync } from "node:fs";
3526
- import { resolve as resolve4, basename as basename2 } from "node:path";
4881
+ import { resolve as resolve4, basename as basename3 } from "node:path";
3527
4882
  import { homedir as homedir2 } from "node:os";
3528
4883
  import { statSync as statSync2 } from "node:fs";
3529
4884
  function extractSettingsFromArgs(args) {
@@ -3656,7 +5011,7 @@ function loadConfig(deps) {
3656
5011
  const claudeCwd = cli.workdir ?? env["OCR_CWD"] ?? process.cwd();
3657
5012
  const explicitArgs = mergeClaudeArgs(cli.claudeArgs, env["OCR_ARGS"]);
3658
5013
  const claudeArgs = explicitArgs.length > 0 || explicitCommand !== void 0 ? explicitArgs : defaultShellArgs(claudeCommand);
3659
- const instanceName = cli.instanceName ?? env["INSTANCE_NAME"] ?? (basename2(claudeCwd) || "instance");
5014
+ const instanceName = cli.instanceName ?? env["INSTANCE_NAME"] ?? (basename3(claudeCwd) || "instance");
3660
5015
  const maxBufferLines = cli.maxBufferLines ?? toInt(env["MAX_BUFFER_LINES"]) ?? DEFAULT_MAX_BUFFER_LINES;
3661
5016
  const sessionTtlMs = cli.sessionTtlMs ?? toInt(env["SESSION_TTL_MS"]) ?? DEFAULT_SESSION_TTL_MS;
3662
5017
  const authRateLimit = cli.authRateLimit ?? toInt(env["AUTH_RATE_LIMIT"]) ?? DEFAULT_AUTH_RATE_LIMIT;
@@ -3889,9 +5244,9 @@ var init_manager = __esm({
3889
5244
  });
3890
5245
 
3891
5246
  // backend/dist/integrations/claude-code/detect.js
3892
- import { basename as basename3 } from "node:path";
5247
+ import { basename as basename4 } from "node:path";
3893
5248
  function isClaudeCommand(command) {
3894
- let name = basename3(command).toLowerCase();
5249
+ let name = basename4(command).toLowerCase();
3895
5250
  for (const suffix of WIN_SUFFIXES) {
3896
5251
  if (name.endsWith(suffix)) {
3897
5252
  name = name.slice(0, -suffix.length);
@@ -4050,7 +5405,7 @@ function extractToolFromMessage(message) {
4050
5405
  const m = TOOL_NAME_RE.exec(message);
4051
5406
  return m?.[1] ?? null;
4052
5407
  }
4053
- function asString(v) {
5408
+ function asString2(v) {
4054
5409
  return typeof v === "string" && v.length > 0 ? v : void 0;
4055
5410
  }
4056
5411
  function asBool(v) {
@@ -4060,35 +5415,35 @@ function asNumber(v) {
4060
5415
  return typeof v === "number" && Number.isFinite(v) ? v : void 0;
4061
5416
  }
4062
5417
  function deriveApprovalId(payload) {
4063
- const toolUseId = asString(payload["tool_use_id"]);
5418
+ const toolUseId = asString2(payload["tool_use_id"]);
4064
5419
  if (toolUseId)
4065
5420
  return toolUseId;
4066
- const tool = asString(payload["tool_name"]) ?? extractToolFromMessage(payload["message"]) ?? "unknown";
5421
+ const tool = asString2(payload["tool_name"]) ?? extractToolFromMessage(payload["message"]) ?? "unknown";
4067
5422
  return `pending:${tool}`;
4068
5423
  }
4069
5424
  function mapHookPayload(payload) {
4070
5425
  if (!payload || typeof payload !== "object")
4071
5426
  return [];
4072
5427
  const p = payload;
4073
- const event = asString(p["hook_event_name"]);
5428
+ const event = asString2(p["hook_event_name"]);
4074
5429
  if (!event)
4075
5430
  return [];
4076
5431
  switch (event) {
4077
5432
  case "Notification": {
4078
5433
  if (p["notification_type"] !== "permission_prompt")
4079
5434
  return [];
4080
- const tool = asString(p["tool_name"]) ?? extractToolFromMessage(p["message"]) ?? "unknown_tool";
5435
+ const tool = asString2(p["tool_name"]) ?? extractToolFromMessage(p["message"]) ?? "unknown_tool";
4081
5436
  return [
4082
5437
  {
4083
5438
  kind: "approval_pending",
4084
5439
  id: deriveApprovalId(p),
4085
5440
  tool,
4086
- ...asString(p["message"]) ? { detail: asString(p["message"]) } : {}
5441
+ ...asString2(p["message"]) ? { detail: asString2(p["message"]) } : {}
4087
5442
  }
4088
5443
  ];
4089
5444
  }
4090
5445
  case "PermissionRequest": {
4091
- const tool = asString(p["tool_name"]) ?? "unknown_tool";
5446
+ const tool = asString2(p["tool_name"]) ?? "unknown_tool";
4092
5447
  const summary = summarizeToolCall(tool, p["tool_input"]);
4093
5448
  return [
4094
5449
  {
@@ -4100,18 +5455,18 @@ function mapHookPayload(payload) {
4100
5455
  ];
4101
5456
  }
4102
5457
  case "PreToolUse": {
4103
- const tool = asString(p["tool_name"]) ?? "unknown_tool";
5458
+ const tool = asString2(p["tool_name"]) ?? "unknown_tool";
4104
5459
  return [
4105
5460
  {
4106
5461
  kind: "tool_started",
4107
- toolUseId: asString(p["tool_use_id"]) ?? deriveApprovalId(p),
5462
+ toolUseId: asString2(p["tool_use_id"]) ?? deriveApprovalId(p),
4108
5463
  tool,
4109
5464
  summary: summarizeToolCall(tool, p["tool_input"])
4110
5465
  }
4111
5466
  ];
4112
5467
  }
4113
5468
  case "PostToolUse": {
4114
- const id = asString(p["tool_use_id"]) ?? deriveApprovalId(p);
5469
+ const id = asString2(p["tool_use_id"]) ?? deriveApprovalId(p);
4115
5470
  const events = [
4116
5471
  { kind: "tool_finished", toolUseId: id, ok: true, ...asNumber(p["duration_ms"]) !== void 0 ? { durationMs: asNumber(p["duration_ms"]) } : {} },
4117
5472
  { kind: "approval_resolved", id, outcome: "allow" }
@@ -4119,7 +5474,7 @@ function mapHookPayload(payload) {
4119
5474
  return events;
4120
5475
  }
4121
5476
  case "PostToolUseFailure": {
4122
- const id = asString(p["tool_use_id"]) ?? deriveApprovalId(p);
5477
+ const id = asString2(p["tool_use_id"]) ?? deriveApprovalId(p);
4123
5478
  const interrupted = asBool(p["is_interrupt"]) === true;
4124
5479
  const events = [
4125
5480
  {
@@ -4127,14 +5482,14 @@ function mapHookPayload(payload) {
4127
5482
  toolUseId: id,
4128
5483
  ok: false,
4129
5484
  ...asNumber(p["duration_ms"]) !== void 0 ? { durationMs: asNumber(p["duration_ms"]) } : {},
4130
- ...asString(p["error"]) ? { error: asString(p["error"]) } : {}
5485
+ ...asString2(p["error"]) ? { error: asString2(p["error"]) } : {}
4131
5486
  },
4132
5487
  { kind: "approval_resolved", id, outcome: interrupted ? "deny" : "unknown" }
4133
5488
  ];
4134
5489
  return events;
4135
5490
  }
4136
5491
  case "UserPromptSubmit": {
4137
- const text = asString(p["prompt"]);
5492
+ const text = asString2(p["prompt"]);
4138
5493
  if (!text)
4139
5494
  return [];
4140
5495
  return [{ kind: "user_prompt", text }];
@@ -4143,7 +5498,7 @@ function mapHookPayload(payload) {
4143
5498
  return [
4144
5499
  {
4145
5500
  kind: "turn_ended",
4146
- ...asString(p["last_assistant_message"]) ? { lastMessage: asString(p["last_assistant_message"]) } : {}
5501
+ ...asString2(p["last_assistant_message"]) ? { lastMessage: asString2(p["last_assistant_message"]) } : {}
4147
5502
  }
4148
5503
  ];
4149
5504
  }
@@ -4151,8 +5506,8 @@ function mapHookPayload(payload) {
4151
5506
  return [
4152
5507
  {
4153
5508
  kind: "turn_failed",
4154
- errorKind: asString(p["error"]) ?? "unknown",
4155
- ...asString(p["error_details"]) ? { detail: asString(p["error_details"]) } : {}
5509
+ errorKind: asString2(p["error"]) ?? "unknown",
5510
+ ...asString2(p["error_details"]) ? { detail: asString2(p["error_details"]) } : {}
4156
5511
  }
4157
5512
  ];
4158
5513
  }
@@ -4161,7 +5516,7 @@ function mapHookPayload(payload) {
4161
5516
  {
4162
5517
  kind: "session_event",
4163
5518
  phase: "start",
4164
- ...asString(p["source"]) ? { detail: asString(p["source"]) } : {}
5519
+ ...asString2(p["source"]) ? { detail: asString2(p["source"]) } : {}
4165
5520
  }
4166
5521
  ];
4167
5522
  }
@@ -4170,7 +5525,7 @@ function mapHookPayload(payload) {
4170
5525
  {
4171
5526
  kind: "session_event",
4172
5527
  phase: "end",
4173
- ...asString(p["reason"]) ? { detail: asString(p["reason"]) } : {}
5528
+ ...asString2(p["reason"]) ? { detail: asString2(p["reason"]) } : {}
4174
5529
  }
4175
5530
  ];
4176
5531
  }
@@ -4179,7 +5534,7 @@ function mapHookPayload(payload) {
4179
5534
  {
4180
5535
  kind: "session_event",
4181
5536
  phase: "compact_start",
4182
- ...asString(p["trigger"]) ? { detail: asString(p["trigger"]) } : {}
5537
+ ...asString2(p["trigger"]) ? { detail: asString2(p["trigger"]) } : {}
4183
5538
  }
4184
5539
  ];
4185
5540
  }
@@ -4188,13 +5543,13 @@ function mapHookPayload(payload) {
4188
5543
  {
4189
5544
  kind: "session_event",
4190
5545
  phase: "compact_end",
4191
- ...asString(p["trigger"]) ? { detail: asString(p["trigger"]) } : {}
5546
+ ...asString2(p["trigger"]) ? { detail: asString2(p["trigger"]) } : {}
4192
5547
  }
4193
5548
  ];
4194
5549
  }
4195
5550
  case "CwdChanged": {
4196
- const from = asString(p["old_cwd"]);
4197
- const to = asString(p["new_cwd"]);
5551
+ const from = asString2(p["old_cwd"]);
5552
+ const to = asString2(p["new_cwd"]);
4198
5553
  if (!from || !to)
4199
5554
  return [];
4200
5555
  return [{ kind: "cwd_changed", from, to }];
@@ -4968,13 +6323,13 @@ __export(resolve_executable_exports, {
4968
6323
  resolveExecutable: () => resolveExecutable
4969
6324
  });
4970
6325
  import { accessSync, existsSync as existsSync9, readdirSync, statSync as statSync3, constants } from "node:fs";
4971
- import { resolve as pathResolve, isAbsolute, sep } from "node:path";
6326
+ import { resolve as pathResolve, isAbsolute as isAbsolute2, sep } from "node:path";
4972
6327
  import { delimiter } from "node:path";
4973
6328
  function resolveExecutable(program, env = process.env) {
4974
6329
  if (!program || program.length === 0)
4975
6330
  return null;
4976
6331
  if (program.includes("/") || program.includes(sep)) {
4977
- const abs = isAbsolute(program) ? program : pathResolve(program);
6332
+ const abs = isAbsolute2(program) ? program : pathResolve(program);
4978
6333
  return isExecutable(abs) ? abs : null;
4979
6334
  }
4980
6335
  const pathEnv = env["PATH"] ?? env["Path"] ?? "";
@@ -5073,7 +6428,7 @@ function colorsEnabled() {
5073
6428
  }
5074
6429
  return Boolean(process.stdout.isTTY);
5075
6430
  }
5076
- function wrap(fn) {
6431
+ function wrap2(fn) {
5077
6432
  return (s) => colorsEnabled() ? fn(s) : s;
5078
6433
  }
5079
6434
  var pcForced, forceDisabled, c;
@@ -5083,14 +6438,14 @@ var init_colors = __esm({
5083
6438
  pcForced = pc.createColors(true);
5084
6439
  forceDisabled = false;
5085
6440
  c = {
5086
- bold: wrap(pcForced.bold),
5087
- dim: wrap(pcForced.dim),
5088
- red: wrap(pcForced.red),
5089
- green: wrap(pcForced.green),
5090
- yellow: wrap(pcForced.yellow),
5091
- blue: wrap(pcForced.blue),
5092
- cyan: wrap(pcForced.cyan),
5093
- gray: wrap(pcForced.gray)
6441
+ bold: wrap2(pcForced.bold),
6442
+ dim: wrap2(pcForced.dim),
6443
+ red: wrap2(pcForced.red),
6444
+ green: wrap2(pcForced.green),
6445
+ yellow: wrap2(pcForced.yellow),
6446
+ blue: wrap2(pcForced.blue),
6447
+ cyan: wrap2(pcForced.cyan),
6448
+ gray: wrap2(pcForced.gray)
5094
6449
  };
5095
6450
  }
5096
6451
  });
@@ -5121,7 +6476,7 @@ var init_did_you_mean = __esm({
5121
6476
 
5122
6477
  // backend/dist/broker/broker-state.js
5123
6478
  import { existsSync as existsSync10, mkdirSync as mkdirSync9, readFileSync as readFileSync7, rmSync as rmSync2 } from "node:fs";
5124
- import { dirname as dirname4, resolve as resolve9 } from "node:path";
6479
+ import { dirname as dirname5, resolve as resolve9 } from "node:path";
5125
6480
  import { homedir as homedir7 } from "node:os";
5126
6481
  function defaultBrokerStatePath() {
5127
6482
  return resolve9(homedir7(), ATR_DATA_DIR, BROKER_STATE_FILENAME);
@@ -5162,7 +6517,7 @@ function readBrokerState(path = defaultBrokerStatePath()) {
5162
6517
  return { version: SCHEMA_VERSION2, pid, port, host, startedAt, brokerVersion };
5163
6518
  }
5164
6519
  function writeBrokerState(state, path = defaultBrokerStatePath()) {
5165
- const dir = dirname4(path);
6520
+ const dir = dirname5(path);
5166
6521
  if (!existsSync10(dir)) {
5167
6522
  try {
5168
6523
  mkdirSync9(dir, { recursive: true, mode: 448 });
@@ -5548,6 +6903,10 @@ function createBrokerApp(opts) {
5548
6903
  if (req.path.startsWith("/api") || req.path.startsWith("/ws")) {
5549
6904
  return next();
5550
6905
  }
6906
+ if (isStaticAssetPath(req.path)) {
6907
+ res.status(404).type("text/plain").send("not found");
6908
+ return;
6909
+ }
5551
6910
  const instanceId = req.__atrInstanceId;
5552
6911
  const urlToken = typeof req.query.token === "string" ? req.query.token : null;
5553
6912
  if (!instanceId && !urlToken) {
@@ -5635,6 +6994,11 @@ async function startBrokerServer(opts) {
5635
6994
  }
5636
6995
  };
5637
6996
  }
6997
+ function isStaticAssetPath(p) {
6998
+ if (p.startsWith("/assets/"))
6999
+ return true;
7000
+ return STATIC_EXT_RE.test(p);
7001
+ }
5638
7002
  function collectLocalHostnames() {
5639
7003
  const set = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
5640
7004
  const ifaces = networkInterfaces3();
@@ -5655,7 +7019,7 @@ function collectLocalHostnames() {
5655
7019
  }
5656
7020
  return set;
5657
7021
  }
5658
- var DEFAULT_BROKER_PORT, DEFAULT_BROKER_HOST;
7022
+ var DEFAULT_BROKER_PORT, DEFAULT_BROKER_HOST, STATIC_EXT_RE;
5659
7023
  var init_broker_server = __esm({
5660
7024
  "backend/dist/broker/broker-server.js"() {
5661
7025
  "use strict";
@@ -5667,13 +7031,14 @@ var init_broker_server = __esm({
5667
7031
  init_port_finder();
5668
7032
  DEFAULT_BROKER_PORT = 3737;
5669
7033
  DEFAULT_BROKER_HOST = "0.0.0.0";
7034
+ STATIC_EXT_RE = /\.(js|mjs|cjs|css|map|json|webmanifest|png|jpg|jpeg|gif|svg|webp|ico|avif|woff|woff2|ttf|otf|wasm)$/i;
5670
7035
  }
5671
7036
  });
5672
7037
 
5673
7038
  // backend/dist/broker/ensure-broker.js
5674
7039
  import { spawn as spawn2 } from "node:child_process";
5675
7040
  import { existsSync as existsSync12, mkdirSync as mkdirSync10, openSync } from "node:fs";
5676
- import { dirname as dirname5, resolve as resolve11 } from "node:path";
7041
+ import { dirname as dirname6, resolve as resolve11 } from "node:path";
5677
7042
  import { homedir as homedir8 } from "node:os";
5678
7043
  function defaultBrokerLockDir() {
5679
7044
  return resolve11(homedir8(), ATR_DATA_DIR, ".broker.lock");
@@ -5756,7 +7121,7 @@ function resolveBrokerEntry(cliJsPath) {
5756
7121
  return { execPath: process.execPath, args: [cliJsPath] };
5757
7122
  }
5758
7123
  function ensureParentDir(lockDir) {
5759
- const parent = dirname5(lockDir);
7124
+ const parent = dirname6(lockDir);
5760
7125
  if (existsSync12(parent))
5761
7126
  return;
5762
7127
  try {
@@ -5996,7 +7361,7 @@ var entry_prompt_exports = {};
5996
7361
  __export(entry_prompt_exports, {
5997
7362
  promptEntrySelection: () => promptEntrySelection
5998
7363
  });
5999
- import { createInterface } from "node:readline";
7364
+ import { createInterface as createInterface2 } from "node:readline";
6000
7365
  async function promptEntrySelection(opts) {
6001
7366
  const { candidates } = opts;
6002
7367
  if (candidates.length === 0) {
@@ -6026,7 +7391,7 @@ async function promptEntrySelection(opts) {
6026
7391
  const timeoutMs = opts.timeoutMs ?? 0;
6027
7392
  const useTimeout = timeoutMs > 0;
6028
7393
  const promptLine = useTimeout ? ` \u9009\u62E9 [1-${candidates.length}\uFF0C\u56DE\u8F66=${defaultIdx + 1}\uFF0C${Math.round(timeoutMs / 1e3)}s \u8D85\u65F6\u9ED8\u8BA4]: ` : ` \u9009\u62E9 [1-${candidates.length}\uFF0C\u56DE\u8F66=${defaultIdx + 1}]: `;
6029
- const rl = createInterface({
7394
+ const rl = createInterface2({
6030
7395
  input,
6031
7396
  output,
6032
7397
  terminal: false
@@ -6091,7 +7456,7 @@ __export(index_exports, {
6091
7456
  import { createServer as createServer3 } from "node:http";
6092
7457
  import { execSync } from "node:child_process";
6093
7458
  import { networkInterfaces as networkInterfaces5 } from "node:os";
6094
- import { resolve as resolve12, dirname as dirname6 } from "node:path";
7459
+ import { resolve as resolve12, dirname as dirname7 } from "node:path";
6095
7460
  import { fileURLToPath as fileURLToPath2 } from "node:url";
6096
7461
  import express2 from "express";
6097
7462
  import cors2 from "cors";
@@ -6157,7 +7522,7 @@ async function startServer(overrides = {}) {
6157
7522
  }
6158
7523
  logger.info({ requested: cfg.claudeCommand, resolved }, "PTY program resolved");
6159
7524
  }
6160
- const __dirnameForBroker = dirname6(fileURLToPath2(import.meta.url));
7525
+ const __dirnameForBroker = dirname7(fileURLToPath2(import.meta.url));
6161
7526
  const cliJsPathForBroker = resolve12(__dirnameForBroker, "cli.js");
6162
7527
  const { ensureBroker: ensureBroker2 } = await Promise.resolve().then(() => (init_broker(), broker_exports));
6163
7528
  let brokerState;
@@ -6249,7 +7614,7 @@ hint: check whether ~/.atr/broker.json is held by a stale process; set ATR_DEBUG
6249
7614
  legacyCookieNames: [createSessionCookieName(cfg.port)],
6250
7615
  sessions: sessionsStore
6251
7616
  });
6252
- const __dirname2 = dirname6(fileURLToPath2(import.meta.url));
7617
+ const __dirname2 = dirname7(fileURLToPath2(import.meta.url));
6253
7618
  const registry = new InstanceRegistryManager();
6254
7619
  const localHostnames = collectLocalHostnames2();
6255
7620
  logger.info({ hostnames: Array.from(localHostnames) }, "CORS \u767D\u540D\u5355");
@@ -7305,7 +8670,7 @@ var init_attach = __esm({
7305
8670
 
7306
8671
  // backend/dist/broker/broker-log-rotator.js
7307
8672
  import { appendFileSync, existsSync as existsSync13, mkdirSync as mkdirSync11, readdirSync as readdirSync2, statSync as statSync4, unlinkSync as unlinkSync2 } from "node:fs";
7308
- import { resolve as resolve13, basename as basename4 } from "node:path";
8673
+ import { resolve as resolve13, basename as basename5 } from "node:path";
7309
8674
  function createBrokerLogRotator(opts) {
7310
8675
  const now = opts.now ?? (() => /* @__PURE__ */ new Date());
7311
8676
  if (!existsSync13(opts.dir)) {
@@ -7390,51 +8755,10 @@ var init_broker_log_rotator = __esm({
7390
8755
  }
7391
8756
  });
7392
8757
 
7393
- // backend/dist/utils/workdir-policy.js
7394
- import picomatch from "picomatch";
7395
- function checkWorkdir(cwd, allow, deny) {
7396
- const norm = normalizePath(cwd);
7397
- const opts = { dot: true };
7398
- if (deny && deny.length > 0) {
7399
- for (const pattern of deny) {
7400
- if (picomatch(pattern, opts)(norm)) {
7401
- return {
7402
- reason: `cwd "${cwd}" \u547D\u4E2D\u9ED1\u540D\u5355 pattern\uFF1A${pattern}`,
7403
- matchedPattern: pattern
7404
- };
7405
- }
7406
- }
7407
- }
7408
- if (allow && allow.length > 0) {
7409
- let hit = false;
7410
- for (const pattern of allow) {
7411
- if (picomatch(pattern, opts)(norm)) {
7412
- hit = true;
7413
- break;
7414
- }
7415
- }
7416
- if (!hit) {
7417
- return {
7418
- reason: `cwd "${cwd}" \u672A\u547D\u4E2D\u4EFB\u4F55\u767D\u540D\u5355 pattern\uFF1A[${allow.join(", ")}]`,
7419
- matchedPattern: ""
7420
- };
7421
- }
7422
- }
7423
- return null;
7424
- }
7425
- function normalizePath(p) {
7426
- return p.replace(/\\/g, "/");
7427
- }
7428
- var init_workdir_policy = __esm({
7429
- "backend/dist/utils/workdir-policy.js"() {
7430
- "use strict";
7431
- }
7432
- });
7433
-
7434
8758
  // backend/dist/registry/instance-spawner.js
7435
8759
  import { spawn as spawn3 } from "node:child_process";
7436
8760
  import { existsSync as existsSync14, statSync as statSync5, openSync as openSync2 } from "node:fs";
7437
- import { resolve as resolve14, isAbsolute as isAbsolute2, dirname as dirname7 } from "node:path";
8761
+ import { resolve as resolve14, isAbsolute as isAbsolute3, dirname as dirname8 } from "node:path";
7438
8762
  function waitForEarlyExit(child, timeoutMs) {
7439
8763
  return new Promise((res) => {
7440
8764
  let settled = false;
@@ -7460,7 +8784,7 @@ function resolveEntry(cliJsPath) {
7460
8784
  }
7461
8785
  const tsPath = cliJsPath.replace(/\.js$/, ".ts");
7462
8786
  if (existsSync14(tsPath)) {
7463
- const tsxBin = findTsxBin(dirname7(tsPath));
8787
+ const tsxBin = findTsxBin(dirname8(tsPath));
7464
8788
  if (tsxBin) {
7465
8789
  return { execPath: tsxBin, args: [tsPath] };
7466
8790
  }
@@ -7477,14 +8801,14 @@ function findTsxBin(startDir) {
7477
8801
  const candidate = resolve14(dir, "node_modules", ".bin", "tsx");
7478
8802
  if (existsSync14(candidate))
7479
8803
  return candidate;
7480
- const parent = dirname7(dir);
8804
+ const parent = dirname8(dir);
7481
8805
  if (parent === dir)
7482
8806
  break;
7483
8807
  dir = parent;
7484
8808
  }
7485
8809
  return null;
7486
8810
  }
7487
- function basename5(p) {
8811
+ function basename6(p) {
7488
8812
  const parts = p.split(/[\\/]/).filter(Boolean);
7489
8813
  return parts[parts.length - 1] ?? "instance";
7490
8814
  }
@@ -7502,7 +8826,7 @@ var init_instance_spawner = __esm({
7502
8826
  this.opts = opts;
7503
8827
  }
7504
8828
  async spawn(input) {
7505
- const cwd = isAbsolute2(input.cwd) ? input.cwd : resolve14(input.cwd);
8829
+ const cwd = isAbsolute3(input.cwd) ? input.cwd : resolve14(input.cwd);
7506
8830
  if (!existsSync14(cwd)) {
7507
8831
  throw new InstanceError(ErrorCode.CWD_NOT_EXIST, `cwd does not exist: ${cwd}`, 400);
7508
8832
  }
@@ -7514,7 +8838,7 @@ var init_instance_spawner = __esm({
7514
8838
  logger.warn({ cwd, verdict }, "workdir policy rejected spawn");
7515
8839
  throw new InstanceError(ErrorCode.CWD_NOT_EXIST, `cwd not allowed by workdir policy: ${verdict.reason}`, 403);
7516
8840
  }
7517
- const name = input.name && input.name.trim() ? input.name.trim() : basename5(cwd);
8841
+ const name = input.name && input.name.trim() ? input.name.trim() : basename6(cwd);
7518
8842
  const { execPath, args: entryArgs } = resolveEntry(this.opts.cliJsPath);
7519
8843
  const logFd = process.env.ATR_DEBUG_SPAWN ? openSync2(`/tmp/atr-spawn-${Date.now()}.log`, "a") : "ignore";
7520
8844
  const child = spawn3(execPath, [...entryArgs, "--no-terminal"], {
@@ -7571,7 +8895,7 @@ __export(service_installer_exports, {
7571
8895
  uninstall: () => uninstall
7572
8896
  });
7573
8897
  import { existsSync as existsSync15, mkdirSync as mkdirSync12, readFileSync as readFileSync10, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "node:fs";
7574
- import { resolve as resolve15, dirname as dirname8 } from "node:path";
8898
+ import { resolve as resolve15, dirname as dirname9 } from "node:path";
7575
8899
  import { homedir as homedir9, platform } from "node:os";
7576
8900
  function detectPlatform(env = process.env, plat = platform()) {
7577
8901
  if (plat === "darwin")
@@ -7646,8 +8970,8 @@ function install(opts) {
7646
8970
  if (platformDetected === "macos") {
7647
8971
  const path2 = launchdPlistPath(home);
7648
8972
  const logPath = brokerLogPath(home);
7649
- ensureDir(fs, dirname8(path2));
7650
- ensureDir(fs, dirname8(logPath));
8973
+ ensureDir(fs, dirname9(path2));
8974
+ ensureDir(fs, dirname9(logPath));
7651
8975
  fs.writeFileSync(path2, renderLaunchdPlist({
7652
8976
  nodeBin: opts.nodeBin,
7653
8977
  cliPath: opts.cliPath,
@@ -7665,7 +8989,7 @@ function install(opts) {
7665
8989
  };
7666
8990
  }
7667
8991
  const path = systemdUnitPath(home);
7668
- ensureDir(fs, dirname8(path));
8992
+ ensureDir(fs, dirname9(path));
7669
8993
  fs.writeFileSync(path, renderSystemdUnit({
7670
8994
  nodeBin: opts.nodeBin,
7671
8995
  cliPath: opts.cliPath,
@@ -7792,11 +9116,11 @@ __export(cli_exports, {
7792
9116
  });
7793
9117
  import { execSync as execSync2, spawn as spawn4 } from "node:child_process";
7794
9118
  import { existsSync as existsSync16, openSync as openSync3, readFileSync as readFileSync11 } from "node:fs";
7795
- import { resolve as resolve16, dirname as dirname9 } from "node:path";
9119
+ import { resolve as resolve16, dirname as dirname10 } from "node:path";
7796
9120
  import { fileURLToPath as fileURLToPath3 } from "node:url";
7797
9121
  import { homedir as homedir10 } from "node:os";
7798
9122
  function getBrokerVersion() {
7799
- const __dirname2 = dirname9(fileURLToPath3(import.meta.url));
9123
+ const __dirname2 = dirname10(fileURLToPath3(import.meta.url));
7800
9124
  const candidates = [
7801
9125
  resolve16(__dirname2, "package.json"),
7802
9126
  resolve16(__dirname2, "..", "package.json"),
@@ -7815,7 +9139,7 @@ function getBrokerVersion() {
7815
9139
  return "0.0.0";
7816
9140
  }
7817
9141
  function getCliPath() {
7818
- const __dirname2 = dirname9(fileURLToPath3(import.meta.url));
9142
+ const __dirname2 = dirname10(fileURLToPath3(import.meta.url));
7819
9143
  const parentDir = resolve16(__dirname2, "..", "cli.js");
7820
9144
  const sameDir = resolve16(__dirname2, "cli.js");
7821
9145
  try {
@@ -7860,7 +9184,7 @@ async function runBrokerStart(cli) {
7860
9184
  process.stderr.write(`[atr] log file: ${logRotator.currentFilePath()}
7861
9185
  `);
7862
9186
  const registry = new InstanceRegistryManager();
7863
- const __dirname2 = dirname9(fileURLToPath3(import.meta.url));
9187
+ const __dirname2 = dirname10(fileURLToPath3(import.meta.url));
7864
9188
  const frontendDist = resolve16(__dirname2, "..", "frontend-dist");
7865
9189
  let sharedToken;
7866
9190
  try {
@@ -7912,7 +9236,8 @@ async function runBrokerStart(cli) {
7912
9236
  brokerPort: port,
7913
9237
  displayIp,
7914
9238
  workdirPolicy: () => ({
7915
- allow: currentUserConfig.workdirAllow ?? []
9239
+ allow: currentUserConfig.workdirAllow ?? [],
9240
+ deny: currentUserConfig.workdirDeny ?? []
7916
9241
  })
7917
9242
  };
7918
9243
  let handle;
@@ -8208,12 +9533,12 @@ async function writeTokenSection() {
8208
9533
  const { resolve: pathResolve2 } = await import("node:path");
8209
9534
  const { homedir: homedir11 } = await import("node:os");
8210
9535
  const path = pathResolve2(homedir11(), ".atrrc");
8211
- const stat = statSync6(path);
9536
+ const stat3 = statSync6(path);
8212
9537
  const cfg = JSON.parse(readFileSync12(path, "utf-8"));
8213
9538
  if (typeof cfg.token === "string" && cfg.token.length > 0) {
8214
9539
  process.stdout.write(` token: ${cfg.token}
8215
9540
  `);
8216
- process.stdout.write(` file: ${path} (mode ${(stat.mode & 511).toString(8)})
9541
+ process.stdout.write(` file: ${path} (mode ${(stat3.mode & 511).toString(8)})
8217
9542
  `);
8218
9543
  } else {
8219
9544
  process.stdout.write(` token: (none; ${path} has no .token field)
@@ -8492,9 +9817,9 @@ void (async () => {
8492
9817
  }
8493
9818
  if (cli.version) {
8494
9819
  const { readFileSync: readFileSync12 } = await import("node:fs");
8495
- const { resolve: resolve17, dirname: dirname10 } = await import("node:path");
9820
+ const { resolve: resolve17, dirname: dirname11 } = await import("node:path");
8496
9821
  const { fileURLToPath: fileURLToPath4 } = await import("node:url");
8497
- const __dirname2 = dirname10(fileURLToPath4(import.meta.url));
9822
+ const __dirname2 = dirname11(fileURLToPath4(import.meta.url));
8498
9823
  const pkg = JSON.parse(readFileSync12(resolve17(__dirname2, "..", "package.json"), "utf-8"));
8499
9824
  process.stdout.write(`${pkg.version}
8500
9825
  `);