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
|
+
// SQLite persistence for thread transcripts.
|
|
2
|
+
//
|
|
3
|
+
// messages-<threadId>.json rewrote the WHOLE thread file on every append —
|
|
4
|
+
// a long computer-use thread reaches megabytes, so each new message cost
|
|
5
|
+
// more disk than the last. This store writes deltas instead: one INSERT
|
|
6
|
+
// per message, one UPDATE per patch, and reads a thread once into the
|
|
7
|
+
// Store's in-memory cache. node:sqlite (built into Node ≥23.4) keeps it
|
|
8
|
+
// dependency-free — nothing new to bundle for the packaged app.
|
|
9
|
+
//
|
|
10
|
+
// Legacy JSON thread files import lazily: the first read of a thread with
|
|
11
|
+
// no rows pulls the old file in, after which the DB is the source of
|
|
12
|
+
// truth (the JSON file is left behind as a one-time backup).
|
|
13
|
+
import { chmodSync, closeSync, existsSync, openSync, readFileSync, renameSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { DatabaseSync } from "node:sqlite";
|
|
16
|
+
import { DATA_DIR } from "./config.js";
|
|
17
|
+
import { peerProvenanceAuthor } from "./peer-provenance.js";
|
|
18
|
+
const DB_FILE = () => join(DATA_DIR, "messages.db");
|
|
19
|
+
let handle = null;
|
|
20
|
+
let handlePath = null;
|
|
21
|
+
function open() {
|
|
22
|
+
const file = DB_FILE();
|
|
23
|
+
// Transcripts can contain private conversations and tool output. Create
|
|
24
|
+
// the database with owner-only permissions and also repair an existing
|
|
25
|
+
// file that may have inherited a permissive umask.
|
|
26
|
+
closeSync(openSync(file, "a", 0o600));
|
|
27
|
+
try {
|
|
28
|
+
chmodSync(file, 0o600);
|
|
29
|
+
}
|
|
30
|
+
catch { }
|
|
31
|
+
const db = new DatabaseSync(file);
|
|
32
|
+
db.exec("PRAGMA journal_mode = WAL");
|
|
33
|
+
db.exec("PRAGMA synchronous = NORMAL");
|
|
34
|
+
db.exec(`
|
|
35
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
36
|
+
thread_id TEXT NOT NULL,
|
|
37
|
+
id TEXT NOT NULL,
|
|
38
|
+
at INTEGER NOT NULL,
|
|
39
|
+
role TEXT NOT NULL,
|
|
40
|
+
kind TEXT NOT NULL,
|
|
41
|
+
text TEXT,
|
|
42
|
+
json TEXT NOT NULL,
|
|
43
|
+
PRIMARY KEY (thread_id, id)
|
|
44
|
+
);
|
|
45
|
+
CREATE INDEX IF NOT EXISTS messages_thread ON messages(thread_id);
|
|
46
|
+
CREATE TABLE IF NOT EXISTS thread_state (
|
|
47
|
+
thread_id TEXT PRIMARY KEY,
|
|
48
|
+
active_leaf_id TEXT
|
|
49
|
+
);
|
|
50
|
+
`);
|
|
51
|
+
ensureRecallIndex(db);
|
|
52
|
+
return db;
|
|
53
|
+
}
|
|
54
|
+
// Ranked recall over transcript text, for the bot's own session_search tool.
|
|
55
|
+
// An external-content FTS5 table over messages.text: the index stores no
|
|
56
|
+
// copy of the text, and three triggers keep it in step with every insert,
|
|
57
|
+
// update, and delete on `messages`. FTS5 ships inside node:sqlite, so this
|
|
58
|
+
// is no more of a dependency than the table it indexes. The sidebar's LIKE
|
|
59
|
+
// search below stays as it is — substring find over a single thread wants
|
|
60
|
+
// every occurrence, not a relevance ranking.
|
|
61
|
+
function ensureRecallIndex(db) {
|
|
62
|
+
const existed = db
|
|
63
|
+
.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'messages_fts'")
|
|
64
|
+
.get();
|
|
65
|
+
db.exec(`
|
|
66
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5(
|
|
67
|
+
text, content='messages', content_rowid='rowid', tokenize='unicode61'
|
|
68
|
+
);
|
|
69
|
+
CREATE TRIGGER IF NOT EXISTS messages_fts_ai AFTER INSERT ON messages BEGIN
|
|
70
|
+
INSERT INTO messages_fts(rowid, text) VALUES (new.rowid, new.text);
|
|
71
|
+
END;
|
|
72
|
+
CREATE TRIGGER IF NOT EXISTS messages_fts_ad AFTER DELETE ON messages BEGIN
|
|
73
|
+
INSERT INTO messages_fts(messages_fts, rowid, text) VALUES ('delete', old.rowid, old.text);
|
|
74
|
+
END;
|
|
75
|
+
CREATE TRIGGER IF NOT EXISTS messages_fts_au AFTER UPDATE ON messages BEGIN
|
|
76
|
+
INSERT INTO messages_fts(messages_fts, rowid, text) VALUES ('delete', old.rowid, old.text);
|
|
77
|
+
INSERT INTO messages_fts(rowid, text) VALUES (new.rowid, new.text);
|
|
78
|
+
END;
|
|
79
|
+
`);
|
|
80
|
+
// First time on an existing database: index everything already there.
|
|
81
|
+
if (!existed)
|
|
82
|
+
db.exec("INSERT INTO messages_fts(messages_fts) VALUES ('rebuild')");
|
|
83
|
+
}
|
|
84
|
+
// INSERT OR REPLACE would delete and re-insert the row under a new rowid
|
|
85
|
+
// without firing the delete trigger (SQLite only fires it with recursive
|
|
86
|
+
// triggers on), leaving a dangling FTS entry. An upsert keeps the rowid and
|
|
87
|
+
// runs the update trigger, so the index never drifts from the table.
|
|
88
|
+
const UPSERT_MESSAGE = "INSERT INTO messages (thread_id, id, at, role, kind, text, json) VALUES (?, ?, ?, ?, ?, ?, ?) " +
|
|
89
|
+
"ON CONFLICT(thread_id, id) DO UPDATE SET at = excluded.at, role = excluded.role, kind = excluded.kind, " +
|
|
90
|
+
"text = excluded.text, json = excluded.json";
|
|
91
|
+
/** The live handle — reopened when the file was removed out from under us
|
|
92
|
+
* (tests wipe DATA_DIR between cases; a fresh Store must get a fresh DB,
|
|
93
|
+
* not a handle onto an unlinked inode). */
|
|
94
|
+
function db() {
|
|
95
|
+
if (handle && handlePath === DB_FILE() && existsSync(DB_FILE()))
|
|
96
|
+
return handle;
|
|
97
|
+
try {
|
|
98
|
+
handle?.close();
|
|
99
|
+
}
|
|
100
|
+
catch { }
|
|
101
|
+
handle = open();
|
|
102
|
+
handlePath = DB_FILE();
|
|
103
|
+
return handle;
|
|
104
|
+
}
|
|
105
|
+
const rowToMessage = (row) => JSON.parse(row.json);
|
|
106
|
+
/** Read one thread, importing its legacy JSON file on first touch. */
|
|
107
|
+
export function readThread(threadId, legacyFile) {
|
|
108
|
+
const rows = db()
|
|
109
|
+
.prepare("SELECT json FROM messages WHERE thread_id = ? ORDER BY rowid")
|
|
110
|
+
.all(threadId);
|
|
111
|
+
if (rows.length) {
|
|
112
|
+
const state = db()
|
|
113
|
+
.prepare("SELECT active_leaf_id FROM thread_state WHERE thread_id = ?")
|
|
114
|
+
.get(threadId);
|
|
115
|
+
return { messages: rows.map(rowToMessage), activeLeafId: state?.active_leaf_id ?? null };
|
|
116
|
+
}
|
|
117
|
+
return importLegacy(threadId, legacyFile);
|
|
118
|
+
}
|
|
119
|
+
function importLegacy(threadId, legacyFile) {
|
|
120
|
+
let messages = [];
|
|
121
|
+
let activeLeafId = null;
|
|
122
|
+
let raw;
|
|
123
|
+
try {
|
|
124
|
+
raw = JSON.parse(readFileSync(legacyFile, "utf8"));
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return { messages, activeLeafId }; // fresh thread
|
|
128
|
+
}
|
|
129
|
+
if (Array.isArray(raw))
|
|
130
|
+
messages = raw; // pre-branching flat file
|
|
131
|
+
else if (raw && typeof raw === "object") {
|
|
132
|
+
messages = (raw.messages ?? []);
|
|
133
|
+
activeLeafId = raw.activeLeafId ?? null;
|
|
134
|
+
}
|
|
135
|
+
const insert = db().prepare(UPSERT_MESSAGE);
|
|
136
|
+
db().exec("BEGIN");
|
|
137
|
+
try {
|
|
138
|
+
for (const message of messages) {
|
|
139
|
+
insert.run(threadId, message.id, message.at, message.role, message.kind, message.text ?? null, JSON.stringify(message));
|
|
140
|
+
}
|
|
141
|
+
setActiveLeaf(threadId, activeLeafId);
|
|
142
|
+
db().exec("COMMIT");
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
db().exec("ROLLBACK");
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
// left beside the DB as a one-time backup, renamed so the import never
|
|
149
|
+
// runs twice against a thread whose rows were later deleted
|
|
150
|
+
try {
|
|
151
|
+
renameSync(legacyFile, `${legacyFile}.imported`);
|
|
152
|
+
try {
|
|
153
|
+
chmodSync(`${legacyFile}.imported`, 0o600);
|
|
154
|
+
}
|
|
155
|
+
catch { }
|
|
156
|
+
}
|
|
157
|
+
catch { }
|
|
158
|
+
return { messages, activeLeafId };
|
|
159
|
+
}
|
|
160
|
+
export function insertMessage(threadId, message) {
|
|
161
|
+
db()
|
|
162
|
+
.prepare(UPSERT_MESSAGE)
|
|
163
|
+
.run(threadId, message.id, message.at, message.role, message.kind, message.text ?? null, JSON.stringify(message));
|
|
164
|
+
}
|
|
165
|
+
/** A backup may only populate a fresh thread, never replace a transcript. */
|
|
166
|
+
export function importThread(threadId, messages, activeLeafId) {
|
|
167
|
+
const database = db();
|
|
168
|
+
database.exec("BEGIN IMMEDIATE");
|
|
169
|
+
try {
|
|
170
|
+
if (database.prepare("SELECT 1 FROM messages WHERE thread_id = ? LIMIT 1").get(threadId) ||
|
|
171
|
+
database.prepare("SELECT 1 FROM thread_state WHERE thread_id = ?").get(threadId)) {
|
|
172
|
+
throw new Error("Cannot import over an existing conversation");
|
|
173
|
+
}
|
|
174
|
+
for (const message of messages)
|
|
175
|
+
insertMessage(threadId, message);
|
|
176
|
+
setActiveLeaf(threadId, activeLeafId);
|
|
177
|
+
database.exec("COMMIT");
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
database.exec("ROLLBACK");
|
|
181
|
+
throw error;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/** Persist a new message and the branch head as one crash-safe mutation. */
|
|
185
|
+
export function appendMessage(threadId, message) {
|
|
186
|
+
const database = db();
|
|
187
|
+
database.exec("BEGIN IMMEDIATE");
|
|
188
|
+
try {
|
|
189
|
+
insertMessage(threadId, message);
|
|
190
|
+
setActiveLeaf(threadId, message.id);
|
|
191
|
+
database.exec("COMMIT");
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
database.exec("ROLLBACK");
|
|
195
|
+
throw error;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
export function updateMessage(threadId, message) {
|
|
199
|
+
db()
|
|
200
|
+
.prepare("UPDATE messages SET at = ?, role = ?, kind = ?, text = ?, json = ? WHERE thread_id = ? AND id = ?")
|
|
201
|
+
.run(message.at, message.role, message.kind, message.text ?? null, JSON.stringify(message), threadId, message.id);
|
|
202
|
+
}
|
|
203
|
+
/** Goal cards are new SQLite-backed messages, so crash recovery can locate
|
|
204
|
+
* the tiny set of unfinished receipts without eagerly loading every room
|
|
205
|
+
* transcript into memory at startup. */
|
|
206
|
+
export function workingGoalRunMessages() {
|
|
207
|
+
const rows = db()
|
|
208
|
+
.prepare("SELECT thread_id, json FROM messages " +
|
|
209
|
+
"WHERE kind = 'goal.run' AND json_extract(json, '$.goalRun.status') = 'working'")
|
|
210
|
+
.all();
|
|
211
|
+
return rows.map((row) => ({ threadId: row.thread_id, message: JSON.parse(row.json) }));
|
|
212
|
+
}
|
|
213
|
+
export function setActiveLeaf(threadId, leafId) {
|
|
214
|
+
db()
|
|
215
|
+
.prepare("INSERT INTO thread_state (thread_id, active_leaf_id) VALUES (?, ?) " +
|
|
216
|
+
"ON CONFLICT(thread_id) DO UPDATE SET active_leaf_id = excluded.active_leaf_id")
|
|
217
|
+
.run(threadId, leafId);
|
|
218
|
+
}
|
|
219
|
+
export function deleteThread(threadId) {
|
|
220
|
+
db().prepare("DELETE FROM messages WHERE thread_id = ?").run(threadId);
|
|
221
|
+
db().prepare("DELETE FROM thread_state WHERE thread_id = ?").run(threadId);
|
|
222
|
+
}
|
|
223
|
+
/** Case-insensitive substring search over text messages, newest first.
|
|
224
|
+
* A LIKE scan, deliberately: local transcripts are megabytes at most, a
|
|
225
|
+
* scan is milliseconds, and it needs no FTS extension to exist. */
|
|
226
|
+
export function searchMessages(query, limit = 40, threadId) {
|
|
227
|
+
const needle = query.trim().toLowerCase();
|
|
228
|
+
if (!needle)
|
|
229
|
+
return [];
|
|
230
|
+
// escape LIKE wildcards so a literal % or _ in the query stays literal
|
|
231
|
+
const pattern = `%${needle.replace(/([\\%_])/g, "\\$1")}%`;
|
|
232
|
+
// text messages by their text; activity chips by the tool name — "which
|
|
233
|
+
// bot ran that migration" is a tool-name question. The chip's name lives
|
|
234
|
+
// in the row's json; a JSON1 extract keeps this one query.
|
|
235
|
+
const scope = threadId ? "thread_id = ? AND " : "";
|
|
236
|
+
const statement = db().prepare("SELECT thread_id, id, at, role, kind, text, json_extract(json, '$.tool.name') AS tool_name, json_extract(json, '$.from.name') AS from_name FROM messages " +
|
|
237
|
+
`WHERE ${scope}((kind = 'text' AND text IS NOT NULL AND lower(text) LIKE ? ESCAPE '\\') ` +
|
|
238
|
+
" OR (kind = 'activity' AND tool_name IS NOT NULL AND lower(tool_name) LIKE ? ESCAPE '\\')) " +
|
|
239
|
+
"ORDER BY at DESC LIMIT ?");
|
|
240
|
+
const rows = (threadId
|
|
241
|
+
? statement.all(threadId, pattern, pattern, limit)
|
|
242
|
+
: statement.all(pattern, pattern, limit));
|
|
243
|
+
return rows.map((row) => {
|
|
244
|
+
const haystack = row.kind === "activity" ? (row.tool_name ?? "") : (row.text ?? "");
|
|
245
|
+
const hitAt = Math.max(0, haystack.toLowerCase().indexOf(needle));
|
|
246
|
+
const start = Math.max(0, hitAt - 60);
|
|
247
|
+
const end = Math.min(haystack.length, hitAt + needle.length + 90);
|
|
248
|
+
const head = start > 0 ? "…" : "";
|
|
249
|
+
const body = haystack.slice(start, end).replace(/\s+/g, " ").trim();
|
|
250
|
+
const snippet = head + body + (end < haystack.length ? "…" : "");
|
|
251
|
+
// whitespace folding can shift the offset; find the match again inside
|
|
252
|
+
const folded = needle.replace(/\s+/g, " ");
|
|
253
|
+
const matchStart = snippet.toLowerCase().indexOf(folded);
|
|
254
|
+
return {
|
|
255
|
+
threadId: row.thread_id,
|
|
256
|
+
messageId: row.id,
|
|
257
|
+
at: row.at,
|
|
258
|
+
role: row.role,
|
|
259
|
+
kind: row.kind,
|
|
260
|
+
snippet,
|
|
261
|
+
matchStart: matchStart < 0 ? head.length : matchStart,
|
|
262
|
+
// A defensive fallback must not mark arbitrary snippet text as the hit.
|
|
263
|
+
matchLength: matchStart < 0 ? 0 : folded.length,
|
|
264
|
+
...(row.from_name ? { from: row.from_name } : {}),
|
|
265
|
+
};
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
/** Who wrote a user-role line that reads as the user's. The structural
|
|
269
|
+
* field wins; rows stored before it existed still open with the note. */
|
|
270
|
+
function peerAuthor(peerName, text) {
|
|
271
|
+
return peerName ?? peerProvenanceAuthor(text);
|
|
272
|
+
}
|
|
273
|
+
/** Enough of a line to see whether it opens with an ask_bot note — the
|
|
274
|
+
* note's fixed wording plus a bot name — without reading the whole text. */
|
|
275
|
+
const PEER_NOTE_HEAD_CHARS = 160;
|
|
276
|
+
// Every query token must match, so a function word the model happened to
|
|
277
|
+
// include ("archive reference on") turns a good query into a miss. Drop
|
|
278
|
+
// the common ones; if that empties the query, search for what was sent.
|
|
279
|
+
const STOP_WORDS = new Set("a an and are as at be by did do for from had has have how i in is it its of on or that the this to was we were what when where which who why with you your".split(" "));
|
|
280
|
+
/** Turn free text into an FTS5 query that cannot be misparsed: every
|
|
281
|
+
* whitespace-separated token becomes a quoted string, so `AND`, `NOT`,
|
|
282
|
+
* `*`, `:`, and stray quotes are searched for rather than interpreted.
|
|
283
|
+
* Tokens are ANDed — FTS5's default — so a hit contains all of them. */
|
|
284
|
+
function ftsQuery(query) {
|
|
285
|
+
const tokens = query
|
|
286
|
+
.split(/\s+/)
|
|
287
|
+
.map((token) => token.replace(/"/g, "").trim())
|
|
288
|
+
.filter(Boolean);
|
|
289
|
+
if (!tokens.length)
|
|
290
|
+
return null;
|
|
291
|
+
const content = tokens.filter((token) => !STOP_WORDS.has(token.toLowerCase()));
|
|
292
|
+
return (content.length ? content : tokens).map((token) => `"${token}"`).join(" ");
|
|
293
|
+
}
|
|
294
|
+
/** How much of a matched message rides back in a hit. Wide enough that a
|
|
295
|
+
* short report reads whole; a longer one is fetched with readMessageText. */
|
|
296
|
+
const SNIPPET_TOKENS = 48;
|
|
297
|
+
/** Full text of one text message, for a session_read after a search hit.
|
|
298
|
+
* Null for a missing row or a non-text kind (activity chips carry no
|
|
299
|
+
* transcript text). */
|
|
300
|
+
export function readMessageText(threadId, messageId) {
|
|
301
|
+
const row = db()
|
|
302
|
+
.prepare("SELECT at, role, text, json_extract(json, '$.from.name') AS from_name, " +
|
|
303
|
+
"json_extract(json, '$.peerAsk.name') AS peer_name FROM messages " +
|
|
304
|
+
"WHERE thread_id = ? AND id = ? AND kind = 'text' AND text IS NOT NULL")
|
|
305
|
+
.get(threadId, messageId);
|
|
306
|
+
if (!row)
|
|
307
|
+
return null;
|
|
308
|
+
const peer = peerAuthor(row.peer_name, row.text);
|
|
309
|
+
return {
|
|
310
|
+
threadId,
|
|
311
|
+
messageId,
|
|
312
|
+
at: row.at,
|
|
313
|
+
role: row.role,
|
|
314
|
+
text: row.text,
|
|
315
|
+
...(row.from_name ? { from: row.from_name } : {}),
|
|
316
|
+
...(peer ? { peer } : {}),
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
/** Relevance-ranked recall over the text messages of the given threads:
|
|
320
|
+
* the bot's own past conversations, best match first, not newest first.
|
|
321
|
+
* bm25 rank from FTS5; the snippet is FTS5's own, windowed around the
|
|
322
|
+
* matched terms. Scoping happens in SQL before LIMIT, so a busy thread
|
|
323
|
+
* cannot crowd out a quieter one. */
|
|
324
|
+
export function recallMessages(query, threadIds, limit = 12) {
|
|
325
|
+
const match = ftsQuery(query);
|
|
326
|
+
if (!match || !threadIds.length)
|
|
327
|
+
return [];
|
|
328
|
+
const placeholders = threadIds.map(() => "?").join(", ");
|
|
329
|
+
const rows = db()
|
|
330
|
+
.prepare("SELECT m.thread_id, m.id, m.at, m.role, json_extract(m.json, '$.from.name') AS from_name, " +
|
|
331
|
+
`json_extract(m.json, '$.peerAsk.name') AS peer_name, substr(m.text, 1, ${PEER_NOTE_HEAD_CHARS}) AS head, ` +
|
|
332
|
+
`snippet(messages_fts, 0, '[', ']', '…', ${SNIPPET_TOKENS}) AS snippet ` +
|
|
333
|
+
"FROM messages_fts JOIN messages m ON m.rowid = messages_fts.rowid " +
|
|
334
|
+
`WHERE messages_fts MATCH ? AND m.kind = 'text' AND m.thread_id IN (${placeholders}) ` +
|
|
335
|
+
"ORDER BY bm25(messages_fts), m.at DESC LIMIT ?")
|
|
336
|
+
.all(match, ...threadIds, limit);
|
|
337
|
+
return rows.map((row) => {
|
|
338
|
+
const peer = peerAuthor(row.peer_name, row.head);
|
|
339
|
+
return {
|
|
340
|
+
threadId: row.thread_id,
|
|
341
|
+
messageId: row.id,
|
|
342
|
+
at: row.at,
|
|
343
|
+
role: row.role,
|
|
344
|
+
snippet: row.snippet.replace(/\s+/g, " ").trim(),
|
|
345
|
+
...(row.from_name ? { from: row.from_name } : {}),
|
|
346
|
+
...(peer ? { peer } : {}),
|
|
347
|
+
};
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
/** Test/shutdown hook — closes the handle so a wiped DATA_DIR starts clean. */
|
|
351
|
+
export function closeMessageDb() {
|
|
352
|
+
try {
|
|
353
|
+
handle?.close();
|
|
354
|
+
}
|
|
355
|
+
catch { }
|
|
356
|
+
handle = null;
|
|
357
|
+
handlePath = null;
|
|
358
|
+
}
|