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,358 @@
|
|
|
1
|
+
import { createECDH, createHash } from "node:crypto";
|
|
2
|
+
import { Aes256Gcm, CipherSuite, DhkemP256HkdfSha256, HkdfSha256, } from "@hpke/core";
|
|
3
|
+
export const PHONE_SECRET_PROTOCOL_VERSION = 1;
|
|
4
|
+
export const PHONE_SECRET_INFO = "OpenMausBot phone credential v1";
|
|
5
|
+
export const PHONE_SECRET_MAX_BYTES = 4_096;
|
|
6
|
+
const BASE64URL = /^[A-Za-z0-9_-]+$/;
|
|
7
|
+
const ROUTE_ID = /^[\w-]{1,128}$/;
|
|
8
|
+
const TARGET_ID = /^[A-Za-z][A-Za-z0-9]{0,63}$/;
|
|
9
|
+
export class PhoneSecretError extends Error {
|
|
10
|
+
status;
|
|
11
|
+
constructor(message, status = 400) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "PhoneSecretError";
|
|
14
|
+
this.status = status;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const suite = new CipherSuite({
|
|
18
|
+
kem: new DhkemP256HkdfSha256(),
|
|
19
|
+
kdf: new HkdfSha256(),
|
|
20
|
+
aead: new Aes256Gcm(),
|
|
21
|
+
});
|
|
22
|
+
const INFO = new TextEncoder().encode(PHONE_SECRET_INFO);
|
|
23
|
+
const decodeBase64URL = (value, expectedBytes) => {
|
|
24
|
+
if (typeof value !== "string" || !BASE64URL.test(value))
|
|
25
|
+
return null;
|
|
26
|
+
try {
|
|
27
|
+
const decoded = Buffer.from(value, "base64url");
|
|
28
|
+
if ((expectedBytes !== undefined && decoded.length !== expectedBytes) ||
|
|
29
|
+
decoded.toString("base64url") !== value) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return decoded;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
export function phoneSecretKeyIdFromJwk(jwk) {
|
|
39
|
+
const x = decodeBase64URL(jwk.x, 32);
|
|
40
|
+
const y = decodeBase64URL(jwk.y, 32);
|
|
41
|
+
if (!x || !y)
|
|
42
|
+
return null;
|
|
43
|
+
return createHash("sha256")
|
|
44
|
+
.update(Buffer.concat([Buffer.from([4]), x, y]))
|
|
45
|
+
.digest()
|
|
46
|
+
.subarray(0, 16)
|
|
47
|
+
.toString("base64url");
|
|
48
|
+
}
|
|
49
|
+
/** A single canonical string is used by Swift and TypeScript. Every dynamic
|
|
50
|
+
* field is route-safe ASCII and therefore cannot contain the newline
|
|
51
|
+
* separator. Authenticating this metadata prevents a relay from moving one
|
|
52
|
+
* ciphertext to another bot, conversation, card, device, or credential. */
|
|
53
|
+
export function phoneSecretAAD(context) {
|
|
54
|
+
const fields = [
|
|
55
|
+
"openmausbot-phone-credential-v1",
|
|
56
|
+
context.keyId,
|
|
57
|
+
context.deviceId,
|
|
58
|
+
context.botId,
|
|
59
|
+
context.threadId,
|
|
60
|
+
context.messageId,
|
|
61
|
+
context.target,
|
|
62
|
+
context.requestKey,
|
|
63
|
+
];
|
|
64
|
+
if (!/^[A-Za-z0-9_-]{22}$/.test(context.keyId) ||
|
|
65
|
+
!fields.slice(2, 6).every((value) => ROUTE_ID.test(value)) ||
|
|
66
|
+
!TARGET_ID.test(context.target) ||
|
|
67
|
+
!ROUTE_ID.test(context.requestKey)) {
|
|
68
|
+
throw new PhoneSecretError("The credential request metadata is invalid");
|
|
69
|
+
}
|
|
70
|
+
return new TextEncoder().encode(fields.join("\n"));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* A stable, non-secret operation id for one exact HPKE envelope. Electron
|
|
74
|
+
* uses it to join a retry whose HTTP response was lost instead of validating
|
|
75
|
+
* and writing the same credential twice. A freshly encrypted submission has
|
|
76
|
+
* a different encapsulated key/ciphertext and therefore a different id.
|
|
77
|
+
*/
|
|
78
|
+
export function phoneSecretOperationId(context) {
|
|
79
|
+
const aad = phoneSecretAAD(context);
|
|
80
|
+
return createHash("sha256")
|
|
81
|
+
.update(aad)
|
|
82
|
+
.update("\0")
|
|
83
|
+
.update(String(context.version))
|
|
84
|
+
.update("\n")
|
|
85
|
+
.update(context.encapsulatedKey)
|
|
86
|
+
.update("\n")
|
|
87
|
+
.update(context.ciphertext)
|
|
88
|
+
.digest("base64url");
|
|
89
|
+
}
|
|
90
|
+
export function assertPhoneSecretRequestMatches(context, authenticatedDeviceId, expected) {
|
|
91
|
+
if (context.deviceId !== authenticatedDeviceId ||
|
|
92
|
+
context.target !== expected.target ||
|
|
93
|
+
context.requestKey !== expected.requestKey) {
|
|
94
|
+
throw new PhoneSecretError("This encrypted credential does not belong to this request", 409);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** Serializes the state transition for one pending credential card. Exact
|
|
98
|
+
* retransmissions join the original operation; a separately encrypted value
|
|
99
|
+
* cannot be mistaken for that retry, and callers can block dismiss/resume
|
|
100
|
+
* while the operating-system store is committing. */
|
|
101
|
+
export class PhoneSecretSubmissionRegistry {
|
|
102
|
+
active = new Map();
|
|
103
|
+
mutations = new Set();
|
|
104
|
+
resources(scope) {
|
|
105
|
+
return new Set([
|
|
106
|
+
...(scope.botId ? [`bot:${scope.botId}`] : []),
|
|
107
|
+
...(scope.threadId ? [`thread:${scope.threadId}`] : []),
|
|
108
|
+
...(scope.groupId ? [`group:${scope.groupId}`] : []),
|
|
109
|
+
]);
|
|
110
|
+
}
|
|
111
|
+
hasActiveResource(resources) {
|
|
112
|
+
return [...this.active.values()].some((entry) => [...resources].some((resource) => entry.resources.has(resource)));
|
|
113
|
+
}
|
|
114
|
+
has(cardKey) {
|
|
115
|
+
return this.active.has(cardKey);
|
|
116
|
+
}
|
|
117
|
+
hasBot(botId) {
|
|
118
|
+
return this.hasActiveResource(this.resources({ botId }));
|
|
119
|
+
}
|
|
120
|
+
hasThread(threadId) {
|
|
121
|
+
return this.hasActiveResource(this.resources({ threadId }));
|
|
122
|
+
}
|
|
123
|
+
hasGroup(groupId) {
|
|
124
|
+
return this.hasActiveResource(this.resources({ groupId }));
|
|
125
|
+
}
|
|
126
|
+
/** Claim a structural mutation before its first await. A submission and a
|
|
127
|
+
* destructive/rewind mutation can then never both pass their preflight
|
|
128
|
+
* checks and invalidate each other while the OS credential store is slow. */
|
|
129
|
+
claimMutation(scope) {
|
|
130
|
+
const resources = this.resources(scope);
|
|
131
|
+
if (resources.size === 0 ||
|
|
132
|
+
this.hasActiveResource(resources) ||
|
|
133
|
+
[...resources].some((resource) => this.mutations.has(resource))) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
for (const resource of resources)
|
|
137
|
+
this.mutations.add(resource);
|
|
138
|
+
let released = false;
|
|
139
|
+
return () => {
|
|
140
|
+
if (released)
|
|
141
|
+
return;
|
|
142
|
+
released = true;
|
|
143
|
+
for (const resource of resources)
|
|
144
|
+
this.mutations.delete(resource);
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
async run(scope, operationId, work) {
|
|
148
|
+
const running = this.active.get(scope.cardKey);
|
|
149
|
+
if (running) {
|
|
150
|
+
if (running.operationId !== operationId) {
|
|
151
|
+
throw new PhoneSecretError("Another credential submission is already being saved", 409);
|
|
152
|
+
}
|
|
153
|
+
await running.promise;
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const resources = this.resources(scope);
|
|
157
|
+
if ([...resources].some((resource) => this.mutations.has(resource))) {
|
|
158
|
+
throw new PhoneSecretError("This credential request is being changed. Try again.", 409);
|
|
159
|
+
}
|
|
160
|
+
// Deferring work by one microtask lets the registry publish the active
|
|
161
|
+
// entry before decrypt/save begins, so no synchronous callback can slip a
|
|
162
|
+
// competing state transition through the gap.
|
|
163
|
+
const promise = Promise.resolve().then(work);
|
|
164
|
+
const entry = { operationId, promise, resources };
|
|
165
|
+
this.active.set(scope.cardKey, entry);
|
|
166
|
+
try {
|
|
167
|
+
await promise;
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
if (this.active.get(scope.cardKey) === entry)
|
|
171
|
+
this.active.delete(scope.cardKey);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
async function importIdentity(message) {
|
|
176
|
+
if (message.version !== PHONE_SECRET_PROTOCOL_VERSION) {
|
|
177
|
+
throw new PhoneSecretError("The desktop credential key version is unsupported", 503);
|
|
178
|
+
}
|
|
179
|
+
const keyId = String(message.keyId ?? "");
|
|
180
|
+
const candidate = message.privateKey;
|
|
181
|
+
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
182
|
+
throw new PhoneSecretError("The desktop credential key is unavailable", 503);
|
|
183
|
+
}
|
|
184
|
+
const privateKey = candidate;
|
|
185
|
+
const x = decodeBase64URL(privateKey.x, 32);
|
|
186
|
+
const y = decodeBase64URL(privateKey.y, 32);
|
|
187
|
+
const d = decodeBase64URL(privateKey.d, 32);
|
|
188
|
+
if (privateKey.kty !== "EC" ||
|
|
189
|
+
privateKey.crv !== "P-256" ||
|
|
190
|
+
!x ||
|
|
191
|
+
!y ||
|
|
192
|
+
!d ||
|
|
193
|
+
phoneSecretKeyIdFromJwk(privateKey) !== keyId) {
|
|
194
|
+
throw new PhoneSecretError("The desktop credential key is invalid", 503);
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
const ecdh = createECDH("prime256v1");
|
|
198
|
+
ecdh.setPrivateKey(d);
|
|
199
|
+
if (!ecdh.getPublicKey(undefined, "uncompressed").equals(Buffer.concat([Buffer.from([4]), x, y]))) {
|
|
200
|
+
throw new Error("mismatched public point");
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
throw new PhoneSecretError("The desktop credential key is invalid", 503);
|
|
205
|
+
}
|
|
206
|
+
const imported = await suite.kem.importKey("jwk", {
|
|
207
|
+
kty: "EC",
|
|
208
|
+
crv: "P-256",
|
|
209
|
+
x: privateKey.x,
|
|
210
|
+
y: privateKey.y,
|
|
211
|
+
d: privateKey.d,
|
|
212
|
+
ext: true,
|
|
213
|
+
key_ops: ["deriveBits"],
|
|
214
|
+
}, false);
|
|
215
|
+
return { keyId, privateKey: imported };
|
|
216
|
+
}
|
|
217
|
+
function decodeSaveResult(raw) {
|
|
218
|
+
const message = raw?.data ?? raw;
|
|
219
|
+
if (!message || typeof message !== "object" || Array.isArray(message))
|
|
220
|
+
return null;
|
|
221
|
+
const value = message;
|
|
222
|
+
if (value.type !== "openmausbot:phone-secret-save-result")
|
|
223
|
+
return null;
|
|
224
|
+
if (typeof value.requestId !== "string" || !ROUTE_ID.test(value.requestId) || typeof value.ok !== "boolean") {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
requestId: value.requestId,
|
|
229
|
+
ok: value.ok,
|
|
230
|
+
...(typeof value.error === "string" ? { error: value.error.slice(0, 180) } : {}),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Owns the narrow private bridge between the embedded server and Electron's
|
|
235
|
+
* OS-encrypted credential document. The phone-facing HTTP route gives this
|
|
236
|
+
* class ciphertext only. Plaintext exists only after HPKE opens it on the
|
|
237
|
+
* desktop and is immediately handed to the already-existing credential save
|
|
238
|
+
* path; it is never returned to HTTP, chat, SQLite, SSE, or logs.
|
|
239
|
+
*/
|
|
240
|
+
export class PhoneSecretBridge {
|
|
241
|
+
identity = null;
|
|
242
|
+
pending = new Map();
|
|
243
|
+
active = 0;
|
|
244
|
+
send;
|
|
245
|
+
timeoutMs;
|
|
246
|
+
maximumPending;
|
|
247
|
+
constructor(send,
|
|
248
|
+
// Provider validation is part of the encrypted-store transaction and can
|
|
249
|
+
// legitimately take tens of seconds. This remains bounded, but outlives
|
|
250
|
+
// every provider's own deadline so a late successful save is not reported
|
|
251
|
+
// as a failure and then repeated underneath the user.
|
|
252
|
+
// Stay materially below the outer HTTPS proxy and phone deadlines. This
|
|
253
|
+
// leaves enough time for their JSON response to travel after a slow
|
|
254
|
+
// provider validation instead of turning a committed save into a client
|
|
255
|
+
// timeout at Cloudflare's boundary.
|
|
256
|
+
timeoutMs = 90_000, maximumPending = 8) {
|
|
257
|
+
this.send = send;
|
|
258
|
+
this.timeoutMs = timeoutMs;
|
|
259
|
+
this.maximumPending = maximumPending;
|
|
260
|
+
}
|
|
261
|
+
receive(raw) {
|
|
262
|
+
const message = raw?.data ?? raw;
|
|
263
|
+
if (!message || typeof message !== "object" || Array.isArray(message))
|
|
264
|
+
return false;
|
|
265
|
+
const record = message;
|
|
266
|
+
if (record.type === "openmausbot:phone-secret-key") {
|
|
267
|
+
// Keep the rejection inside the promise. A request receives a bounded
|
|
268
|
+
// 503; an invalid parent message must never become an unhandled reject.
|
|
269
|
+
this.identity = importIdentity(record);
|
|
270
|
+
void this.identity.catch(() => { });
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
const result = decodeSaveResult(record);
|
|
274
|
+
if (!result)
|
|
275
|
+
return false;
|
|
276
|
+
const pending = this.pending.get(result.requestId);
|
|
277
|
+
if (!pending)
|
|
278
|
+
return true;
|
|
279
|
+
this.pending.delete(result.requestId);
|
|
280
|
+
clearTimeout(pending.timer);
|
|
281
|
+
if (result.ok)
|
|
282
|
+
pending.resolve();
|
|
283
|
+
else
|
|
284
|
+
pending.reject(new PhoneSecretError(result.error || "The credential could not be saved", 503));
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
async provide(context) {
|
|
288
|
+
if (this.active >= this.maximumPending) {
|
|
289
|
+
throw new PhoneSecretError("Another secure credential is still being saved. Try again.", 429);
|
|
290
|
+
}
|
|
291
|
+
this.active += 1;
|
|
292
|
+
try {
|
|
293
|
+
await this.provideWithinLimit(context);
|
|
294
|
+
}
|
|
295
|
+
finally {
|
|
296
|
+
this.active -= 1;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
async provideWithinLimit(context) {
|
|
300
|
+
if (!this.identity) {
|
|
301
|
+
throw new PhoneSecretError("Secure phone entry is not ready on this computer. Reopen OpenMausBot and try again.", 503);
|
|
302
|
+
}
|
|
303
|
+
const identity = await this.identity.catch(() => {
|
|
304
|
+
throw new PhoneSecretError("Secure phone entry is not ready on this computer. Reopen OpenMausBot and try again.", 503);
|
|
305
|
+
});
|
|
306
|
+
if (context.version !== PHONE_SECRET_PROTOCOL_VERSION || context.keyId !== identity.keyId) {
|
|
307
|
+
throw new PhoneSecretError("This phone was paired with an older security key. Pair it again by QR code.", 409);
|
|
308
|
+
}
|
|
309
|
+
const encapsulatedKey = decodeBase64URL(context.encapsulatedKey, 65);
|
|
310
|
+
const ciphertext = decodeBase64URL(context.ciphertext);
|
|
311
|
+
if (!encapsulatedKey ||
|
|
312
|
+
!ciphertext ||
|
|
313
|
+
ciphertext.length <= 16 ||
|
|
314
|
+
ciphertext.length > PHONE_SECRET_MAX_BYTES + 16) {
|
|
315
|
+
throw new PhoneSecretError("The encrypted credential is invalid");
|
|
316
|
+
}
|
|
317
|
+
let opened;
|
|
318
|
+
try {
|
|
319
|
+
opened = await suite.open({ recipientKey: identity.privateKey, enc: encapsulatedKey, info: INFO }, ciphertext, phoneSecretAAD(context));
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
throw new PhoneSecretError("The encrypted credential could not be verified");
|
|
323
|
+
}
|
|
324
|
+
const openedBytes = new Uint8Array(opened);
|
|
325
|
+
let value;
|
|
326
|
+
try {
|
|
327
|
+
value = new TextDecoder("utf-8", { fatal: true }).decode(openedBytes).trim();
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
throw new PhoneSecretError("The encrypted credential is not valid text");
|
|
331
|
+
}
|
|
332
|
+
finally {
|
|
333
|
+
openedBytes.fill(0);
|
|
334
|
+
}
|
|
335
|
+
if (!value || Buffer.byteLength(value) > PHONE_SECRET_MAX_BYTES) {
|
|
336
|
+
throw new PhoneSecretError("The credential must be between 1 and 4096 bytes");
|
|
337
|
+
}
|
|
338
|
+
const requestId = phoneSecretOperationId(context);
|
|
339
|
+
await new Promise((resolve, reject) => {
|
|
340
|
+
const timer = setTimeout(() => {
|
|
341
|
+
this.pending.delete(requestId);
|
|
342
|
+
reject(new PhoneSecretError("The operating-system credential store did not respond. Try again.", 504));
|
|
343
|
+
}, this.timeoutMs);
|
|
344
|
+
timer.unref?.();
|
|
345
|
+
this.pending.set(requestId, { resolve, reject, timer });
|
|
346
|
+
if (this.send({
|
|
347
|
+
type: "openmausbot:phone-secret-save",
|
|
348
|
+
requestId,
|
|
349
|
+
target: context.target,
|
|
350
|
+
value,
|
|
351
|
+
}))
|
|
352
|
+
return;
|
|
353
|
+
clearTimeout(timer);
|
|
354
|
+
this.pending.delete(requestId);
|
|
355
|
+
reject(new PhoneSecretError("Secure phone entry is unavailable in this build.", 503));
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Capture a preview only while nobody holds the human-control lease. The
|
|
2
|
+
* second check matters for remote captures: a user can take over while the
|
|
3
|
+
* screenshot request is in flight, and that result may already contain what
|
|
4
|
+
* they started typing. */
|
|
5
|
+
export async function captureOutsideHumanControl(control, capture) {
|
|
6
|
+
const before = control();
|
|
7
|
+
if (before.held)
|
|
8
|
+
return null;
|
|
9
|
+
const { png, format } = await capture();
|
|
10
|
+
const after = control();
|
|
11
|
+
// Checking only `held` has a take→type→release race: a slow remote
|
|
12
|
+
// screenshot can finish after the lease is already false again. Any control
|
|
13
|
+
// transition during the request makes that frame private and disposable.
|
|
14
|
+
if (after.held || after.revision !== before.revision)
|
|
15
|
+
return null;
|
|
16
|
+
return { png, mime: format === "jpeg" ? "image/jpeg" : "image/png" };
|
|
17
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// Cross-platform process spawning for the agent CLIs. Four Windows
|
|
2
|
+
// differences are exposed to drivers through this module:
|
|
3
|
+
// 1. CreateProcess can't exec npm .cmd/.bat shims or node-shebang scripts
|
|
4
|
+
// directly. env-path resolves those to their real .exe / `node script`
|
|
5
|
+
// entry without a shell, so quoting-sensitive JSON argv stays intact.
|
|
6
|
+
// 2. No process-group kill (kill(-pid) is POSIX) — taskkill /T reaps the
|
|
7
|
+
// whole tree, CLI + its spawned MCP proxies alike.
|
|
8
|
+
// 3. Console apps spawned from the GUI shell flash a console window
|
|
9
|
+
// unless windowsHide is set.
|
|
10
|
+
// 4. CreateProcess has a 32,767-character command-line limit. Keep prompt
|
|
11
|
+
// bodies on stdin or in private files and fail clearly if a future
|
|
12
|
+
// driver accidentally puts one back in argv.
|
|
13
|
+
import { spawn, execFile, } from "node:child_process";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { resolveCliSpawn } from "./env-path.js";
|
|
16
|
+
export function resolveCli(cli, args = []) {
|
|
17
|
+
return resolveCliSpawn(cli, args);
|
|
18
|
+
}
|
|
19
|
+
/** Leave headroom below CreateProcess' 32,767 UTF-16 code-unit limit for
|
|
20
|
+
* libuv's quoting and environment-specific executable expansion. */
|
|
21
|
+
export const WINDOWS_SAFE_COMMAND_LINE_CHARS = 30_000;
|
|
22
|
+
/** Conservative size of the command line libuv will give CreateProcess.
|
|
23
|
+
* JSON string quoting escapes every slash/quote case Windows quoting needs,
|
|
24
|
+
* so this can over-count but cannot hide a dangerous launch. */
|
|
25
|
+
export function estimatedWindowsCommandLineChars(resolved) {
|
|
26
|
+
return [resolved.command, ...resolved.args].reduce((total, value) => total + JSON.stringify(value).length + 1, 0);
|
|
27
|
+
}
|
|
28
|
+
export function assertSafeCliArgv(resolved, platform = process.platform) {
|
|
29
|
+
if (platform !== "win32")
|
|
30
|
+
return;
|
|
31
|
+
if (estimatedWindowsCommandLineChars(resolved) <= WINDOWS_SAFE_COMMAND_LINE_CHARS)
|
|
32
|
+
return;
|
|
33
|
+
const error = new Error("agent CLI launch arguments exceed Windows' safe command-line limit; pass large prompts through stdin or a file");
|
|
34
|
+
error.code = "ENAMETOOLONG";
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
export function spawnCli(cli, args, opts) {
|
|
38
|
+
const resolved = resolveCli(cli, args);
|
|
39
|
+
assertSafeCliArgv(resolved);
|
|
40
|
+
const child = spawn(resolved.command, resolved.args, {
|
|
41
|
+
...opts,
|
|
42
|
+
// posix: own process group so kill(-pid) reaps child MCP servers;
|
|
43
|
+
// win32: taskkill /T does the reaping instead (see killCliTree)
|
|
44
|
+
...(process.platform === "win32" ? { windowsHide: true } : { detached: true }),
|
|
45
|
+
}); // callers always pipe all three
|
|
46
|
+
// A write to a dying child's stdin fails differently per platform, and one
|
|
47
|
+
// of the ways is fatal. On POSIX the kill is synchronous, the stream is
|
|
48
|
+
// already destroyed by the time anything writes, and the write throws into
|
|
49
|
+
// the caller's try/catch. On Windows killCliTree goes through taskkill — a
|
|
50
|
+
// subprocess — so there is a window where the child is dead but its pipe is
|
|
51
|
+
// not, and a write during it errors *asynchronously* on the stream. No
|
|
52
|
+
// driver listens for that, an unlistened stream error is an uncaught
|
|
53
|
+
// exception, and the whole harness exits over one dead CLI. The error
|
|
54
|
+
// carries no information the drivers don't already get from `close`, which
|
|
55
|
+
// is where every one of them settles the turn — so it is swallowed, not
|
|
56
|
+
// logged.
|
|
57
|
+
child.stdin?.on("error", () => { });
|
|
58
|
+
return child;
|
|
59
|
+
}
|
|
60
|
+
export function execCli(cli, args, opts, cb) {
|
|
61
|
+
const resolved = resolveCli(cli, args);
|
|
62
|
+
try {
|
|
63
|
+
assertSafeCliArgv(resolved);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
queueMicrotask(() => cb(error instanceof Error ? error : new Error(String(error)), "", ""));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
execFile(resolved.command, resolved.args, { ...opts, windowsHide: true, encoding: "utf8" }, (err, stdout, stderr) => cb(err, stdout, stderr));
|
|
70
|
+
}
|
|
71
|
+
export function describeSpawnFailure(err, cli) {
|
|
72
|
+
if (err.code === "ENOENT")
|
|
73
|
+
return { message: `\`${cli}\` isn't installed, or isn't on this app's PATH`, setup: true };
|
|
74
|
+
if (err.code === "EACCES" || err.code === "EPERM")
|
|
75
|
+
return { message: `\`${cli}\` isn't executable — check its file permissions`, setup: true };
|
|
76
|
+
if (err.code === "ENAMETOOLONG")
|
|
77
|
+
return {
|
|
78
|
+
message: `\`${cli}\` received too much launch data for Windows; update this provider or pass its prompt through stdin/a file`,
|
|
79
|
+
setup: false,
|
|
80
|
+
};
|
|
81
|
+
return { message: `spawn failed: ${err.message}`, setup: false };
|
|
82
|
+
}
|
|
83
|
+
/** Stop a CLI and every process it spawned (MCP proxies included). */
|
|
84
|
+
export function killCliTree(child) {
|
|
85
|
+
const pid = child.pid;
|
|
86
|
+
if (!pid || child.exitCode !== null || child.signalCode !== null)
|
|
87
|
+
return;
|
|
88
|
+
if (process.platform === "win32") {
|
|
89
|
+
execFile("taskkill", ["/PID", String(pid), "/T", "/F"], { windowsHide: true }, (err) => {
|
|
90
|
+
if (!err)
|
|
91
|
+
return;
|
|
92
|
+
try {
|
|
93
|
+
// taskkill is unavailable or the tree lookup failed. At least stop
|
|
94
|
+
// the process we own instead of leaving the entire turn running.
|
|
95
|
+
child.kill();
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
/* already gone */
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
process.kill(-pid, "SIGTERM");
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
try {
|
|
108
|
+
child.kill("SIGTERM");
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
/* already gone */
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/** Per-turn broker channel: unix socket on POSIX, named pipe on Windows
|
|
116
|
+
* (Node can't listen on a filesystem socket path there — EACCES). */
|
|
117
|
+
export function brokerSocketPath(dataDir, tag) {
|
|
118
|
+
return process.platform === "win32"
|
|
119
|
+
// Named pipes share a global namespace; DATA_DIR cannot isolate two
|
|
120
|
+
// concurrent app instances the way a POSIX socket directory does.
|
|
121
|
+
? `\\\\.\\pipe\\openmausbot-perm-${process.pid}-${tag}`
|
|
122
|
+
: join(dataDir, `perm-${tag}.sock`);
|
|
123
|
+
}
|