openmausbot 0.1.55
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/LICENSE +202 -0
- package/README.md +14 -0
- package/cli.js +2 -0
- package/dist/app-icon.svg +29 -0
- package/dist/assets/abap-BdImnpbu.js +1 -0
- package/dist/assets/actionscript-3-B3316cI-.js +1 -0
- package/dist/assets/ada-bCR0ucgS.js +1 -0
- package/dist/assets/ahk-CsyLZFj1.js +1 -0
- package/dist/assets/ahk2-8Zs4aa1G.js +1 -0
- package/dist/assets/andromeeda-C4gqWexZ.js +1 -0
- package/dist/assets/angular-html-DA-rfuFy.js +1 -0
- package/dist/assets/angular-ts-BrjP3tb8.js +1 -0
- package/dist/assets/apache-Pmp26Uib.js +1 -0
- package/dist/assets/apex-DhZFqWV2.js +1 -0
- package/dist/assets/apl-CORt7UWP.js +1 -0
- package/dist/assets/applescript-Co6uUVPk.js +1 -0
- package/dist/assets/ara-BRHolxvo.js +1 -0
- package/dist/assets/asciidoc-CSVQ5wI8.js +1 -0
- package/dist/assets/asm-D_Q5rh1f.js +1 -0
- package/dist/assets/astro-HNnZUWAn.js +1 -0
- package/dist/assets/aurora-x-D-2ljcwZ.js +1 -0
- package/dist/assets/awk-DMzUqQB5.js +1 -0
- package/dist/assets/ayu-dark-DYE7WIF3.js +1 -0
- package/dist/assets/ayu-light-BA47KaF1.js +1 -0
- package/dist/assets/ayu-mirage-32ctXXKs.js +1 -0
- package/dist/assets/ballerina-BFfxhgS-.js +1 -0
- package/dist/assets/bat-CickPsom.js +1 -0
- package/dist/assets/beancount-k_qm7-4y.js +1 -0
- package/dist/assets/berry-uYugtg8r.js +1 -0
- package/dist/assets/bibtex-CHM0blh-.js +1 -0
- package/dist/assets/bicep-Bmn6On1c.js +1 -0
- package/dist/assets/bird2-Bx8U0n9b.js +1 -0
- package/dist/assets/blade-2xfisSek.js +1 -0
- package/dist/assets/bsl-DlhNcFeZ.js +1 -0
- package/dist/assets/c-BIGW1oBm.js +1 -0
- package/dist/assets/c3-Dp5svz6Z.js +1 -0
- package/dist/assets/cadence-Bv_4Rxtq.js +1 -0
- package/dist/assets/cairo-KRGpt6FW.js +1 -0
- package/dist/assets/catppuccin-frappe-CZL1YF0i.js +1 -0
- package/dist/assets/catppuccin-latte-DH-8KZSZ.js +1 -0
- package/dist/assets/catppuccin-macchiato-B7yYVSCf.js +1 -0
- package/dist/assets/catppuccin-mocha-Ct7hS0mc.js +1 -0
- package/dist/assets/chapel-DTp_pixX.js +1 -0
- package/dist/assets/clarity-Dn5IMItf.js +1 -0
- package/dist/assets/clojure-P80f7IUj.js +1 -0
- package/dist/assets/cmake-D1j8_8rp.js +1 -0
- package/dist/assets/cobol-nBiQ_Alo.js +1 -0
- package/dist/assets/codeowners-Bp6g37R7.js +1 -0
- package/dist/assets/codeql-DsOJ9woJ.js +1 -0
- package/dist/assets/coffee-Ch7k5sss.js +1 -0
- package/dist/assets/common-lisp-Cg-RD9OK.js +1 -0
- package/dist/assets/coq-C7JzOVbR.js +1 -0
- package/dist/assets/cpp-BMRokrvK.js +1 -0
- package/dist/assets/crystal-DGywbUpC.js +1 -0
- package/dist/assets/csharp-DSvCPggb.js +1 -0
- package/dist/assets/css-CLj8gQPS.js +1 -0
- package/dist/assets/csv-fuZLfV_i.js +1 -0
- package/dist/assets/cue-D82EKSYY.js +1 -0
- package/dist/assets/cypher-COkxafJQ.js +1 -0
- package/dist/assets/d-85-TOEBH.js +1 -0
- package/dist/assets/dark-plus-C3mMm8J8.js +1 -0
- package/dist/assets/dart-bE4Kk8sk.js +1 -0
- package/dist/assets/dax-CEL-wOlO.js +1 -0
- package/dist/assets/desktop-BmXAJ9_W.js +1 -0
- package/dist/assets/diff-D97Zzqfu.js +1 -0
- package/dist/assets/docker-BcOcwvcX.js +1 -0
- package/dist/assets/dotenv-Da5cRb03.js +1 -0
- package/dist/assets/dracula-BzJJZx-M.js +1 -0
- package/dist/assets/dracula-soft-BXkSAIEj.js +1 -0
- package/dist/assets/dream-maker-BtqSS_iP.js +1 -0
- package/dist/assets/edge-FbVlp4U3.js +1 -0
- package/dist/assets/elixir-CkH2-t6x.js +1 -0
- package/dist/assets/elm-DbKCFpqz.js +1 -0
- package/dist/assets/emacs-lisp-C_m_b--Z.js +1 -0
- package/dist/assets/erb-DXfck5VN.js +1 -0
- package/dist/assets/erlang-DsQrWhSR.js +1 -0
- package/dist/assets/everforest-dark-BgDCqdQA.js +1 -0
- package/dist/assets/everforest-light-C8M2exoo.js +1 -0
- package/dist/assets/fennel-BYunw83y.js +1 -0
- package/dist/assets/fish-BvzEVeQv.js +1 -0
- package/dist/assets/fluent-C4IJs8-o.js +1 -0
- package/dist/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
- package/dist/assets/fortran-free-form-BxgE0vQu.js +1 -0
- package/dist/assets/fsharp-CXgrBDvD.js +1 -0
- package/dist/assets/gdresource-TyuKm33G.js +1 -0
- package/dist/assets/gdscript-DqcFQ5yU.js +1 -0
- package/dist/assets/gdshader-DkwncUOv.js +1 -0
- package/dist/assets/genie-D0YGMca9.js +1 -0
- package/dist/assets/gherkin-DyxjwDmM.js +1 -0
- package/dist/assets/git-commit-F4YmCXRG.js +1 -0
- package/dist/assets/git-rebase-r7XF79zn.js +1 -0
- package/dist/assets/github-dark-DHJKELXO.js +1 -0
- package/dist/assets/github-dark-default-Cuk6v7N8.js +1 -0
- package/dist/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
- package/dist/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
- package/dist/assets/github-light-DAi9KRSo.js +1 -0
- package/dist/assets/github-light-default-D7oLnXFd.js +1 -0
- package/dist/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
- package/dist/assets/gleam-BspZqrRM.js +1 -0
- package/dist/assets/glimmer-js-ByusRIyA.js +1 -0
- package/dist/assets/glimmer-ts-BfAWNZQY.js +1 -0
- package/dist/assets/glsl-DplSGwfg.js +1 -0
- package/dist/assets/gn-n2N0HUVH.js +1 -0
- package/dist/assets/gnuplot-DdkO51Og.js +1 -0
- package/dist/assets/go-C27-OAKa.js +1 -0
- package/dist/assets/graphql-ChdNCCLP.js +1 -0
- package/dist/assets/groovy-gcz8RCvz.js +1 -0
- package/dist/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
- package/dist/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
- package/dist/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
- package/dist/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
- package/dist/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
- package/dist/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
- package/dist/assets/hack-BWmVpMyf.js +1 -0
- package/dist/assets/haml-D5jkg6IW.js +1 -0
- package/dist/assets/handlebars-BpdQsYii.js +1 -0
- package/dist/assets/haskell-Df6bDoY_.js +1 -0
- package/dist/assets/haxe-CfZj7gIn.js +1 -0
- package/dist/assets/hcl-BWvSN4gD.js +1 -0
- package/dist/assets/hjson-D5-asLiD.js +1 -0
- package/dist/assets/hlsl-D3lLCCz7.js +1 -0
- package/dist/assets/horizon-BUw7H-hv.js +1 -0
- package/dist/assets/horizon-bright-CUuTKBJd.js +1 -0
- package/dist/assets/houston-DnULxvSX.js +1 -0
- package/dist/assets/html-derivative-DlHx6ybY.js +1 -0
- package/dist/assets/html-pp8916En.js +1 -0
- package/dist/assets/http-jrhK8wxY.js +1 -0
- package/dist/assets/hurl-irOxFIW8.js +1 -0
- package/dist/assets/hxml-2-FPmUDs.js +1 -0
- package/dist/assets/hy-DFXneXwc.js +1 -0
- package/dist/assets/imba-DGztddWO.js +1 -0
- package/dist/assets/index-B9rLIY81.js +263 -0
- package/dist/assets/index-CJBrtDbC.css +1 -0
- package/dist/assets/index-D-u0LYsV.js +153 -0
- package/dist/assets/ini-BEwlwnbL.js +1 -0
- package/dist/assets/java-CylS5w8V.js +1 -0
- package/dist/assets/javascript-wDzz0qaB.js +1 -0
- package/dist/assets/jinja-f2NsQr07.js +1 -0
- package/dist/assets/jison-wvAkD_A8.js +1 -0
- package/dist/assets/json-Cp-IABpG.js +1 -0
- package/dist/assets/json5-C9tS-k6U.js +1 -0
- package/dist/assets/jsonc-Des-eS-w.js +1 -0
- package/dist/assets/jsonl-DcaNXYhu.js +1 -0
- package/dist/assets/jsonnet-DFQXde-d.js +1 -0
- package/dist/assets/jssm-C2t-YnRu.js +1 -0
- package/dist/assets/jsx-g9-lgVsj.js +1 -0
- package/dist/assets/julia-5Bft2YPA.js +1 -0
- package/dist/assets/just-Cwhn7H3k.js +1 -0
- package/dist/assets/kanagawa-dragon-BuwD2xS4.js +1 -0
- package/dist/assets/kanagawa-lotus-C3DzagqV.js +1 -0
- package/dist/assets/kanagawa-wave-DFGoQZhC.js +1 -0
- package/dist/assets/kdl-DV7GczEv.js +1 -0
- package/dist/assets/kotlin-BdnUsdx6.js +1 -0
- package/dist/assets/kusto-wEQ09or8.js +1 -0
- package/dist/assets/laserwave-DUszq2jm.js +1 -0
- package/dist/assets/latex-D5pSuvFb.js +1 -0
- package/dist/assets/lean-BZvkOJ9d.js +1 -0
- package/dist/assets/less-B1dDrJ26.js +1 -0
- package/dist/assets/light-plus-B7mTdjB0.js +1 -0
- package/dist/assets/liquid-C0sCDyMI.js +1 -0
- package/dist/assets/llvm-BZoOZj88.js +1 -0
- package/dist/assets/log-2UxHyX5q.js +1 -0
- package/dist/assets/logo-BtOb2qkB.js +1 -0
- package/dist/assets/lua-BaeVxFsk.js +1 -0
- package/dist/assets/luau-BnpPk5vE.js +1 -0
- package/dist/assets/make-CHLpvVh8.js +1 -0
- package/dist/assets/markdown-Cvjx9yec.js +1 -0
- package/dist/assets/marko-DjSrsDqO.js +1 -0
- package/dist/assets/material-theme-D5KoaKCx.js +1 -0
- package/dist/assets/material-theme-darker-BfHTSMKl.js +1 -0
- package/dist/assets/material-theme-lighter-B0m2ddpp.js +1 -0
- package/dist/assets/material-theme-ocean-CyktbL80.js +1 -0
- package/dist/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
- package/dist/assets/matlab-D7o27uSR.js +1 -0
- package/dist/assets/mdc-D1_yUvq7.js +1 -0
- package/dist/assets/mdx-Cmh6b_Ma.js +1 -0
- package/dist/assets/mermaid-CQcHuHx7.js +1 -0
- package/dist/assets/min-dark-CafNBF8u.js +1 -0
- package/dist/assets/min-light-CTRr51gU.js +1 -0
- package/dist/assets/mipsasm-CKIfxQSi.js +1 -0
- package/dist/assets/mojo-DJz3ZmWd.js +1 -0
- package/dist/assets/monokai-BRVnQi9A.js +1 -0
- package/dist/assets/moonbit-CHtswR0a.js +1 -0
- package/dist/assets/move-el3G9tDJ.js +1 -0
- package/dist/assets/narrat-DRg8JJMk.js +1 -0
- package/dist/assets/nextflow-C-mBbutL.js +1 -0
- package/dist/assets/nextflow-groovy-vE_lwT2v.js +1 -0
- package/dist/assets/nginx-BpAMiNFr.js +1 -0
- package/dist/assets/night-owl-C39BiMTA.js +1 -0
- package/dist/assets/night-owl-light-CMTm3GFP.js +1 -0
- package/dist/assets/nim-BIad80T-.js +1 -0
- package/dist/assets/nix-CwoSXNpI.js +1 -0
- package/dist/assets/nord-Ddv68eIx.js +1 -0
- package/dist/assets/nsis-BlV79W_Q.js +1 -0
- package/dist/assets/nushell-D3jzshHO.js +1 -0
- package/dist/assets/objective-c-DXmwc3jG.js +1 -0
- package/dist/assets/objective-cpp-CLxacb5B.js +1 -0
- package/dist/assets/ocaml-C0hk2d4L.js +1 -0
- package/dist/assets/odin-BBf5iR-q.js +1 -0
- package/dist/assets/one-dark-pro-DVMEJ2y_.js +1 -0
- package/dist/assets/one-light-C3Wv6jpd.js +1 -0
- package/dist/assets/openscad-C4EeE6gA.js +1 -0
- package/dist/assets/org-DM6o9KBp.js +1 -0
- package/dist/assets/pascal-D93ZcfNL.js +1 -0
- package/dist/assets/perl-B9cMNwum.js +1 -0
- package/dist/assets/php-Csjmro_R.js +1 -0
- package/dist/assets/pkl-u5AG7uiY.js +1 -0
- package/dist/assets/plastic-3e1v2bzS.js +1 -0
- package/dist/assets/plsql-ChMvpjG-.js +1 -0
- package/dist/assets/po-BTJTHyun.js +1 -0
- package/dist/assets/poimandres-CS3Unz2-.js +1 -0
- package/dist/assets/polar-C0HS_06l.js +1 -0
- package/dist/assets/postcss-CXtECtnM.js +1 -0
- package/dist/assets/powerquery-CEu0bR-o.js +1 -0
- package/dist/assets/powershell-BmBUJMz7.js +1 -0
- package/dist/assets/prisma-Vru482bI.js +1 -0
- package/dist/assets/prolog-CbFg5uaA.js +1 -0
- package/dist/assets/proto-C7zT0LnQ.js +1 -0
- package/dist/assets/pug-DKIMFp6K.js +1 -0
- package/dist/assets/puppet-BMWR74SV.js +1 -0
- package/dist/assets/purescript-CklMAg4u.js +1 -0
- package/dist/assets/python-B6aJPvgy.js +1 -0
- package/dist/assets/qml-3beO22l8.js +1 -0
- package/dist/assets/qmldir-C8lEn-DE.js +1 -0
- package/dist/assets/qss-IeuSbFQv.js +1 -0
- package/dist/assets/r-Cf5RLm7j.js +1 -0
- package/dist/assets/racket-BqYA7rlc.js +1 -0
- package/dist/assets/raku-DXvB9xmW.js +1 -0
- package/dist/assets/razor-BjBPvh-w.js +1 -0
- package/dist/assets/rbs-CpoqiR4B.js +1 -0
- package/dist/assets/red-hvxz__6c.js +1 -0
- package/dist/assets/reg-C-SQnVFl.js +1 -0
- package/dist/assets/regexp-CDVJQ6XC.js +1 -0
- package/dist/assets/rel-C3B-1QV4.js +1 -0
- package/dist/assets/riscv-BM1_JUlF.js +1 -0
- package/dist/assets/ron-D8l8udqQ.js +1 -0
- package/dist/assets/rose-pine-5qJOZa0Y.js +1 -0
- package/dist/assets/rose-pine-dawn-zx0QlTCp.js +1 -0
- package/dist/assets/rose-pine-moon-C9pEdX9L.js +1 -0
- package/dist/assets/rosmsg-BJDFO7_C.js +1 -0
- package/dist/assets/rst-bs7f0vWN.js +1 -0
- package/dist/assets/ruby-C0TQ7zu5.js +1 -0
- package/dist/assets/rust-B1yitclQ.js +1 -0
- package/dist/assets/sas-DEy46yEz.js +1 -0
- package/dist/assets/sass-Cj5Yp3dK.js +1 -0
- package/dist/assets/scala-CqE71os6.js +1 -0
- package/dist/assets/scheme-C98Dy4si.js +1 -0
- package/dist/assets/scss-D5BDwBP9.js +1 -0
- package/dist/assets/sdbl-DVxCFoDh.js +1 -0
- package/dist/assets/shaderlab-Dg9Lc6iA.js +1 -0
- package/dist/assets/shellscript-Yzrsuije.js +1 -0
- package/dist/assets/shellsession-BADoaaVG.js +1 -0
- package/dist/assets/slack-dark-BthQWCQV.js +1 -0
- package/dist/assets/slack-ochin-DqwNpetd.js +1 -0
- package/dist/assets/smalltalk-BOQMe2GC.js +1 -0
- package/dist/assets/smithy-cds9vsN8.js +1 -0
- package/dist/assets/snazzy-light-Bw305WKR.js +1 -0
- package/dist/assets/solarized-dark-CpvCGNkr.js +1 -0
- package/dist/assets/solarized-light-Dlz6yCKv.js +1 -0
- package/dist/assets/solidity-DijEV5ha.js +1 -0
- package/dist/assets/soy-8wufbnw4.js +1 -0
- package/dist/assets/sparql-rVzFXLq3.js +1 -0
- package/dist/assets/splunk-BtCnVYZw.js +1 -0
- package/dist/assets/sql-CRqJ_cUM.js +1 -0
- package/dist/assets/ssh-config-_ykCGR6B.js +1 -0
- package/dist/assets/stata-DI20mbqo.js +1 -0
- package/dist/assets/stylus-BEDo0Tqx.js +1 -0
- package/dist/assets/surrealql-Cjom0U5J.js +1 -0
- package/dist/assets/svelte-Cy7k_4gC.js +1 -0
- package/dist/assets/swift-C2oV4EkX.js +1 -0
- package/dist/assets/synthwave-84-CbfX1IO0.js +1 -0
- package/dist/assets/system-verilog-0hqHdDBg.js +1 -0
- package/dist/assets/systemd-4A_iFExJ.js +1 -0
- package/dist/assets/talonscript-CkByrt1z.js +1 -0
- package/dist/assets/tasl-QIJgUcNo.js +1 -0
- package/dist/assets/tcl-dwOrl1Do.js +1 -0
- package/dist/assets/templ-DhtptRzy.js +1 -0
- package/dist/assets/terraform-BETggiCN.js +1 -0
- package/dist/assets/tex-D96PA37w.js +1 -0
- package/dist/assets/tokyo-night-hegEt444.js +1 -0
- package/dist/assets/toml-vGWfd6FD.js +1 -0
- package/dist/assets/ts-tags-D351s5mN.js +1 -0
- package/dist/assets/tsv-B_m7g4N7.js +1 -0
- package/dist/assets/tsx-COt5Ahok.js +1 -0
- package/dist/assets/turtle-BsS91CYL.js +1 -0
- package/dist/assets/twig-27uCiNez.js +1 -0
- package/dist/assets/typescript-BPQ3VLAy.js +1 -0
- package/dist/assets/typespec-CAFt9gP4.js +1 -0
- package/dist/assets/typst-BUadGCkm.js +1 -0
- package/dist/assets/v-BGw2Nkan.js +1 -0
- package/dist/assets/vala-CsfeWuGM.js +1 -0
- package/dist/assets/vb-Cu-pLBUe.js +1 -0
- package/dist/assets/verilog-nZwndyjY.js +1 -0
- package/dist/assets/vesper-DRje8inN.js +1 -0
- package/dist/assets/vhdl-CeAyd5Ju.js +1 -0
- package/dist/assets/viml-CJc9bBzg.js +1 -0
- package/dist/assets/vitesse-black-Bkuqu6BP.js +1 -0
- package/dist/assets/vitesse-dark-D0r3Knsf.js +1 -0
- package/dist/assets/vitesse-light-CVO1_9PV.js +1 -0
- package/dist/assets/vue-BqiEGhQt.js +1 -0
- package/dist/assets/vue-html-AaS7Mt5G.js +1 -0
- package/dist/assets/vue-vine-BoDAl6tE.js +1 -0
- package/dist/assets/vyper-CDx5xZoG.js +1 -0
- package/dist/assets/wasm-CG6Dc4jp.js +1 -0
- package/dist/assets/wasm-MzD3tlZU.js +1 -0
- package/dist/assets/wenyan-BV7otONQ.js +1 -0
- package/dist/assets/wgsl-Dx-B1_4e.js +1 -0
- package/dist/assets/wikitext-BhOHFoWU.js +1 -0
- package/dist/assets/wit-5i3qLPDT.js +1 -0
- package/dist/assets/wolfram-lXgVvXCa.js +1 -0
- package/dist/assets/xml-sdJ4AIDG.js +1 -0
- package/dist/assets/xsl-CtQFsRM5.js +1 -0
- package/dist/assets/yaml-Buea-lGh.js +1 -0
- package/dist/assets/zenscript-DVFEvuxE.js +1 -0
- package/dist/assets/zig-VOosw3JB.js +1 -0
- package/dist/index.html +14 -0
- package/dist-server/companion/src/listener.js +187 -0
- package/dist-server/computer-proxy.js +1185 -0
- package/dist-server/connector-proxy.js +186 -0
- package/dist-server/container-mcp.js +15186 -0
- package/dist-server/drivers/agents-proxy.js +887 -0
- package/dist-server/drivers/browser-proxy.js +15037 -0
- package/dist-server/drivers/dweb-proxy.js +175 -0
- package/dist-server/drivers/phone-proxy.js +339 -0
- package/dist-server/drivers/pi-mcp-extension.ts +638 -0
- package/dist-server/index.js +64869 -0
- package/dist-server/local-computer.js +198 -0
- package/dist-server/mcp-server.js +1233 -0
- package/dist-server/openmausbot.js +3671 -0
- package/dist-server/pair-cli.js +3671 -0
- package/dist-server/permission-proxy.js +126 -0
- package/dist-server/prepare-cloudflared.js +253 -0
- package/dist-server/proxy-paths.js +29 -0
- package/dist-server/server/atomic.js +40 -0
- package/dist-server/server/attachments.js +471 -0
- package/dist-server/server/auto-approve.js +162 -0
- package/dist-server/server/auto-review.js +79 -0
- package/dist-server/server/avatar-image.js +144 -0
- package/dist-server/server/bot-cwd.js +29 -0
- package/dist-server/server/bot-directory.js +127 -0
- package/dist-server/server/bot-package.js +268 -0
- package/dist-server/server/bot-profile.js +76 -0
- package/dist-server/server/box-create-idempotency.js +463 -0
- package/dist-server/server/box.js +944 -0
- package/dist-server/server/brand.js +65 -0
- package/dist-server/server/browser-connection.js +187 -0
- package/dist-server/server/browser-lifecycle-cleanup.js +359 -0
- package/dist-server/server/calendar-calls.js +314 -0
- package/dist-server/server/channel-queue.js +70 -0
- package/dist-server/server/checkpoints.js +405 -0
- package/dist-server/server/chief-of-staff.js +49 -0
- package/dist-server/server/claude-update.js +70 -0
- package/dist-server/server/cli.js +524 -0
- package/dist-server/server/cloud-backend.js +30 -0
- package/dist-server/server/comms-visibility.js +109 -0
- package/dist-server/server/composio.js +945 -0
- package/dist-server/server/computer-control.js +149 -0
- package/dist-server/server/computer-observation.js +133 -0
- package/dist-server/server/computer-proxy.js +1061 -0
- package/dist-server/server/config.js +760 -0
- package/dist-server/server/connector-proxy.js +228 -0
- package/dist-server/server/container-computer.js +840 -0
- package/dist-server/server/container-mcp.js +27 -0
- package/dist-server/server/contracts.js +24 -0
- package/dist-server/server/control-client.js +100 -0
- package/dist-server/server/data-dir-lease.js +3 -0
- package/dist-server/server/decision-log.js +106 -0
- package/dist-server/server/delegations.js +628 -0
- package/dist-server/server/drivers/acp/core.js +904 -0
- package/dist-server/server/drivers/acp/cursor.js +365 -0
- package/dist-server/server/drivers/acp/custom.js +51 -0
- package/dist-server/server/drivers/acp/droid.js +225 -0
- package/dist-server/server/drivers/acp/gemini.js +95 -0
- package/dist-server/server/drivers/acp/grok.js +249 -0
- package/dist-server/server/drivers/acp/hermes.js +429 -0
- package/dist-server/server/drivers/acp/kimi.js +559 -0
- package/dist-server/server/drivers/acp/opencode-go.js +370 -0
- package/dist-server/server/drivers/acp/qwen.js +98 -0
- package/dist-server/server/drivers/agents-proxy.js +941 -0
- package/dist-server/server/drivers/antigravity-acp.js +507 -0
- package/dist-server/server/drivers/antigravity-release.js +65 -0
- package/dist-server/server/drivers/antigravity-runtime.js +395 -0
- package/dist-server/server/drivers/antigravity.js +144 -0
- package/dist-server/server/drivers/boxagent.js +245 -0
- package/dist-server/server/drivers/browser-proxy.js +520 -0
- package/dist-server/server/drivers/builtIn.js +36 -0
- package/dist-server/server/drivers/claude.js +1337 -0
- package/dist-server/server/drivers/codex-catalog.js +409 -0
- package/dist-server/server/drivers/codex.js +1116 -0
- package/dist-server/server/drivers/dweb-proxy.js +193 -0
- package/dist-server/server/drivers/grok.js +48 -0
- package/dist-server/server/drivers/grokagent.js +4 -0
- package/dist-server/server/drivers/local-inject.js +388 -0
- package/dist-server/server/drivers/minimax.js +108 -0
- package/dist-server/server/drivers/native.js +21 -0
- package/dist-server/server/drivers/openai-chat.js +240 -0
- package/dist-server/server/drivers/openai-compat.js +143 -0
- package/dist-server/server/drivers/phone-proxy.js +372 -0
- package/dist-server/server/drivers/pi.js +855 -0
- package/dist-server/server/drivers/retry.js +96 -0
- package/dist-server/server/enterprise.js +93 -0
- package/dist-server/server/env-path.js +329 -0
- package/dist-server/server/environment.js +105 -0
- package/dist-server/server/generated-image.js +39 -0
- package/dist-server/server/graceful-shutdown.js +24 -0
- package/dist-server/server/group-goal-run.js +124 -0
- package/dist-server/server/harness/bus.js +86 -0
- package/dist-server/server/harness/registry.js +217 -0
- package/dist-server/server/index.js +11634 -0
- package/dist-server/server/installed-playbooks.js +34 -0
- package/dist-server/server/local-computer.js +278 -0
- package/dist-server/server/local-routing.js +9 -0
- package/dist-server/server/local-vm-idle.js +44 -0
- package/dist-server/server/local-vm-inventory.js +34 -0
- package/dist-server/server/local-vm-lease.js +58 -0
- package/dist-server/server/mcp-bridge.js +251 -0
- package/dist-server/server/mcp-probe.js +153 -0
- package/dist-server/server/mcp-registry.js +130 -0
- package/dist-server/server/member-turn.js +6 -0
- package/dist-server/server/message-db.js +358 -0
- package/dist-server/server/message-file.js +439 -0
- package/dist-server/server/names.js +26 -0
- package/dist-server/server/notify.js +69 -0
- package/dist-server/server/openmaus-status-capsule.js +329 -0
- package/dist-server/server/openmausbot.js +6 -0
- package/dist-server/server/package-export.js +157 -0
- package/dist-server/server/pair-cli.js +7 -0
- package/dist-server/server/peer-approval-key.js +5 -0
- package/dist-server/server/peer-approval.js +182 -0
- package/dist-server/server/peer-provenance.js +44 -0
- package/dist-server/server/peer-roster.js +139 -0
- package/dist-server/server/permission-proxy.js +157 -0
- package/dist-server/server/phone-secret.js +358 -0
- package/dist-server/server/private-screen-capture.js +17 -0
- package/dist-server/server/procs.js +123 -0
- package/dist-server/server/project-scout.js +304 -0
- package/dist-server/server/proxy-paths.js +47 -0
- package/dist-server/server/redact.js +102 -0
- package/dist-server/server/remote-computer.js +170 -0
- package/dist-server/server/repeat-detector.js +48 -0
- package/dist-server/server/replies.js +38 -0
- package/dist-server/server/request-auth.js +327 -0
- package/dist-server/server/room-cwd.js +15 -0
- package/dist-server/server/room-post-budget.js +112 -0
- package/dist-server/server/room-turn-timeout.js +115 -0
- package/dist-server/server/routine-requests.js +871 -0
- package/dist-server/server/routines.js +1111 -0
- package/dist-server/server/schema.js +11 -0
- package/dist-server/server/screen-frame-gate.js +80 -0
- package/dist-server/server/section-context.js +85 -0
- package/dist-server/server/send-idempotency.js +53 -0
- package/dist-server/server/sessions.js +319 -0
- package/dist-server/server/skill-fetch.js +148 -0
- package/dist-server/server/skill-learn.js +61 -0
- package/dist-server/server/skill-library.js +116 -0
- package/dist-server/server/skills.js +1223 -0
- package/dist-server/server/steer-queue.js +114 -0
- package/dist-server/server/store.js +1217 -0
- package/dist-server/server/surface.js +107 -0
- package/dist-server/server/tailscale.js +103 -0
- package/dist-server/server/team-backup.js +183 -0
- package/dist-server/server/team-library.js +205 -0
- package/dist-server/server/team-manifest.js +224 -0
- package/dist-server/server/thread-events.js +226 -0
- package/dist-server/server/tts/elevenlabs.js +92 -0
- package/dist-server/server/tts/index.js +79 -0
- package/dist-server/server/tts/speech-text.js +195 -0
- package/dist-server/server/tts/system-voices.js +74 -0
- package/dist-server/server/tunnel.js +202 -0
- package/dist-server/server/turn-context.js +40 -0
- package/dist-server/server/turn-dispatch-guard.js +152 -0
- package/dist-server/server/turn-images.js +138 -0
- package/dist-server/server/turn-watchdog.js +65 -0
- package/dist-server/server/vps-computer.js +1099 -0
- package/dist-server/server/vps-container-mcp.js +31 -0
- package/dist-server/server/webhook-ingress.js +173 -0
- package/dist-server/server/webhooks.js +491 -0
- package/dist-server/server/workspace.js +178 -0
- package/dist-server/shared/approval-mode.js +39 -0
- package/dist-server/shared/bot-avatar.js +33 -0
- package/dist-server/shared/bot-profile.js +7 -0
- package/dist-server/shared/connector-availability.js +12 -0
- package/dist-server/shared/credential-request.js +82 -0
- package/dist-server/shared/group-goal-run.js +1 -0
- package/dist-server/shared/import-name.js +11 -0
- package/dist-server/shared/mascot-bodies.js +107 -0
- package/dist-server/shared/routine-request.js +10 -0
- package/dist-server/shared/routine-run.js +1 -0
- package/dist-server/shared/skill-request.js +16 -0
- package/dist-server/shared/team-backup.js +148 -0
- package/dist-server/src/lib/composer-attachments.js +676 -0
- package/dist-server/tunnel-guardian.js +390 -0
- package/dist-server/vps-container-mcp.js +15209 -0
- package/package.json +32 -0
- package/skills/create-verification-skill/SKILL.md +65 -0
- package/skills/create-verification-skill/manifest.json +13 -0
- package/skills/phone-harness/SKILL.md +26 -0
- package/skills/phone-harness/agents/openai.yaml +13 -0
- package/skills/phone-harness/manifest.json +17 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
// A bot may link to a file it created in the workspace for one conversation.
|
|
2
|
+
// Opening that link from a phone must not become a general-purpose host file
|
|
3
|
+
// reader: the HTTP route supplies only roots derived from the exact bot
|
|
4
|
+
// message, and this helper keeps the eventual file handle inside one of them.
|
|
5
|
+
import { constants } from "node:fs";
|
|
6
|
+
import { open, realpath, stat } from "node:fs/promises";
|
|
7
|
+
import { basename, extname, isAbsolute, posix, relative, resolve, sep, win32 } from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
10
|
+
export const MESSAGE_FILE_MAX_BYTES = 25 * 1024 * 1024;
|
|
11
|
+
export function messageFileRoots(options) {
|
|
12
|
+
const conversationRoot = options.pinnedCwd === undefined ? options.configuredCwd : options.pinnedCwd;
|
|
13
|
+
return [...new Set([
|
|
14
|
+
...(typeof conversationRoot === "string" ? [conversationRoot] : []),
|
|
15
|
+
options.senderWorkspace,
|
|
16
|
+
options.attachments,
|
|
17
|
+
])];
|
|
18
|
+
}
|
|
19
|
+
function statusError(status, message) {
|
|
20
|
+
return Object.assign(new Error(message), { status });
|
|
21
|
+
}
|
|
22
|
+
function decodePathWithSuffixRemoved(href) {
|
|
23
|
+
// Split before decoding so an encoded `?` or `#` remains part of the
|
|
24
|
+
// filename, while a real Markdown query/fragment never reaches the file
|
|
25
|
+
// lookup. Decode exactly once so authorization and opening see the same
|
|
26
|
+
// path without making double-encoded input more privileged.
|
|
27
|
+
const path = href.split(/[?#]/, 1)[0];
|
|
28
|
+
if (!path)
|
|
29
|
+
throw statusError(400, "path must be a non-empty file link");
|
|
30
|
+
try {
|
|
31
|
+
return decodeURIComponent(path);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
throw statusError(400, "path must be a valid file link");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function referencedPath(href, portableFileURL = false, allowForwardSlashUNC = true) {
|
|
38
|
+
if (!href || Buffer.byteLength(href) > 8_192 || href.includes("\0")) {
|
|
39
|
+
throw statusError(400, "path must be a non-empty file link");
|
|
40
|
+
}
|
|
41
|
+
// A Windows drive prefix is a path, not a one-letter URL scheme. UNC is
|
|
42
|
+
// also already an absolute local path on Windows and must not be mistaken
|
|
43
|
+
// for a protocol-relative web URL.
|
|
44
|
+
if (/^[a-z]:[\\/]/i.test(href) || href.startsWith("\\\\")) {
|
|
45
|
+
return decodePathWithSuffixRemoved(href);
|
|
46
|
+
}
|
|
47
|
+
// In Markdown, //host/path is a protocol-relative web URL. It is accepted
|
|
48
|
+
// only as the normalized request spelling of an explicit file:// UNC link,
|
|
49
|
+
// never as the authored capability itself.
|
|
50
|
+
if (href.startsWith("//")) {
|
|
51
|
+
if (!allowForwardSlashUNC) {
|
|
52
|
+
throw statusError(400, "protocol-relative web links are not local files");
|
|
53
|
+
}
|
|
54
|
+
return decodePathWithSuffixRemoved(href);
|
|
55
|
+
}
|
|
56
|
+
if (/^[a-z][a-z\d+.-]*:/i.test(href)) {
|
|
57
|
+
let url;
|
|
58
|
+
try {
|
|
59
|
+
url = new URL(href);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
throw statusError(400, "path must be a valid file link");
|
|
63
|
+
}
|
|
64
|
+
if (url.protocol !== "file:" || url.username || url.password || url.port || url.search || url.hash) {
|
|
65
|
+
throw statusError(400, "only local file links can be downloaded here");
|
|
66
|
+
}
|
|
67
|
+
if (url.hostname && url.hostname !== "localhost") {
|
|
68
|
+
try {
|
|
69
|
+
return `//${url.hostname}${decodeURIComponent(url.pathname)}`;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
throw statusError(400, "path must be a valid file link");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (!portableFileURL) {
|
|
76
|
+
try {
|
|
77
|
+
return fileURLToPath(url);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
throw statusError(400, "path must be a valid file link");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const decoded = decodeURIComponent(url.pathname);
|
|
85
|
+
// WHATWG file URLs always spell drive paths as /C:/..., even when the
|
|
86
|
+
// URL is parsed on macOS or Linux. Strip only that drive sentinel; an
|
|
87
|
+
// ordinary /Users/... URL must remain a POSIX path on every host.
|
|
88
|
+
return /^\/[a-z]:[\\/]/i.test(decoded) ? decoded.slice(1) : decoded;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
throw statusError(400, "path must be a valid file link");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Query strings and fragments belong to the Markdown link, not the local
|
|
95
|
+
// filename. Percent-encoding is common for spaces in relative hrefs.
|
|
96
|
+
return decodePathWithSuffixRemoved(href);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* A lexical path identity used only for matching a requested file against a
|
|
100
|
+
* rendered Markdown link. Native `resolve` and `fileURLToPath` follow the
|
|
101
|
+
* runner OS, which makes a Unix link compare differently on Windows CI and a
|
|
102
|
+
* Windows link compare differently on macOS. Keeping the path flavour in the
|
|
103
|
+
* identity also prevents a POSIX path such as `/C:/notes.md` from being
|
|
104
|
+
* mistaken for the Windows path `C:\\notes.md`.
|
|
105
|
+
*/
|
|
106
|
+
function referencedPathIdentity(href, allowForwardSlashUNC = true) {
|
|
107
|
+
const path = referencedPath(href, true, allowForwardSlashUNC);
|
|
108
|
+
if (/^[a-z]:[\\/]/i.test(path) || path.startsWith("\\\\") || path.startsWith("//")) {
|
|
109
|
+
return `windows:${win32.resolve(path)}`;
|
|
110
|
+
}
|
|
111
|
+
if (path.startsWith("/"))
|
|
112
|
+
return `posix:${posix.resolve(path)}`;
|
|
113
|
+
return `relative:${posix.normalize(path)}`;
|
|
114
|
+
}
|
|
115
|
+
function walkMarkdown(node, visit) {
|
|
116
|
+
const pending = [node];
|
|
117
|
+
while (pending.length > 0) {
|
|
118
|
+
const current = pending.pop();
|
|
119
|
+
visit(current);
|
|
120
|
+
const children = current.children ?? [];
|
|
121
|
+
for (let index = children.length - 1; index >= 0; index -= 1) {
|
|
122
|
+
pending.push(children[index]);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function renderedMarkdownTargets(markdown) {
|
|
127
|
+
const definitions = new Map();
|
|
128
|
+
const links = [];
|
|
129
|
+
const references = [];
|
|
130
|
+
walkMarkdown(fromMarkdown(markdown), (node) => {
|
|
131
|
+
if (node.type === "definition" && node.identifier && node.url) {
|
|
132
|
+
if (!definitions.has(node.identifier))
|
|
133
|
+
definitions.set(node.identifier, node.url);
|
|
134
|
+
}
|
|
135
|
+
else if ((node.type === "link" || node.type === "image") && node.url) {
|
|
136
|
+
links.push(node.url);
|
|
137
|
+
}
|
|
138
|
+
else if ((node.type === "linkReference" || node.type === "imageReference") && node.identifier) {
|
|
139
|
+
references.push(node.identifier);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
for (const identifier of references) {
|
|
143
|
+
const target = definitions.get(identifier);
|
|
144
|
+
if (target)
|
|
145
|
+
links.push(target);
|
|
146
|
+
}
|
|
147
|
+
return links;
|
|
148
|
+
}
|
|
149
|
+
/** Resolve the local image authored at one Markdown source offset. The
|
|
150
|
+
* browser can use this small message-scoped reference instead of putting an
|
|
151
|
+
* absolute host path in a GET URL. Definitions are collected first because
|
|
152
|
+
* CommonMark permits them to appear after the image reference. */
|
|
153
|
+
export function messageImageTargetAt(text, sourceOffset) {
|
|
154
|
+
if (!Number.isSafeInteger(sourceOffset) || sourceOffset < 0)
|
|
155
|
+
return null;
|
|
156
|
+
const definitions = new Map();
|
|
157
|
+
let direct = null;
|
|
158
|
+
let reference = null;
|
|
159
|
+
walkMarkdown(fromMarkdown(text), (node) => {
|
|
160
|
+
if (node.type === "definition" && node.identifier && node.url) {
|
|
161
|
+
if (!definitions.has(node.identifier))
|
|
162
|
+
definitions.set(node.identifier, node.url);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (node.position?.start.offset !== sourceOffset)
|
|
166
|
+
return;
|
|
167
|
+
if (node.type === "image" && node.url)
|
|
168
|
+
direct = node.url;
|
|
169
|
+
else if (node.type === "imageReference" && node.identifier)
|
|
170
|
+
reference = node.identifier;
|
|
171
|
+
});
|
|
172
|
+
return direct ?? (reference ? definitions.get(reference) ?? null : null);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Confirm that the requested path is carried by this message, tolerating the
|
|
176
|
+
* one representation change native URL APIs make for us: a file href with
|
|
177
|
+
* percent-encoded spaces arrives from iOS as a decoded filesystem path.
|
|
178
|
+
* Normalisation is applied only to rendered Markdown link targets, never to
|
|
179
|
+
* arbitrary prose in the message.
|
|
180
|
+
*/
|
|
181
|
+
export function messageReferencesFile(text, requested) {
|
|
182
|
+
let wanted;
|
|
183
|
+
try {
|
|
184
|
+
wanted = referencedPathIdentity(requested);
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
for (const target of renderedMarkdownTargets(text)) {
|
|
190
|
+
try {
|
|
191
|
+
if (referencedPathIdentity(target, false) === wanted)
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// A malformed candidate is not the link the client asked to open.
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
/** Decode exactly the entity spellings emitted by the composer. A single
|
|
201
|
+
* pass is intentional: double-encoded input must not turn into a path only
|
|
202
|
+
* while it is being authorised. */
|
|
203
|
+
function decodeAttachmentAttribute(value) {
|
|
204
|
+
return value.replace(/&(quot|lt|gt|amp);|&#(9|10|13);/g, (entity, named, numeric) => {
|
|
205
|
+
if (numeric === "9")
|
|
206
|
+
return "\t";
|
|
207
|
+
if (numeric === "10")
|
|
208
|
+
return "\n";
|
|
209
|
+
if (numeric === "13")
|
|
210
|
+
return "\r";
|
|
211
|
+
if (named === "quot")
|
|
212
|
+
return '"';
|
|
213
|
+
if (named === "lt")
|
|
214
|
+
return "<";
|
|
215
|
+
if (named === "gt")
|
|
216
|
+
return ">";
|
|
217
|
+
if (named === "amp")
|
|
218
|
+
return "&";
|
|
219
|
+
return entity;
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
function utf8Prefix(value, maximumBytes) {
|
|
223
|
+
let bytes = 0;
|
|
224
|
+
let result = "";
|
|
225
|
+
for (const character of value) {
|
|
226
|
+
const size = Buffer.byteLength(character);
|
|
227
|
+
if (bytes + size > maximumBytes)
|
|
228
|
+
break;
|
|
229
|
+
result += character;
|
|
230
|
+
bytes += size;
|
|
231
|
+
}
|
|
232
|
+
return result;
|
|
233
|
+
}
|
|
234
|
+
/** Keep the eventual native filename below common 255-byte component limits.
|
|
235
|
+
* 180 bytes leaves room for the app's temporary-file suffix. */
|
|
236
|
+
function boundedDisplayName(value, maximumBytes = 180) {
|
|
237
|
+
if (Buffer.byteLength(value) <= maximumBytes)
|
|
238
|
+
return value;
|
|
239
|
+
const extension = extname(value);
|
|
240
|
+
const extensionBytes = Buffer.byteLength(extension);
|
|
241
|
+
if (extension && extensionBytes <= 32 && extensionBytes < maximumBytes) {
|
|
242
|
+
const stem = utf8Prefix(value.slice(0, -extension.length), maximumBytes - extensionBytes);
|
|
243
|
+
if (stem)
|
|
244
|
+
return `${stem}${extension}`;
|
|
245
|
+
}
|
|
246
|
+
return utf8Prefix(value, maximumBytes) || "download";
|
|
247
|
+
}
|
|
248
|
+
function safeDisplayName(value) {
|
|
249
|
+
const portable = value.split(/[\\/]/).at(-1) ?? "";
|
|
250
|
+
const clean = Array.from(portable, (character) => {
|
|
251
|
+
const code = character.codePointAt(0) ?? 0;
|
|
252
|
+
const invalid = code <= 31 || (code >= 127 && code <= 159)
|
|
253
|
+
|| (code >= 0xd800 && code <= 0xdfff)
|
|
254
|
+
|| (code >= 0x202a && code <= 0x202e)
|
|
255
|
+
|| (code >= 0x2066 && code <= 0x2069);
|
|
256
|
+
return invalid ? "_" : character;
|
|
257
|
+
}).join("").trim();
|
|
258
|
+
return boundedDisplayName(clean || "download");
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Confirm that a stored user message carries the requested attachment as an
|
|
262
|
+
* exact standalone transport tag. Plain prose, inline examples, fenced code,
|
|
263
|
+
* and near-matching paths do not grant access. The HTTP route pairs this
|
|
264
|
+
* message capability with ATTACHMENTS_DIR containment, so this can never
|
|
265
|
+
* become an arbitrary host-file reader.
|
|
266
|
+
*/
|
|
267
|
+
export function messageReferencesAttachment(text, requested) {
|
|
268
|
+
return messageAttachmentName(text, requested) !== null;
|
|
269
|
+
}
|
|
270
|
+
/** Return the user-facing name carried by an authorised attachment tag. */
|
|
271
|
+
export function messageAttachmentName(text, requested) {
|
|
272
|
+
let wanted;
|
|
273
|
+
try {
|
|
274
|
+
wanted = referencedPathIdentity(requested);
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
const tag = /^<attached-(?:image|file)[\t ]+path="([^"\r\n]*)"(?:[\t ]+name="([^"\r\n]*)")?[\t ]*\/>$/;
|
|
280
|
+
let found = null;
|
|
281
|
+
walkMarkdown(fromMarkdown(text), (node) => {
|
|
282
|
+
if (found !== null)
|
|
283
|
+
return;
|
|
284
|
+
if (node.type !== "html" || !node.value || !node.position)
|
|
285
|
+
return;
|
|
286
|
+
const start = node.position.start.offset;
|
|
287
|
+
const end = node.position.end.offset;
|
|
288
|
+
if (start === undefined || end === undefined)
|
|
289
|
+
return;
|
|
290
|
+
const lineStart = text.lastIndexOf("\n", start - 1) + 1;
|
|
291
|
+
const nextLine = text.indexOf("\n", end);
|
|
292
|
+
const lineEnd = nextLine < 0 ? text.length : nextLine;
|
|
293
|
+
if (text.slice(lineStart, start).trim() || text.slice(end, lineEnd).trim())
|
|
294
|
+
return;
|
|
295
|
+
const match = tag.exec(node.value);
|
|
296
|
+
if (!match)
|
|
297
|
+
return;
|
|
298
|
+
try {
|
|
299
|
+
if (referencedPathIdentity(decodeAttachmentAttribute(match[1])) === wanted) {
|
|
300
|
+
found = safeDisplayName(match[2]
|
|
301
|
+
? decodeAttachmentAttribute(match[2])
|
|
302
|
+
: decodeAttachmentAttribute(match[1]));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
// A malformed transport tag grants no capability.
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
return found;
|
|
310
|
+
}
|
|
311
|
+
function containedBy(root, candidate) {
|
|
312
|
+
const suffix = relative(root, candidate);
|
|
313
|
+
return suffix === "" || (suffix !== ".." && !suffix.startsWith(`..${sep}`) && !isAbsolute(suffix));
|
|
314
|
+
}
|
|
315
|
+
function mimeFor(path) {
|
|
316
|
+
switch (extname(path).toLowerCase()) {
|
|
317
|
+
case ".md": return "text/markdown; charset=utf-8";
|
|
318
|
+
case ".txt": return "text/plain; charset=utf-8";
|
|
319
|
+
case ".csv": return "text/csv; charset=utf-8";
|
|
320
|
+
case ".tsv": return "text/tab-separated-values; charset=utf-8";
|
|
321
|
+
case ".json": return "application/json";
|
|
322
|
+
case ".pdf": return "application/pdf";
|
|
323
|
+
case ".rtf": return "application/rtf";
|
|
324
|
+
case ".png": return "image/png";
|
|
325
|
+
case ".jpg":
|
|
326
|
+
case ".jpeg": return "image/jpeg";
|
|
327
|
+
case ".gif": return "image/gif";
|
|
328
|
+
case ".webp": return "image/webp";
|
|
329
|
+
case ".doc": return "application/msword";
|
|
330
|
+
case ".docx": return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
331
|
+
case ".xls": return "application/vnd.ms-excel";
|
|
332
|
+
case ".xlsx": return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
333
|
+
case ".ppt": return "application/vnd.ms-powerpoint";
|
|
334
|
+
case ".pptx": return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
|
335
|
+
case ".odt": return "application/vnd.oasis.opendocument.text";
|
|
336
|
+
case ".ods": return "application/vnd.oasis.opendocument.spreadsheet";
|
|
337
|
+
case ".odp": return "application/vnd.oasis.opendocument.presentation";
|
|
338
|
+
default: return "application/octet-stream";
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Open a message-linked file under one of the supplied roots. The returned
|
|
343
|
+
* handle, not the pathname, is what the caller streams. We canonicalise both
|
|
344
|
+
* before and after opening and compare the handle with the post-open path;
|
|
345
|
+
* this rejects symlink escapes and directory swaps instead of checking a
|
|
346
|
+
* path and then opening a potentially different file.
|
|
347
|
+
*/
|
|
348
|
+
export async function openMessageFile(href, roots) {
|
|
349
|
+
const requested = referencedPath(href);
|
|
350
|
+
const canonicalRoots = (await Promise.all(roots.map(async (root) => {
|
|
351
|
+
try {
|
|
352
|
+
const canonical = await realpath(root);
|
|
353
|
+
return (await stat(canonical)).isDirectory() ? canonical : null;
|
|
354
|
+
}
|
|
355
|
+
catch {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
}))).filter((root) => Boolean(root));
|
|
359
|
+
if (canonicalRoots.length === 0)
|
|
360
|
+
throw statusError(404, "the linked file is unavailable");
|
|
361
|
+
const candidates = isAbsolute(requested)
|
|
362
|
+
? [resolve(requested)]
|
|
363
|
+
: canonicalRoots.map((root) => resolve(root, requested));
|
|
364
|
+
let sawOutsideRoot = false;
|
|
365
|
+
for (const candidate of new Set(candidates)) {
|
|
366
|
+
let canonicalBefore;
|
|
367
|
+
try {
|
|
368
|
+
canonicalBefore = await realpath(candidate);
|
|
369
|
+
}
|
|
370
|
+
catch {
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
const root = canonicalRoots.find((allowed) => containedBy(allowed, canonicalBefore));
|
|
374
|
+
if (!root) {
|
|
375
|
+
sawOutsideRoot = true;
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
let handle;
|
|
379
|
+
try {
|
|
380
|
+
const noFollow = typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
|
|
381
|
+
handle = await open(canonicalBefore, constants.O_RDONLY | noFollow);
|
|
382
|
+
const opened = await handle.stat();
|
|
383
|
+
if (!opened.isFile())
|
|
384
|
+
throw statusError(400, "the link does not point to a regular file");
|
|
385
|
+
if (opened.size > MESSAGE_FILE_MAX_BYTES) {
|
|
386
|
+
throw statusError(413, `file exceeds ${MESSAGE_FILE_MAX_BYTES} bytes`);
|
|
387
|
+
}
|
|
388
|
+
const canonicalAfter = await realpath(candidate);
|
|
389
|
+
if (!containedBy(root, canonicalAfter))
|
|
390
|
+
throw statusError(403, "the linked file is outside this conversation's workspace");
|
|
391
|
+
const after = await stat(canonicalAfter);
|
|
392
|
+
if (opened.dev !== after.dev || opened.ino !== after.ino) {
|
|
393
|
+
throw statusError(409, "the linked file changed while it was being opened");
|
|
394
|
+
}
|
|
395
|
+
return {
|
|
396
|
+
handle,
|
|
397
|
+
bytes: opened.size,
|
|
398
|
+
name: basename(canonicalAfter),
|
|
399
|
+
mime: mimeFor(canonicalAfter),
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
await handle?.close().catch(() => undefined);
|
|
404
|
+
if (error && typeof error === "object" && "status" in error)
|
|
405
|
+
throw error;
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
if (sawOutsideRoot)
|
|
410
|
+
throw statusError(403, "the linked file is outside this conversation's workspace");
|
|
411
|
+
throw statusError(404, "the linked file is unavailable");
|
|
412
|
+
}
|
|
413
|
+
/** A safe attachment header with a readable ASCII fallback and UTF-8 name. */
|
|
414
|
+
export function messageFileDisposition(name) {
|
|
415
|
+
const safeName = safeDisplayName(name);
|
|
416
|
+
const fallback = safeName
|
|
417
|
+
.normalize("NFKD")
|
|
418
|
+
.replace(/[^\x20-\x7e]/g, "_")
|
|
419
|
+
.replace(/["\\]/g, "_")
|
|
420
|
+
.slice(0, 180) || "download";
|
|
421
|
+
const encoded = encodeURIComponent(safeName).replace(/[!'()*]/g, (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
422
|
+
return `attachment; filename="${fallback}"; filename*=UTF-8''${encoded}`;
|
|
423
|
+
}
|
|
424
|
+
/** Keep a friendly transport name without allowing it to disguise the bytes'
|
|
425
|
+
* canonical extension (for example PDF bytes named setup.exe). */
|
|
426
|
+
export function messageFileDownloadName(displayName, canonicalName) {
|
|
427
|
+
const canonical = safeDisplayName(canonicalName);
|
|
428
|
+
if (!displayName)
|
|
429
|
+
return canonical;
|
|
430
|
+
const display = safeDisplayName(displayName);
|
|
431
|
+
const actualExtension = extname(canonical);
|
|
432
|
+
if (!actualExtension)
|
|
433
|
+
return canonical;
|
|
434
|
+
if (extname(display).toLowerCase() === actualExtension.toLowerCase())
|
|
435
|
+
return display;
|
|
436
|
+
const displayExtension = extname(display);
|
|
437
|
+
const stem = displayExtension ? display.slice(0, -displayExtension.length) : display;
|
|
438
|
+
return safeDisplayName(`${stem || "download"}${actualExtension}`);
|
|
439
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Bot name generator — a curated local list beats a naming API: instant,
|
|
2
|
+
// offline, and every name is on-brand (short, friendly, a little pet-like,
|
|
3
|
+
// which suits the Maus). Picks avoid names already in use; when the pool is
|
|
4
|
+
// exhausted it falls back to "Name 2", "Name 3", …
|
|
5
|
+
const NAMES = [
|
|
6
|
+
"Scout", "Pixel", "Atlas", "Nova", "Juno", "Koda", "Miso", "Mochi",
|
|
7
|
+
"Biscuit", "Pepper", "Clover", "Ember", "Willow", "Comet", "Orbit", "Echo",
|
|
8
|
+
"Indigo", "Sage", "Zephyr", "Poppy", "Maple", "Cosmo", "Luna", "Otto",
|
|
9
|
+
"Ivy", "Finch", "Wren", "Basil", "Hazel", "Nimbus", "Onyx", "Pearl",
|
|
10
|
+
"Quill", "Rocket", "Sunny", "Tango", "Vega", "Waffle", "Ziggy", "Noodle",
|
|
11
|
+
"Pickle", "Churro", "Panko", "Dumpling", "Pesto", "Olive", "Cocoa", "Taffy",
|
|
12
|
+
"Bramble", "Fig", "Juniper", "Moss", "Pebble", "Rio", "Skye", "Tuli",
|
|
13
|
+
"Ursa", "Yuki", "Zuko", "Momo", "Kiwi", "Plum", "Sprout", "Turnip",
|
|
14
|
+
];
|
|
15
|
+
export function pickBotName(taken) {
|
|
16
|
+
const used = new Set([...taken].map((n) => n.trim().toLowerCase()));
|
|
17
|
+
const free = NAMES.filter((n) => !used.has(n.toLowerCase()));
|
|
18
|
+
if (free.length > 0)
|
|
19
|
+
return free[Math.floor(Math.random() * free.length)];
|
|
20
|
+
// pool exhausted — number a random base name
|
|
21
|
+
const base = NAMES[Math.floor(Math.random() * NAMES.length)];
|
|
22
|
+
for (let i = 2;; i++) {
|
|
23
|
+
if (!used.has(`${base.toLowerCase()} ${i}`))
|
|
24
|
+
return `${base} ${i}`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Notifications — what is worth interrupting someone for.
|
|
2
|
+
//
|
|
3
|
+
// `BotRecord.notifications` has been a switch in the settings panel that
|
|
4
|
+
// nothing read. This is the thing that reads it. The rule it encodes is
|
|
5
|
+
// small and deliberate: a bot that is *blocked on you* is worth a buzz, and
|
|
6
|
+
// a bot that *finished* is worth one if you asked for it; everything else a
|
|
7
|
+
// bot does while it works is not.
|
|
8
|
+
//
|
|
9
|
+
// A turn that dies before it starts is the first case, not the last: the
|
|
10
|
+
// bot is not working, and the fix is usually a setting only a person can
|
|
11
|
+
// change, so a retry cannot clear it. A routine failure already buzzed;
|
|
12
|
+
// this makes an interactive turn behave the same way.
|
|
13
|
+
//
|
|
14
|
+
// Delivery is a separate concern. The harness emits a frame; whoever is
|
|
15
|
+
// listening decides what to do with it — desktop and paired-phone local
|
|
16
|
+
// notifications today, and closed-app APNs delivery once a relay exists.
|
|
17
|
+
/** One line, short enough for a lock screen, with the newlines and code
|
|
18
|
+
* fences of a model's answer flattened out of it. */
|
|
19
|
+
export function summarize(text, max = 140) {
|
|
20
|
+
const line = text.replace(/```[\s\S]*?```/g, " ").replace(/\s+/g, " ").trim();
|
|
21
|
+
return line.length > max ? `${line.slice(0, max - 1).trimEnd()}…` : line;
|
|
22
|
+
}
|
|
23
|
+
/** Where a "blocked on you" notification has to open. A bot speaking in a
|
|
24
|
+
* room is not reachable in its own 1:1 thread — the turn, its screen and the
|
|
25
|
+
* card all live in the room — so the room wins while it owns that bot. A
|
|
26
|
+
* room it merely belongs to, or one another member is speaking in, is not
|
|
27
|
+
* where this bot is: those fall back to its own thread. */
|
|
28
|
+
export function blockedTarget(bot, room) {
|
|
29
|
+
if (!room || room.busyBotId !== bot.id)
|
|
30
|
+
return { threadId: bot.threadId };
|
|
31
|
+
return { threadId: room.threadId, group: { id: room.id, name: room.name } };
|
|
32
|
+
}
|
|
33
|
+
/** Build the frame for one event, or null when it should stay quiet.
|
|
34
|
+
*
|
|
35
|
+
* Kept pure and separate from the event fold so the policy — which is the
|
|
36
|
+
* part people will argue about — can be read and tested on its own. */
|
|
37
|
+
export function buildNotification(kind, bot, threadId, detail, extra) {
|
|
38
|
+
// The toggle means what it says: off is off, including for approvals.
|
|
39
|
+
// A bot whose notifications you turned off can still block waiting for
|
|
40
|
+
// you — that is the choice you made, and the chat still shows the card.
|
|
41
|
+
if (bot.notifications === false)
|
|
42
|
+
return null;
|
|
43
|
+
const body = summarize(detail);
|
|
44
|
+
// A bot working in a room is not "Scout" to whoever reads the banner — it
|
|
45
|
+
// is Scout, in that room. Name the room or the notification reads as if it
|
|
46
|
+
// came from the 1:1 thread it will not open.
|
|
47
|
+
const who = extra?.group ? `${bot.name} in ${extra.group.name}` : bot.name;
|
|
48
|
+
const title = kind === "approval"
|
|
49
|
+
? `${who} needs approval`
|
|
50
|
+
: kind === "question"
|
|
51
|
+
? `${who} has a question`
|
|
52
|
+
: kind === "takeover"
|
|
53
|
+
? `${who} needs your hands`
|
|
54
|
+
: kind === "routine-failed"
|
|
55
|
+
? `${who}'s routine failed`
|
|
56
|
+
: kind === "turn-failed"
|
|
57
|
+
? `${who} couldn't start`
|
|
58
|
+
: `${who} finished`;
|
|
59
|
+
// A "finished" with nothing to say is not worth a notification — the
|
|
60
|
+
// badge in the sidebar already carries that much.
|
|
61
|
+
if (kind === "done" && !body)
|
|
62
|
+
return null;
|
|
63
|
+
const notification = { kind, botId: bot.id, botName: bot.name, threadId, title, body };
|
|
64
|
+
if (extra?.avatarUrl)
|
|
65
|
+
notification.avatarUrl = extra.avatarUrl;
|
|
66
|
+
if (extra?.group)
|
|
67
|
+
notification.groupId = extra.group.id;
|
|
68
|
+
return notification;
|
|
69
|
+
}
|