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.
- package/dist/cli.js +1614 -289
- package/frontend-dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/frontend-dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/frontend-dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/frontend-dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/frontend-dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/frontend-dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/frontend-dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/frontend-dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/frontend-dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/frontend-dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/frontend-dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/frontend-dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/frontend-dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/frontend-dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/frontend-dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/frontend-dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/frontend-dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/frontend-dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/frontend-dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/frontend-dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/frontend-dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/frontend-dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/frontend-dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/frontend-dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/frontend-dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/frontend-dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/frontend-dist/assets/MarkdownPreview-CF6sudmV.js +293 -0
- package/frontend-dist/assets/MarkdownPreview-CKe8gJP-.css +1 -0
- package/frontend-dist/assets/abap-BdImnpbu.js +1 -0
- package/frontend-dist/assets/actionscript-3-CoDkCxhg.js +1 -0
- package/frontend-dist/assets/ada-bCR0ucgS.js +1 -0
- package/frontend-dist/assets/andromeeda-C4gqWexZ.js +1 -0
- package/frontend-dist/assets/angular-html-DA-rfuFy.js +1 -0
- package/frontend-dist/assets/angular-ts-BrjP3tb8.js +1 -0
- package/frontend-dist/assets/apache-Pmp26Uib.js +1 -0
- package/frontend-dist/assets/apex-Dqspr-GT.js +1 -0
- package/frontend-dist/assets/apl-CORt7UWP.js +1 -0
- package/frontend-dist/assets/applescript-Co6uUVPk.js +1 -0
- package/frontend-dist/assets/ara-BRHolxvo.js +1 -0
- package/frontend-dist/assets/asciidoc-Ve4PFQV2.js +1 -0
- package/frontend-dist/assets/asm-D_Q5rh1f.js +1 -0
- package/frontend-dist/assets/astro-HNnZUWAn.js +1 -0
- package/frontend-dist/assets/aurora-x-D-2ljcwZ.js +1 -0
- package/frontend-dist/assets/awk-DMzUqQB5.js +1 -0
- package/frontend-dist/assets/ayu-dark-DYE7WIF3.js +1 -0
- package/frontend-dist/assets/ayu-light-BA47KaF1.js +1 -0
- package/frontend-dist/assets/ayu-mirage-32ctXXKs.js +1 -0
- package/frontend-dist/assets/ballerina-BFfxhgS-.js +1 -0
- package/frontend-dist/assets/bat-BkioyH1T.js +1 -0
- package/frontend-dist/assets/beancount-k_qm7-4y.js +1 -0
- package/frontend-dist/assets/berry-uYugtg8r.js +1 -0
- package/frontend-dist/assets/bibtex-CHM0blh-.js +1 -0
- package/frontend-dist/assets/bicep-Bmn6On1c.js +1 -0
- package/frontend-dist/assets/bird2-BIv1doCn.js +1 -0
- package/frontend-dist/assets/blade-2xfisSek.js +1 -0
- package/frontend-dist/assets/bsl-BO_Y6i37.js +1 -0
- package/frontend-dist/assets/c-BIGW1oBm.js +1 -0
- package/frontend-dist/assets/c3-MRO5bC_T.js +1 -0
- package/frontend-dist/assets/cadence-Bv_4Rxtq.js +1 -0
- package/frontend-dist/assets/cairo-KRGpt6FW.js +1 -0
- package/frontend-dist/assets/catppuccin-frappe-DFWUc33u.js +1 -0
- package/frontend-dist/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
- package/frontend-dist/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
- package/frontend-dist/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
- package/frontend-dist/assets/clarity-D53aC0YG.js +1 -0
- package/frontend-dist/assets/clojure-P80f7IUj.js +1 -0
- package/frontend-dist/assets/cmake-D1j8_8rp.js +1 -0
- package/frontend-dist/assets/cobol-nBiQ_Alo.js +1 -0
- package/frontend-dist/assets/codeowners-Bp6g37R7.js +1 -0
- package/frontend-dist/assets/codeql-DsOJ9woJ.js +1 -0
- package/frontend-dist/assets/coffee-Ch7k5sss.js +1 -0
- package/frontend-dist/assets/common-lisp-Cg-RD9OK.js +1 -0
- package/frontend-dist/assets/coq-DkFqJrB1.js +1 -0
- package/frontend-dist/assets/cpp-UfJy6YNI.js +1 -0
- package/frontend-dist/assets/crystal-DGywbUpC.js +1 -0
- package/frontend-dist/assets/csharp-DSvCPggb.js +1 -0
- package/frontend-dist/assets/css-CLj8gQPS.js +1 -0
- package/frontend-dist/assets/csv-fuZLfV_i.js +1 -0
- package/frontend-dist/assets/cue-D82EKSYY.js +1 -0
- package/frontend-dist/assets/cypher-COkxafJQ.js +1 -0
- package/frontend-dist/assets/d-85-TOEBH.js +1 -0
- package/frontend-dist/assets/dark-plus-C3mMm8J8.js +1 -0
- package/frontend-dist/assets/dart-bE4Kk8sk.js +1 -0
- package/frontend-dist/assets/dax-CEL-wOlO.js +1 -0
- package/frontend-dist/assets/desktop-BmXAJ9_W.js +1 -0
- package/frontend-dist/assets/diff-D97Zzqfu.js +1 -0
- package/frontend-dist/assets/docker-BcOcwvcX.js +1 -0
- package/frontend-dist/assets/dotenv-Da5cRb03.js +1 -0
- package/frontend-dist/assets/dracula-BzJJZx-M.js +1 -0
- package/frontend-dist/assets/dracula-soft-BXkSAIEj.js +1 -0
- package/frontend-dist/assets/dream-maker-BtqSS_iP.js +1 -0
- package/frontend-dist/assets/edge-FbVlp4U3.js +1 -0
- package/frontend-dist/assets/elixir-CkH2-t6x.js +1 -0
- package/frontend-dist/assets/elm-DbKCFpqz.js +1 -0
- package/frontend-dist/assets/emacs-lisp-CXvaQtF9.js +1 -0
- package/frontend-dist/assets/erb-Dm6A9KJ5.js +1 -0
- package/frontend-dist/assets/erlang-DsQrWhSR.js +1 -0
- package/frontend-dist/assets/{eruda-Chf2H6-5.js → eruda-I4dOyDju.js} +1 -1
- package/frontend-dist/assets/everforest-dark-BgDCqdQA.js +1 -0
- package/frontend-dist/assets/everforest-light-C8M2exoo.js +1 -0
- package/frontend-dist/assets/fennel-BYunw83y.js +1 -0
- package/frontend-dist/assets/fish-BvzEVeQv.js +1 -0
- package/frontend-dist/assets/fluent-C4IJs8-o.js +1 -0
- package/frontend-dist/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
- package/frontend-dist/assets/fortran-free-form-BxgE0vQu.js +1 -0
- package/frontend-dist/assets/fsharp-CXgrBDvD.js +1 -0
- package/frontend-dist/assets/gdresource-BOOCDP_w.js +1 -0
- package/frontend-dist/assets/gdscript-C5YyOfLZ.js +1 -0
- package/frontend-dist/assets/gdshader-DkwncUOv.js +1 -0
- package/frontend-dist/assets/genie-D0YGMca9.js +1 -0
- package/frontend-dist/assets/gherkin-DyxjwDmM.js +1 -0
- package/frontend-dist/assets/git-commit-F4YmCXRG.js +1 -0
- package/frontend-dist/assets/git-rebase-r7XF79zn.js +1 -0
- package/frontend-dist/assets/github-dark-DHJKELXO.js +1 -0
- package/frontend-dist/assets/github-dark-default-Cuk6v7N8.js +1 -0
- package/frontend-dist/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
- package/frontend-dist/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
- package/frontend-dist/assets/github-light-DAi9KRSo.js +1 -0
- package/frontend-dist/assets/github-light-default-D7oLnXFd.js +1 -0
- package/frontend-dist/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
- package/frontend-dist/assets/gleam-BspZqrRM.js +1 -0
- package/frontend-dist/assets/glimmer-js-ByusRIyA.js +1 -0
- package/frontend-dist/assets/glimmer-ts-BfAWNZQY.js +1 -0
- package/frontend-dist/assets/glsl-DplSGwfg.js +1 -0
- package/frontend-dist/assets/gn-n2N0HUVH.js +1 -0
- package/frontend-dist/assets/gnuplot-DdkO51Og.js +1 -0
- package/frontend-dist/assets/go-C27-OAKa.js +1 -0
- package/frontend-dist/assets/graphql-ChdNCCLP.js +1 -0
- package/frontend-dist/assets/groovy-gcz8RCvz.js +1 -0
- package/frontend-dist/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
- package/frontend-dist/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
- package/frontend-dist/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
- package/frontend-dist/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
- package/frontend-dist/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
- package/frontend-dist/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
- package/frontend-dist/assets/hack-DbPARsA_.js +1 -0
- package/frontend-dist/assets/haml-D5jkg6IW.js +1 -0
- package/frontend-dist/assets/handlebars-BpdQsYii.js +1 -0
- package/frontend-dist/assets/haskell-Df6bDoY_.js +1 -0
- package/frontend-dist/assets/haxe-CzTSHFRz.js +1 -0
- package/frontend-dist/assets/hcl-BWvSN4gD.js +1 -0
- package/frontend-dist/assets/hjson-D5-asLiD.js +1 -0
- package/frontend-dist/assets/hlsl-D3lLCCz7.js +1 -0
- package/frontend-dist/assets/horizon-BUw7H-hv.js +1 -0
- package/frontend-dist/assets/horizon-bright-CUuTKBJd.js +1 -0
- package/frontend-dist/assets/houston-DnULxvSX.js +1 -0
- package/frontend-dist/assets/html-derivative-DlHx6ybY.js +1 -0
- package/frontend-dist/assets/html-pp8916En.js +1 -0
- package/frontend-dist/assets/http-jrhK8wxY.js +1 -0
- package/frontend-dist/assets/hurl-irOxFIW8.js +1 -0
- package/frontend-dist/assets/hxml-Bvhsp5Yf.js +1 -0
- package/frontend-dist/assets/hy-DFXneXwc.js +1 -0
- package/frontend-dist/assets/imba-DGztddWO.js +1 -0
- package/frontend-dist/assets/index-3yH0kVT5.css +32 -0
- package/frontend-dist/assets/index-DNdXwx-1.js +153 -0
- package/frontend-dist/assets/index-QyYOrA8J.js +391 -0
- package/frontend-dist/assets/index-XrxXnMBj.js +1 -0
- package/frontend-dist/assets/ini-BEwlwnbL.js +1 -0
- package/frontend-dist/assets/java-CylS5w8V.js +1 -0
- package/frontend-dist/assets/javascript-wDzz0qaB.js +1 -0
- package/frontend-dist/assets/jinja-f2NsQr07.js +1 -0
- package/frontend-dist/assets/jison-wvAkD_A8.js +1 -0
- package/frontend-dist/assets/json-Cp-IABpG.js +1 -0
- package/frontend-dist/assets/json5-C9tS-k6U.js +1 -0
- package/frontend-dist/assets/jsonc-Des-eS-w.js +1 -0
- package/frontend-dist/assets/jsonl-DcaNXYhu.js +1 -0
- package/frontend-dist/assets/jsonnet-DFQXde-d.js +1 -0
- package/frontend-dist/assets/jssm-C2t-YnRu.js +1 -0
- package/frontend-dist/assets/jsx-g9-lgVsj.js +1 -0
- package/frontend-dist/assets/julia-D7OTSIA_.js +1 -0
- package/frontend-dist/assets/just-CUsbIsdP.js +1 -0
- package/frontend-dist/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
- package/frontend-dist/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
- package/frontend-dist/assets/kanagawa-wave-DWedfzmr.js +1 -0
- package/frontend-dist/assets/kdl-DV7GczEv.js +1 -0
- package/frontend-dist/assets/kotlin-BdnUsdx6.js +1 -0
- package/frontend-dist/assets/kusto-wEQ09or8.js +1 -0
- package/frontend-dist/assets/laserwave-DUszq2jm.js +1 -0
- package/frontend-dist/assets/latex-CaSxy8MP.js +1 -0
- package/frontend-dist/assets/lean-BZvkOJ9d.js +1 -0
- package/frontend-dist/assets/less-B1dDrJ26.js +1 -0
- package/frontend-dist/assets/light-plus-B7mTdjB0.js +1 -0
- package/frontend-dist/assets/liquid-C0sCDyMI.js +1 -0
- package/frontend-dist/assets/llvm-DjAJT7YJ.js +1 -0
- package/frontend-dist/assets/log-2UxHyX5q.js +1 -0
- package/frontend-dist/assets/logo-BtOb2qkB.js +1 -0
- package/frontend-dist/assets/lua-BaeVxFsk.js +1 -0
- package/frontend-dist/assets/luau-KW6xsasC.js +1 -0
- package/frontend-dist/assets/make-CHLpvVh8.js +1 -0
- package/frontend-dist/assets/markdown-Cvjx9yec.js +1 -0
- package/frontend-dist/assets/marko-DjSrsDqO.js +1 -0
- package/frontend-dist/assets/material-theme-D5KoaKCx.js +1 -0
- package/frontend-dist/assets/material-theme-darker-BfHTSMKl.js +1 -0
- package/frontend-dist/assets/material-theme-lighter-B0m2ddpp.js +1 -0
- package/frontend-dist/assets/material-theme-ocean-CyktbL80.js +1 -0
- package/frontend-dist/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
- package/frontend-dist/assets/matlab-D7o27uSR.js +1 -0
- package/frontend-dist/assets/mdc-DTYItulj.js +1 -0
- package/frontend-dist/assets/mdx-Cmh6b_Ma.js +1 -0
- package/frontend-dist/assets/mermaid-mWjccvbQ.js +1 -0
- package/frontend-dist/assets/min-dark-CafNBF8u.js +1 -0
- package/frontend-dist/assets/min-light-CTRr51gU.js +1 -0
- package/frontend-dist/assets/mipsasm-CKIfxQSi.js +1 -0
- package/frontend-dist/assets/mojo-rZm6bMo-.js +1 -0
- package/frontend-dist/assets/monokai-D4h5O-jR.js +1 -0
- package/frontend-dist/assets/moonbit-_H4v1dQx.js +1 -0
- package/frontend-dist/assets/move-IF9eRakj.js +1 -0
- package/frontend-dist/assets/narrat-DRg8JJMk.js +1 -0
- package/frontend-dist/assets/nextflow-C-mBbutL.js +1 -0
- package/frontend-dist/assets/nextflow-groovy-vE_lwT2v.js +1 -0
- package/frontend-dist/assets/nginx-BpAMiNFr.js +1 -0
- package/frontend-dist/assets/night-owl-C39BiMTA.js +1 -0
- package/frontend-dist/assets/night-owl-light-CMTm3GFP.js +1 -0
- package/frontend-dist/assets/nim-BIad80T-.js +1 -0
- package/frontend-dist/assets/nix-CwoSXNpI.js +1 -0
- package/frontend-dist/assets/nord-Ddv68eIx.js +1 -0
- package/frontend-dist/assets/nushell-Cz2AlsmD.js +1 -0
- package/frontend-dist/assets/objective-c-DXmwc3jG.js +1 -0
- package/frontend-dist/assets/objective-cpp-CLxacb5B.js +1 -0
- package/frontend-dist/assets/ocaml-C0hk2d4L.js +1 -0
- package/frontend-dist/assets/odin-BBf5iR-q.js +1 -0
- package/frontend-dist/assets/one-dark-pro-DVMEJ2y_.js +1 -0
- package/frontend-dist/assets/one-light-C3Wv6jpd.js +1 -0
- package/frontend-dist/assets/openscad-C4EeE6gA.js +1 -0
- package/frontend-dist/assets/pascal-D93ZcfNL.js +1 -0
- package/frontend-dist/assets/perl-B9cMNwum.js +1 -0
- package/frontend-dist/assets/php-Csjmro_R.js +1 -0
- package/frontend-dist/assets/pkl-u5AG7uiY.js +1 -0
- package/frontend-dist/assets/plastic-3e1v2bzS.js +1 -0
- package/frontend-dist/assets/plsql-ChMvpjG-.js +1 -0
- package/frontend-dist/assets/po-BTJTHyun.js +1 -0
- package/frontend-dist/assets/poimandres-CS3Unz2-.js +1 -0
- package/frontend-dist/assets/polar-C0HS_06l.js +1 -0
- package/frontend-dist/assets/postcss-CXtECtnM.js +1 -0
- package/frontend-dist/assets/powerquery-CEu0bR-o.js +1 -0
- package/frontend-dist/assets/powershell-Dpen1YoG.js +1 -0
- package/frontend-dist/assets/prisma-Dd19v3D-.js +1 -0
- package/frontend-dist/assets/prolog-CbFg5uaA.js +1 -0
- package/frontend-dist/assets/proto-C7zT0LnQ.js +1 -0
- package/frontend-dist/assets/pug-DKIMFp6K.js +1 -0
- package/frontend-dist/assets/puppet-BMWR74SV.js +1 -0
- package/frontend-dist/assets/purescript-CklMAg4u.js +1 -0
- package/frontend-dist/assets/python-B6aJPvgy.js +1 -0
- package/frontend-dist/assets/qml-3beO22l8.js +1 -0
- package/frontend-dist/assets/qmldir-C8lEn-DE.js +1 -0
- package/frontend-dist/assets/qss-IeuSbFQv.js +1 -0
- package/frontend-dist/assets/r-Dspwwk_N.js +1 -0
- package/frontend-dist/assets/racket-BqYA7rlc.js +1 -0
- package/frontend-dist/assets/raku-DXvB9xmW.js +1 -0
- package/frontend-dist/assets/razor-BjBPvh-w.js +1 -0
- package/frontend-dist/assets/red-bN70gL4F.js +1 -0
- package/frontend-dist/assets/reg-C-SQnVFl.js +1 -0
- package/frontend-dist/assets/regexp-CDVJQ6XC.js +1 -0
- package/frontend-dist/assets/rel-C3B-1QV4.js +1 -0
- package/frontend-dist/assets/riscv-BM1_JUlF.js +1 -0
- package/frontend-dist/assets/ron-D8l8udqQ.js +1 -0
- package/frontend-dist/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
- package/frontend-dist/assets/rose-pine-moon-D4_iv3hh.js +1 -0
- package/frontend-dist/assets/rose-pine-qdsjHGoJ.js +1 -0
- package/frontend-dist/assets/rosmsg-BJDFO7_C.js +1 -0
- package/frontend-dist/assets/rst-CpCqk9r5.js +1 -0
- package/frontend-dist/assets/ruby-DyJCeAvU.js +1 -0
- package/frontend-dist/assets/rust-B1yitclQ.js +1 -0
- package/frontend-dist/assets/sas-DEy46yEz.js +1 -0
- package/frontend-dist/assets/sass-Cj5Yp3dK.js +1 -0
- package/frontend-dist/assets/scala-C151Ov-r.js +1 -0
- package/frontend-dist/assets/scheme-C98Dy4si.js +1 -0
- package/frontend-dist/assets/scss-D5BDwBP9.js +1 -0
- package/frontend-dist/assets/sdbl-DVxCFoDh.js +1 -0
- package/frontend-dist/assets/shaderlab-Dg9Lc6iA.js +1 -0
- package/frontend-dist/assets/shellscript-Yzrsuije.js +1 -0
- package/frontend-dist/assets/shellsession-BADoaaVG.js +1 -0
- package/frontend-dist/assets/slack-dark-BthQWCQV.js +1 -0
- package/frontend-dist/assets/slack-ochin-DqwNpetd.js +1 -0
- package/frontend-dist/assets/smalltalk-BERRCDM3.js +1 -0
- package/frontend-dist/assets/snazzy-light-Bw305WKR.js +1 -0
- package/frontend-dist/assets/solarized-dark-DXbdFlpD.js +1 -0
- package/frontend-dist/assets/solarized-light-L9t79GZl.js +1 -0
- package/frontend-dist/assets/solidity-rGO070M0.js +1 -0
- package/frontend-dist/assets/soy-8wufbnw4.js +1 -0
- package/frontend-dist/assets/sparql-rVzFXLq3.js +1 -0
- package/frontend-dist/assets/splunk-BtCnVYZw.js +1 -0
- package/frontend-dist/assets/sql-CRqJ_cUM.js +1 -0
- package/frontend-dist/assets/ssh-config-_ykCGR6B.js +1 -0
- package/frontend-dist/assets/stata-DI20mbqo.js +1 -0
- package/frontend-dist/assets/stylus-BEDo0Tqx.js +1 -0
- package/frontend-dist/assets/surrealql-Bq5Q-fJD.js +1 -0
- package/frontend-dist/assets/svelte-Cy7k_4gC.js +1 -0
- package/frontend-dist/assets/swift-D82vCrfD.js +1 -0
- package/frontend-dist/assets/synthwave-84-CbfX1IO0.js +1 -0
- package/frontend-dist/assets/system-verilog-CnnmHF94.js +1 -0
- package/frontend-dist/assets/systemd-4A_iFExJ.js +1 -0
- package/frontend-dist/assets/talonscript-CkByrt1z.js +1 -0
- package/frontend-dist/assets/tasl-QIJgUcNo.js +1 -0
- package/frontend-dist/assets/tcl-dwOrl1Do.js +1 -0
- package/frontend-dist/assets/templ-DhtptRzy.js +1 -0
- package/frontend-dist/assets/terraform-BETggiCN.js +1 -0
- package/frontend-dist/assets/tex-idrVyKtj.js +1 -0
- package/frontend-dist/assets/tokyo-night-hegEt444.js +1 -0
- package/frontend-dist/assets/toml-vGWfd6FD.js +1 -0
- package/frontend-dist/assets/ts-tags-D351s5mN.js +1 -0
- package/frontend-dist/assets/tsv-B_m7g4N7.js +1 -0
- package/frontend-dist/assets/tsx-COt5Ahok.js +1 -0
- package/frontend-dist/assets/turtle-BsS91CYL.js +1 -0
- package/frontend-dist/assets/twig-CW1WmMYd.js +1 -0
- package/frontend-dist/assets/typescript-BPQ3VLAy.js +1 -0
- package/frontend-dist/assets/typespec-CAFt9gP4.js +1 -0
- package/frontend-dist/assets/typst-DHCkPAjA.js +1 -0
- package/frontend-dist/assets/v-BcVCzyr7.js +1 -0
- package/frontend-dist/assets/vala-CsfeWuGM.js +1 -0
- package/frontend-dist/assets/vb-D17OF-Vu.js +1 -0
- package/frontend-dist/assets/verilog-BQ8w6xss.js +1 -0
- package/frontend-dist/assets/vesper-DRje8inN.js +1 -0
- package/frontend-dist/assets/vhdl-CeAyd5Ju.js +1 -0
- package/frontend-dist/assets/viml-CJc9bBzg.js +1 -0
- package/frontend-dist/assets/vitesse-black-Bkuqu6BP.js +1 -0
- package/frontend-dist/assets/vitesse-dark-D0r3Knsf.js +1 -0
- package/frontend-dist/assets/vitesse-light-CVO1_9PV.js +1 -0
- package/frontend-dist/assets/vue-D2xRrEX4.js +1 -0
- package/frontend-dist/assets/vue-html-AaS7Mt5G.js +1 -0
- package/frontend-dist/assets/vue-vine-BoDAl6tE.js +1 -0
- package/frontend-dist/assets/vyper-CDx5xZoG.js +1 -0
- package/frontend-dist/assets/wasm-CG6Dc4jp.js +1 -0
- package/frontend-dist/assets/wasm-MzD3tlZU.js +1 -0
- package/frontend-dist/assets/wenyan-BV7otONQ.js +1 -0
- package/frontend-dist/assets/wgsl-Dx-B1_4e.js +1 -0
- package/frontend-dist/assets/wikitext-BhOHFoWU.js +1 -0
- package/frontend-dist/assets/wit-5i3qLPDT.js +1 -0
- package/frontend-dist/assets/wolfram-lXgVvXCa.js +1 -0
- package/frontend-dist/assets/xml-sdJ4AIDG.js +1 -0
- package/frontend-dist/assets/xsl-CtQFsRM5.js +1 -0
- package/frontend-dist/assets/yaml-Buea-lGh.js +1 -0
- package/frontend-dist/assets/zenscript-DVFEvuxE.js +1 -0
- package/frontend-dist/assets/zig-VOosw3JB.js +1 -0
- package/frontend-dist/index.html +2 -2
- package/frontend-dist/manifest.webmanifest +1 -1
- package/frontend-dist/sw.js +1 -1
- package/package.json +1 -1
- package/frontend-dist/assets/index-B7bzacGC.css +0 -32
- 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
|
-
|
|
79
|
-
|
|
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
|
|
87
|
-
const
|
|
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
|
-
|
|
1564
|
-
|
|
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
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
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
|
|
1593
|
-
if (
|
|
1594
|
-
return "
|
|
1595
|
-
|
|
1596
|
-
|
|
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
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
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
|
|
1623
|
-
"backend/dist/api/
|
|
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
|
|
3084
|
+
import { Router as Router10 } from "express";
|
|
1630
3085
|
function createBrokerApiRouter(opts) {
|
|
1631
|
-
const router =
|
|
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 =
|
|
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
|
|
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(
|
|
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 =
|
|
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
|
|
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"] ?? (
|
|
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
|
|
5247
|
+
import { basename as basename4 } from "node:path";
|
|
3893
5248
|
function isClaudeCommand(command) {
|
|
3894
|
-
let name =
|
|
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
|
|
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 =
|
|
5418
|
+
const toolUseId = asString2(payload["tool_use_id"]);
|
|
4064
5419
|
if (toolUseId)
|
|
4065
5420
|
return toolUseId;
|
|
4066
|
-
const tool =
|
|
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 =
|
|
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 =
|
|
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
|
-
...
|
|
5441
|
+
...asString2(p["message"]) ? { detail: asString2(p["message"]) } : {}
|
|
4087
5442
|
}
|
|
4088
5443
|
];
|
|
4089
5444
|
}
|
|
4090
5445
|
case "PermissionRequest": {
|
|
4091
|
-
const 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 =
|
|
5458
|
+
const tool = asString2(p["tool_name"]) ?? "unknown_tool";
|
|
4104
5459
|
return [
|
|
4105
5460
|
{
|
|
4106
5461
|
kind: "tool_started",
|
|
4107
|
-
toolUseId:
|
|
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 =
|
|
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 =
|
|
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
|
-
...
|
|
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 =
|
|
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
|
-
...
|
|
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:
|
|
4155
|
-
...
|
|
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
|
-
...
|
|
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
|
-
...
|
|
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
|
-
...
|
|
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
|
-
...
|
|
5546
|
+
...asString2(p["trigger"]) ? { detail: asString2(p["trigger"]) } : {}
|
|
4192
5547
|
}
|
|
4193
5548
|
];
|
|
4194
5549
|
}
|
|
4195
5550
|
case "CwdChanged": {
|
|
4196
|
-
const from =
|
|
4197
|
-
const to =
|
|
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 =
|
|
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
|
|
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:
|
|
5087
|
-
dim:
|
|
5088
|
-
red:
|
|
5089
|
-
green:
|
|
5090
|
-
yellow:
|
|
5091
|
-
blue:
|
|
5092
|
-
cyan:
|
|
5093
|
-
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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(
|
|
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 =
|
|
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
|
|
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 =
|
|
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() :
|
|
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
|
|
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,
|
|
7650
|
-
ensureDir(fs,
|
|
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,
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 ${(
|
|
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:
|
|
9820
|
+
const { resolve: resolve17, dirname: dirname11 } = await import("node:path");
|
|
8496
9821
|
const { fileURLToPath: fileURLToPath4 } = await import("node:url");
|
|
8497
|
-
const __dirname2 =
|
|
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
|
`);
|