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.
Files changed (499) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +14 -0
  3. package/cli.js +2 -0
  4. package/dist/app-icon.svg +29 -0
  5. package/dist/assets/abap-BdImnpbu.js +1 -0
  6. package/dist/assets/actionscript-3-B3316cI-.js +1 -0
  7. package/dist/assets/ada-bCR0ucgS.js +1 -0
  8. package/dist/assets/ahk-CsyLZFj1.js +1 -0
  9. package/dist/assets/ahk2-8Zs4aa1G.js +1 -0
  10. package/dist/assets/andromeeda-C4gqWexZ.js +1 -0
  11. package/dist/assets/angular-html-DA-rfuFy.js +1 -0
  12. package/dist/assets/angular-ts-BrjP3tb8.js +1 -0
  13. package/dist/assets/apache-Pmp26Uib.js +1 -0
  14. package/dist/assets/apex-DhZFqWV2.js +1 -0
  15. package/dist/assets/apl-CORt7UWP.js +1 -0
  16. package/dist/assets/applescript-Co6uUVPk.js +1 -0
  17. package/dist/assets/ara-BRHolxvo.js +1 -0
  18. package/dist/assets/asciidoc-CSVQ5wI8.js +1 -0
  19. package/dist/assets/asm-D_Q5rh1f.js +1 -0
  20. package/dist/assets/astro-HNnZUWAn.js +1 -0
  21. package/dist/assets/aurora-x-D-2ljcwZ.js +1 -0
  22. package/dist/assets/awk-DMzUqQB5.js +1 -0
  23. package/dist/assets/ayu-dark-DYE7WIF3.js +1 -0
  24. package/dist/assets/ayu-light-BA47KaF1.js +1 -0
  25. package/dist/assets/ayu-mirage-32ctXXKs.js +1 -0
  26. package/dist/assets/ballerina-BFfxhgS-.js +1 -0
  27. package/dist/assets/bat-CickPsom.js +1 -0
  28. package/dist/assets/beancount-k_qm7-4y.js +1 -0
  29. package/dist/assets/berry-uYugtg8r.js +1 -0
  30. package/dist/assets/bibtex-CHM0blh-.js +1 -0
  31. package/dist/assets/bicep-Bmn6On1c.js +1 -0
  32. package/dist/assets/bird2-Bx8U0n9b.js +1 -0
  33. package/dist/assets/blade-2xfisSek.js +1 -0
  34. package/dist/assets/bsl-DlhNcFeZ.js +1 -0
  35. package/dist/assets/c-BIGW1oBm.js +1 -0
  36. package/dist/assets/c3-Dp5svz6Z.js +1 -0
  37. package/dist/assets/cadence-Bv_4Rxtq.js +1 -0
  38. package/dist/assets/cairo-KRGpt6FW.js +1 -0
  39. package/dist/assets/catppuccin-frappe-CZL1YF0i.js +1 -0
  40. package/dist/assets/catppuccin-latte-DH-8KZSZ.js +1 -0
  41. package/dist/assets/catppuccin-macchiato-B7yYVSCf.js +1 -0
  42. package/dist/assets/catppuccin-mocha-Ct7hS0mc.js +1 -0
  43. package/dist/assets/chapel-DTp_pixX.js +1 -0
  44. package/dist/assets/clarity-Dn5IMItf.js +1 -0
  45. package/dist/assets/clojure-P80f7IUj.js +1 -0
  46. package/dist/assets/cmake-D1j8_8rp.js +1 -0
  47. package/dist/assets/cobol-nBiQ_Alo.js +1 -0
  48. package/dist/assets/codeowners-Bp6g37R7.js +1 -0
  49. package/dist/assets/codeql-DsOJ9woJ.js +1 -0
  50. package/dist/assets/coffee-Ch7k5sss.js +1 -0
  51. package/dist/assets/common-lisp-Cg-RD9OK.js +1 -0
  52. package/dist/assets/coq-C7JzOVbR.js +1 -0
  53. package/dist/assets/cpp-BMRokrvK.js +1 -0
  54. package/dist/assets/crystal-DGywbUpC.js +1 -0
  55. package/dist/assets/csharp-DSvCPggb.js +1 -0
  56. package/dist/assets/css-CLj8gQPS.js +1 -0
  57. package/dist/assets/csv-fuZLfV_i.js +1 -0
  58. package/dist/assets/cue-D82EKSYY.js +1 -0
  59. package/dist/assets/cypher-COkxafJQ.js +1 -0
  60. package/dist/assets/d-85-TOEBH.js +1 -0
  61. package/dist/assets/dark-plus-C3mMm8J8.js +1 -0
  62. package/dist/assets/dart-bE4Kk8sk.js +1 -0
  63. package/dist/assets/dax-CEL-wOlO.js +1 -0
  64. package/dist/assets/desktop-BmXAJ9_W.js +1 -0
  65. package/dist/assets/diff-D97Zzqfu.js +1 -0
  66. package/dist/assets/docker-BcOcwvcX.js +1 -0
  67. package/dist/assets/dotenv-Da5cRb03.js +1 -0
  68. package/dist/assets/dracula-BzJJZx-M.js +1 -0
  69. package/dist/assets/dracula-soft-BXkSAIEj.js +1 -0
  70. package/dist/assets/dream-maker-BtqSS_iP.js +1 -0
  71. package/dist/assets/edge-FbVlp4U3.js +1 -0
  72. package/dist/assets/elixir-CkH2-t6x.js +1 -0
  73. package/dist/assets/elm-DbKCFpqz.js +1 -0
  74. package/dist/assets/emacs-lisp-C_m_b--Z.js +1 -0
  75. package/dist/assets/erb-DXfck5VN.js +1 -0
  76. package/dist/assets/erlang-DsQrWhSR.js +1 -0
  77. package/dist/assets/everforest-dark-BgDCqdQA.js +1 -0
  78. package/dist/assets/everforest-light-C8M2exoo.js +1 -0
  79. package/dist/assets/fennel-BYunw83y.js +1 -0
  80. package/dist/assets/fish-BvzEVeQv.js +1 -0
  81. package/dist/assets/fluent-C4IJs8-o.js +1 -0
  82. package/dist/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
  83. package/dist/assets/fortran-free-form-BxgE0vQu.js +1 -0
  84. package/dist/assets/fsharp-CXgrBDvD.js +1 -0
  85. package/dist/assets/gdresource-TyuKm33G.js +1 -0
  86. package/dist/assets/gdscript-DqcFQ5yU.js +1 -0
  87. package/dist/assets/gdshader-DkwncUOv.js +1 -0
  88. package/dist/assets/genie-D0YGMca9.js +1 -0
  89. package/dist/assets/gherkin-DyxjwDmM.js +1 -0
  90. package/dist/assets/git-commit-F4YmCXRG.js +1 -0
  91. package/dist/assets/git-rebase-r7XF79zn.js +1 -0
  92. package/dist/assets/github-dark-DHJKELXO.js +1 -0
  93. package/dist/assets/github-dark-default-Cuk6v7N8.js +1 -0
  94. package/dist/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  95. package/dist/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  96. package/dist/assets/github-light-DAi9KRSo.js +1 -0
  97. package/dist/assets/github-light-default-D7oLnXFd.js +1 -0
  98. package/dist/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  99. package/dist/assets/gleam-BspZqrRM.js +1 -0
  100. package/dist/assets/glimmer-js-ByusRIyA.js +1 -0
  101. package/dist/assets/glimmer-ts-BfAWNZQY.js +1 -0
  102. package/dist/assets/glsl-DplSGwfg.js +1 -0
  103. package/dist/assets/gn-n2N0HUVH.js +1 -0
  104. package/dist/assets/gnuplot-DdkO51Og.js +1 -0
  105. package/dist/assets/go-C27-OAKa.js +1 -0
  106. package/dist/assets/graphql-ChdNCCLP.js +1 -0
  107. package/dist/assets/groovy-gcz8RCvz.js +1 -0
  108. package/dist/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  109. package/dist/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  110. package/dist/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  111. package/dist/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  112. package/dist/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  113. package/dist/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  114. package/dist/assets/hack-BWmVpMyf.js +1 -0
  115. package/dist/assets/haml-D5jkg6IW.js +1 -0
  116. package/dist/assets/handlebars-BpdQsYii.js +1 -0
  117. package/dist/assets/haskell-Df6bDoY_.js +1 -0
  118. package/dist/assets/haxe-CfZj7gIn.js +1 -0
  119. package/dist/assets/hcl-BWvSN4gD.js +1 -0
  120. package/dist/assets/hjson-D5-asLiD.js +1 -0
  121. package/dist/assets/hlsl-D3lLCCz7.js +1 -0
  122. package/dist/assets/horizon-BUw7H-hv.js +1 -0
  123. package/dist/assets/horizon-bright-CUuTKBJd.js +1 -0
  124. package/dist/assets/houston-DnULxvSX.js +1 -0
  125. package/dist/assets/html-derivative-DlHx6ybY.js +1 -0
  126. package/dist/assets/html-pp8916En.js +1 -0
  127. package/dist/assets/http-jrhK8wxY.js +1 -0
  128. package/dist/assets/hurl-irOxFIW8.js +1 -0
  129. package/dist/assets/hxml-2-FPmUDs.js +1 -0
  130. package/dist/assets/hy-DFXneXwc.js +1 -0
  131. package/dist/assets/imba-DGztddWO.js +1 -0
  132. package/dist/assets/index-B9rLIY81.js +263 -0
  133. package/dist/assets/index-CJBrtDbC.css +1 -0
  134. package/dist/assets/index-D-u0LYsV.js +153 -0
  135. package/dist/assets/ini-BEwlwnbL.js +1 -0
  136. package/dist/assets/java-CylS5w8V.js +1 -0
  137. package/dist/assets/javascript-wDzz0qaB.js +1 -0
  138. package/dist/assets/jinja-f2NsQr07.js +1 -0
  139. package/dist/assets/jison-wvAkD_A8.js +1 -0
  140. package/dist/assets/json-Cp-IABpG.js +1 -0
  141. package/dist/assets/json5-C9tS-k6U.js +1 -0
  142. package/dist/assets/jsonc-Des-eS-w.js +1 -0
  143. package/dist/assets/jsonl-DcaNXYhu.js +1 -0
  144. package/dist/assets/jsonnet-DFQXde-d.js +1 -0
  145. package/dist/assets/jssm-C2t-YnRu.js +1 -0
  146. package/dist/assets/jsx-g9-lgVsj.js +1 -0
  147. package/dist/assets/julia-5Bft2YPA.js +1 -0
  148. package/dist/assets/just-Cwhn7H3k.js +1 -0
  149. package/dist/assets/kanagawa-dragon-BuwD2xS4.js +1 -0
  150. package/dist/assets/kanagawa-lotus-C3DzagqV.js +1 -0
  151. package/dist/assets/kanagawa-wave-DFGoQZhC.js +1 -0
  152. package/dist/assets/kdl-DV7GczEv.js +1 -0
  153. package/dist/assets/kotlin-BdnUsdx6.js +1 -0
  154. package/dist/assets/kusto-wEQ09or8.js +1 -0
  155. package/dist/assets/laserwave-DUszq2jm.js +1 -0
  156. package/dist/assets/latex-D5pSuvFb.js +1 -0
  157. package/dist/assets/lean-BZvkOJ9d.js +1 -0
  158. package/dist/assets/less-B1dDrJ26.js +1 -0
  159. package/dist/assets/light-plus-B7mTdjB0.js +1 -0
  160. package/dist/assets/liquid-C0sCDyMI.js +1 -0
  161. package/dist/assets/llvm-BZoOZj88.js +1 -0
  162. package/dist/assets/log-2UxHyX5q.js +1 -0
  163. package/dist/assets/logo-BtOb2qkB.js +1 -0
  164. package/dist/assets/lua-BaeVxFsk.js +1 -0
  165. package/dist/assets/luau-BnpPk5vE.js +1 -0
  166. package/dist/assets/make-CHLpvVh8.js +1 -0
  167. package/dist/assets/markdown-Cvjx9yec.js +1 -0
  168. package/dist/assets/marko-DjSrsDqO.js +1 -0
  169. package/dist/assets/material-theme-D5KoaKCx.js +1 -0
  170. package/dist/assets/material-theme-darker-BfHTSMKl.js +1 -0
  171. package/dist/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  172. package/dist/assets/material-theme-ocean-CyktbL80.js +1 -0
  173. package/dist/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  174. package/dist/assets/matlab-D7o27uSR.js +1 -0
  175. package/dist/assets/mdc-D1_yUvq7.js +1 -0
  176. package/dist/assets/mdx-Cmh6b_Ma.js +1 -0
  177. package/dist/assets/mermaid-CQcHuHx7.js +1 -0
  178. package/dist/assets/min-dark-CafNBF8u.js +1 -0
  179. package/dist/assets/min-light-CTRr51gU.js +1 -0
  180. package/dist/assets/mipsasm-CKIfxQSi.js +1 -0
  181. package/dist/assets/mojo-DJz3ZmWd.js +1 -0
  182. package/dist/assets/monokai-BRVnQi9A.js +1 -0
  183. package/dist/assets/moonbit-CHtswR0a.js +1 -0
  184. package/dist/assets/move-el3G9tDJ.js +1 -0
  185. package/dist/assets/narrat-DRg8JJMk.js +1 -0
  186. package/dist/assets/nextflow-C-mBbutL.js +1 -0
  187. package/dist/assets/nextflow-groovy-vE_lwT2v.js +1 -0
  188. package/dist/assets/nginx-BpAMiNFr.js +1 -0
  189. package/dist/assets/night-owl-C39BiMTA.js +1 -0
  190. package/dist/assets/night-owl-light-CMTm3GFP.js +1 -0
  191. package/dist/assets/nim-BIad80T-.js +1 -0
  192. package/dist/assets/nix-CwoSXNpI.js +1 -0
  193. package/dist/assets/nord-Ddv68eIx.js +1 -0
  194. package/dist/assets/nsis-BlV79W_Q.js +1 -0
  195. package/dist/assets/nushell-D3jzshHO.js +1 -0
  196. package/dist/assets/objective-c-DXmwc3jG.js +1 -0
  197. package/dist/assets/objective-cpp-CLxacb5B.js +1 -0
  198. package/dist/assets/ocaml-C0hk2d4L.js +1 -0
  199. package/dist/assets/odin-BBf5iR-q.js +1 -0
  200. package/dist/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  201. package/dist/assets/one-light-C3Wv6jpd.js +1 -0
  202. package/dist/assets/openscad-C4EeE6gA.js +1 -0
  203. package/dist/assets/org-DM6o9KBp.js +1 -0
  204. package/dist/assets/pascal-D93ZcfNL.js +1 -0
  205. package/dist/assets/perl-B9cMNwum.js +1 -0
  206. package/dist/assets/php-Csjmro_R.js +1 -0
  207. package/dist/assets/pkl-u5AG7uiY.js +1 -0
  208. package/dist/assets/plastic-3e1v2bzS.js +1 -0
  209. package/dist/assets/plsql-ChMvpjG-.js +1 -0
  210. package/dist/assets/po-BTJTHyun.js +1 -0
  211. package/dist/assets/poimandres-CS3Unz2-.js +1 -0
  212. package/dist/assets/polar-C0HS_06l.js +1 -0
  213. package/dist/assets/postcss-CXtECtnM.js +1 -0
  214. package/dist/assets/powerquery-CEu0bR-o.js +1 -0
  215. package/dist/assets/powershell-BmBUJMz7.js +1 -0
  216. package/dist/assets/prisma-Vru482bI.js +1 -0
  217. package/dist/assets/prolog-CbFg5uaA.js +1 -0
  218. package/dist/assets/proto-C7zT0LnQ.js +1 -0
  219. package/dist/assets/pug-DKIMFp6K.js +1 -0
  220. package/dist/assets/puppet-BMWR74SV.js +1 -0
  221. package/dist/assets/purescript-CklMAg4u.js +1 -0
  222. package/dist/assets/python-B6aJPvgy.js +1 -0
  223. package/dist/assets/qml-3beO22l8.js +1 -0
  224. package/dist/assets/qmldir-C8lEn-DE.js +1 -0
  225. package/dist/assets/qss-IeuSbFQv.js +1 -0
  226. package/dist/assets/r-Cf5RLm7j.js +1 -0
  227. package/dist/assets/racket-BqYA7rlc.js +1 -0
  228. package/dist/assets/raku-DXvB9xmW.js +1 -0
  229. package/dist/assets/razor-BjBPvh-w.js +1 -0
  230. package/dist/assets/rbs-CpoqiR4B.js +1 -0
  231. package/dist/assets/red-hvxz__6c.js +1 -0
  232. package/dist/assets/reg-C-SQnVFl.js +1 -0
  233. package/dist/assets/regexp-CDVJQ6XC.js +1 -0
  234. package/dist/assets/rel-C3B-1QV4.js +1 -0
  235. package/dist/assets/riscv-BM1_JUlF.js +1 -0
  236. package/dist/assets/ron-D8l8udqQ.js +1 -0
  237. package/dist/assets/rose-pine-5qJOZa0Y.js +1 -0
  238. package/dist/assets/rose-pine-dawn-zx0QlTCp.js +1 -0
  239. package/dist/assets/rose-pine-moon-C9pEdX9L.js +1 -0
  240. package/dist/assets/rosmsg-BJDFO7_C.js +1 -0
  241. package/dist/assets/rst-bs7f0vWN.js +1 -0
  242. package/dist/assets/ruby-C0TQ7zu5.js +1 -0
  243. package/dist/assets/rust-B1yitclQ.js +1 -0
  244. package/dist/assets/sas-DEy46yEz.js +1 -0
  245. package/dist/assets/sass-Cj5Yp3dK.js +1 -0
  246. package/dist/assets/scala-CqE71os6.js +1 -0
  247. package/dist/assets/scheme-C98Dy4si.js +1 -0
  248. package/dist/assets/scss-D5BDwBP9.js +1 -0
  249. package/dist/assets/sdbl-DVxCFoDh.js +1 -0
  250. package/dist/assets/shaderlab-Dg9Lc6iA.js +1 -0
  251. package/dist/assets/shellscript-Yzrsuije.js +1 -0
  252. package/dist/assets/shellsession-BADoaaVG.js +1 -0
  253. package/dist/assets/slack-dark-BthQWCQV.js +1 -0
  254. package/dist/assets/slack-ochin-DqwNpetd.js +1 -0
  255. package/dist/assets/smalltalk-BOQMe2GC.js +1 -0
  256. package/dist/assets/smithy-cds9vsN8.js +1 -0
  257. package/dist/assets/snazzy-light-Bw305WKR.js +1 -0
  258. package/dist/assets/solarized-dark-CpvCGNkr.js +1 -0
  259. package/dist/assets/solarized-light-Dlz6yCKv.js +1 -0
  260. package/dist/assets/solidity-DijEV5ha.js +1 -0
  261. package/dist/assets/soy-8wufbnw4.js +1 -0
  262. package/dist/assets/sparql-rVzFXLq3.js +1 -0
  263. package/dist/assets/splunk-BtCnVYZw.js +1 -0
  264. package/dist/assets/sql-CRqJ_cUM.js +1 -0
  265. package/dist/assets/ssh-config-_ykCGR6B.js +1 -0
  266. package/dist/assets/stata-DI20mbqo.js +1 -0
  267. package/dist/assets/stylus-BEDo0Tqx.js +1 -0
  268. package/dist/assets/surrealql-Cjom0U5J.js +1 -0
  269. package/dist/assets/svelte-Cy7k_4gC.js +1 -0
  270. package/dist/assets/swift-C2oV4EkX.js +1 -0
  271. package/dist/assets/synthwave-84-CbfX1IO0.js +1 -0
  272. package/dist/assets/system-verilog-0hqHdDBg.js +1 -0
  273. package/dist/assets/systemd-4A_iFExJ.js +1 -0
  274. package/dist/assets/talonscript-CkByrt1z.js +1 -0
  275. package/dist/assets/tasl-QIJgUcNo.js +1 -0
  276. package/dist/assets/tcl-dwOrl1Do.js +1 -0
  277. package/dist/assets/templ-DhtptRzy.js +1 -0
  278. package/dist/assets/terraform-BETggiCN.js +1 -0
  279. package/dist/assets/tex-D96PA37w.js +1 -0
  280. package/dist/assets/tokyo-night-hegEt444.js +1 -0
  281. package/dist/assets/toml-vGWfd6FD.js +1 -0
  282. package/dist/assets/ts-tags-D351s5mN.js +1 -0
  283. package/dist/assets/tsv-B_m7g4N7.js +1 -0
  284. package/dist/assets/tsx-COt5Ahok.js +1 -0
  285. package/dist/assets/turtle-BsS91CYL.js +1 -0
  286. package/dist/assets/twig-27uCiNez.js +1 -0
  287. package/dist/assets/typescript-BPQ3VLAy.js +1 -0
  288. package/dist/assets/typespec-CAFt9gP4.js +1 -0
  289. package/dist/assets/typst-BUadGCkm.js +1 -0
  290. package/dist/assets/v-BGw2Nkan.js +1 -0
  291. package/dist/assets/vala-CsfeWuGM.js +1 -0
  292. package/dist/assets/vb-Cu-pLBUe.js +1 -0
  293. package/dist/assets/verilog-nZwndyjY.js +1 -0
  294. package/dist/assets/vesper-DRje8inN.js +1 -0
  295. package/dist/assets/vhdl-CeAyd5Ju.js +1 -0
  296. package/dist/assets/viml-CJc9bBzg.js +1 -0
  297. package/dist/assets/vitesse-black-Bkuqu6BP.js +1 -0
  298. package/dist/assets/vitesse-dark-D0r3Knsf.js +1 -0
  299. package/dist/assets/vitesse-light-CVO1_9PV.js +1 -0
  300. package/dist/assets/vue-BqiEGhQt.js +1 -0
  301. package/dist/assets/vue-html-AaS7Mt5G.js +1 -0
  302. package/dist/assets/vue-vine-BoDAl6tE.js +1 -0
  303. package/dist/assets/vyper-CDx5xZoG.js +1 -0
  304. package/dist/assets/wasm-CG6Dc4jp.js +1 -0
  305. package/dist/assets/wasm-MzD3tlZU.js +1 -0
  306. package/dist/assets/wenyan-BV7otONQ.js +1 -0
  307. package/dist/assets/wgsl-Dx-B1_4e.js +1 -0
  308. package/dist/assets/wikitext-BhOHFoWU.js +1 -0
  309. package/dist/assets/wit-5i3qLPDT.js +1 -0
  310. package/dist/assets/wolfram-lXgVvXCa.js +1 -0
  311. package/dist/assets/xml-sdJ4AIDG.js +1 -0
  312. package/dist/assets/xsl-CtQFsRM5.js +1 -0
  313. package/dist/assets/yaml-Buea-lGh.js +1 -0
  314. package/dist/assets/zenscript-DVFEvuxE.js +1 -0
  315. package/dist/assets/zig-VOosw3JB.js +1 -0
  316. package/dist/index.html +14 -0
  317. package/dist-server/companion/src/listener.js +187 -0
  318. package/dist-server/computer-proxy.js +1185 -0
  319. package/dist-server/connector-proxy.js +186 -0
  320. package/dist-server/container-mcp.js +15186 -0
  321. package/dist-server/drivers/agents-proxy.js +887 -0
  322. package/dist-server/drivers/browser-proxy.js +15037 -0
  323. package/dist-server/drivers/dweb-proxy.js +175 -0
  324. package/dist-server/drivers/phone-proxy.js +339 -0
  325. package/dist-server/drivers/pi-mcp-extension.ts +638 -0
  326. package/dist-server/index.js +64869 -0
  327. package/dist-server/local-computer.js +198 -0
  328. package/dist-server/mcp-server.js +1233 -0
  329. package/dist-server/openmausbot.js +3671 -0
  330. package/dist-server/pair-cli.js +3671 -0
  331. package/dist-server/permission-proxy.js +126 -0
  332. package/dist-server/prepare-cloudflared.js +253 -0
  333. package/dist-server/proxy-paths.js +29 -0
  334. package/dist-server/server/atomic.js +40 -0
  335. package/dist-server/server/attachments.js +471 -0
  336. package/dist-server/server/auto-approve.js +162 -0
  337. package/dist-server/server/auto-review.js +79 -0
  338. package/dist-server/server/avatar-image.js +144 -0
  339. package/dist-server/server/bot-cwd.js +29 -0
  340. package/dist-server/server/bot-directory.js +127 -0
  341. package/dist-server/server/bot-package.js +268 -0
  342. package/dist-server/server/bot-profile.js +76 -0
  343. package/dist-server/server/box-create-idempotency.js +463 -0
  344. package/dist-server/server/box.js +944 -0
  345. package/dist-server/server/brand.js +65 -0
  346. package/dist-server/server/browser-connection.js +187 -0
  347. package/dist-server/server/browser-lifecycle-cleanup.js +359 -0
  348. package/dist-server/server/calendar-calls.js +314 -0
  349. package/dist-server/server/channel-queue.js +70 -0
  350. package/dist-server/server/checkpoints.js +405 -0
  351. package/dist-server/server/chief-of-staff.js +49 -0
  352. package/dist-server/server/claude-update.js +70 -0
  353. package/dist-server/server/cli.js +524 -0
  354. package/dist-server/server/cloud-backend.js +30 -0
  355. package/dist-server/server/comms-visibility.js +109 -0
  356. package/dist-server/server/composio.js +945 -0
  357. package/dist-server/server/computer-control.js +149 -0
  358. package/dist-server/server/computer-observation.js +133 -0
  359. package/dist-server/server/computer-proxy.js +1061 -0
  360. package/dist-server/server/config.js +760 -0
  361. package/dist-server/server/connector-proxy.js +228 -0
  362. package/dist-server/server/container-computer.js +840 -0
  363. package/dist-server/server/container-mcp.js +27 -0
  364. package/dist-server/server/contracts.js +24 -0
  365. package/dist-server/server/control-client.js +100 -0
  366. package/dist-server/server/data-dir-lease.js +3 -0
  367. package/dist-server/server/decision-log.js +106 -0
  368. package/dist-server/server/delegations.js +628 -0
  369. package/dist-server/server/drivers/acp/core.js +904 -0
  370. package/dist-server/server/drivers/acp/cursor.js +365 -0
  371. package/dist-server/server/drivers/acp/custom.js +51 -0
  372. package/dist-server/server/drivers/acp/droid.js +225 -0
  373. package/dist-server/server/drivers/acp/gemini.js +95 -0
  374. package/dist-server/server/drivers/acp/grok.js +249 -0
  375. package/dist-server/server/drivers/acp/hermes.js +429 -0
  376. package/dist-server/server/drivers/acp/kimi.js +559 -0
  377. package/dist-server/server/drivers/acp/opencode-go.js +370 -0
  378. package/dist-server/server/drivers/acp/qwen.js +98 -0
  379. package/dist-server/server/drivers/agents-proxy.js +941 -0
  380. package/dist-server/server/drivers/antigravity-acp.js +507 -0
  381. package/dist-server/server/drivers/antigravity-release.js +65 -0
  382. package/dist-server/server/drivers/antigravity-runtime.js +395 -0
  383. package/dist-server/server/drivers/antigravity.js +144 -0
  384. package/dist-server/server/drivers/boxagent.js +245 -0
  385. package/dist-server/server/drivers/browser-proxy.js +520 -0
  386. package/dist-server/server/drivers/builtIn.js +36 -0
  387. package/dist-server/server/drivers/claude.js +1337 -0
  388. package/dist-server/server/drivers/codex-catalog.js +409 -0
  389. package/dist-server/server/drivers/codex.js +1116 -0
  390. package/dist-server/server/drivers/dweb-proxy.js +193 -0
  391. package/dist-server/server/drivers/grok.js +48 -0
  392. package/dist-server/server/drivers/grokagent.js +4 -0
  393. package/dist-server/server/drivers/local-inject.js +388 -0
  394. package/dist-server/server/drivers/minimax.js +108 -0
  395. package/dist-server/server/drivers/native.js +21 -0
  396. package/dist-server/server/drivers/openai-chat.js +240 -0
  397. package/dist-server/server/drivers/openai-compat.js +143 -0
  398. package/dist-server/server/drivers/phone-proxy.js +372 -0
  399. package/dist-server/server/drivers/pi.js +855 -0
  400. package/dist-server/server/drivers/retry.js +96 -0
  401. package/dist-server/server/enterprise.js +93 -0
  402. package/dist-server/server/env-path.js +329 -0
  403. package/dist-server/server/environment.js +105 -0
  404. package/dist-server/server/generated-image.js +39 -0
  405. package/dist-server/server/graceful-shutdown.js +24 -0
  406. package/dist-server/server/group-goal-run.js +124 -0
  407. package/dist-server/server/harness/bus.js +86 -0
  408. package/dist-server/server/harness/registry.js +217 -0
  409. package/dist-server/server/index.js +11634 -0
  410. package/dist-server/server/installed-playbooks.js +34 -0
  411. package/dist-server/server/local-computer.js +278 -0
  412. package/dist-server/server/local-routing.js +9 -0
  413. package/dist-server/server/local-vm-idle.js +44 -0
  414. package/dist-server/server/local-vm-inventory.js +34 -0
  415. package/dist-server/server/local-vm-lease.js +58 -0
  416. package/dist-server/server/mcp-bridge.js +251 -0
  417. package/dist-server/server/mcp-probe.js +153 -0
  418. package/dist-server/server/mcp-registry.js +130 -0
  419. package/dist-server/server/member-turn.js +6 -0
  420. package/dist-server/server/message-db.js +358 -0
  421. package/dist-server/server/message-file.js +439 -0
  422. package/dist-server/server/names.js +26 -0
  423. package/dist-server/server/notify.js +69 -0
  424. package/dist-server/server/openmaus-status-capsule.js +329 -0
  425. package/dist-server/server/openmausbot.js +6 -0
  426. package/dist-server/server/package-export.js +157 -0
  427. package/dist-server/server/pair-cli.js +7 -0
  428. package/dist-server/server/peer-approval-key.js +5 -0
  429. package/dist-server/server/peer-approval.js +182 -0
  430. package/dist-server/server/peer-provenance.js +44 -0
  431. package/dist-server/server/peer-roster.js +139 -0
  432. package/dist-server/server/permission-proxy.js +157 -0
  433. package/dist-server/server/phone-secret.js +358 -0
  434. package/dist-server/server/private-screen-capture.js +17 -0
  435. package/dist-server/server/procs.js +123 -0
  436. package/dist-server/server/project-scout.js +304 -0
  437. package/dist-server/server/proxy-paths.js +47 -0
  438. package/dist-server/server/redact.js +102 -0
  439. package/dist-server/server/remote-computer.js +170 -0
  440. package/dist-server/server/repeat-detector.js +48 -0
  441. package/dist-server/server/replies.js +38 -0
  442. package/dist-server/server/request-auth.js +327 -0
  443. package/dist-server/server/room-cwd.js +15 -0
  444. package/dist-server/server/room-post-budget.js +112 -0
  445. package/dist-server/server/room-turn-timeout.js +115 -0
  446. package/dist-server/server/routine-requests.js +871 -0
  447. package/dist-server/server/routines.js +1111 -0
  448. package/dist-server/server/schema.js +11 -0
  449. package/dist-server/server/screen-frame-gate.js +80 -0
  450. package/dist-server/server/section-context.js +85 -0
  451. package/dist-server/server/send-idempotency.js +53 -0
  452. package/dist-server/server/sessions.js +319 -0
  453. package/dist-server/server/skill-fetch.js +148 -0
  454. package/dist-server/server/skill-learn.js +61 -0
  455. package/dist-server/server/skill-library.js +116 -0
  456. package/dist-server/server/skills.js +1223 -0
  457. package/dist-server/server/steer-queue.js +114 -0
  458. package/dist-server/server/store.js +1217 -0
  459. package/dist-server/server/surface.js +107 -0
  460. package/dist-server/server/tailscale.js +103 -0
  461. package/dist-server/server/team-backup.js +183 -0
  462. package/dist-server/server/team-library.js +205 -0
  463. package/dist-server/server/team-manifest.js +224 -0
  464. package/dist-server/server/thread-events.js +226 -0
  465. package/dist-server/server/tts/elevenlabs.js +92 -0
  466. package/dist-server/server/tts/index.js +79 -0
  467. package/dist-server/server/tts/speech-text.js +195 -0
  468. package/dist-server/server/tts/system-voices.js +74 -0
  469. package/dist-server/server/tunnel.js +202 -0
  470. package/dist-server/server/turn-context.js +40 -0
  471. package/dist-server/server/turn-dispatch-guard.js +152 -0
  472. package/dist-server/server/turn-images.js +138 -0
  473. package/dist-server/server/turn-watchdog.js +65 -0
  474. package/dist-server/server/vps-computer.js +1099 -0
  475. package/dist-server/server/vps-container-mcp.js +31 -0
  476. package/dist-server/server/webhook-ingress.js +173 -0
  477. package/dist-server/server/webhooks.js +491 -0
  478. package/dist-server/server/workspace.js +178 -0
  479. package/dist-server/shared/approval-mode.js +39 -0
  480. package/dist-server/shared/bot-avatar.js +33 -0
  481. package/dist-server/shared/bot-profile.js +7 -0
  482. package/dist-server/shared/connector-availability.js +12 -0
  483. package/dist-server/shared/credential-request.js +82 -0
  484. package/dist-server/shared/group-goal-run.js +1 -0
  485. package/dist-server/shared/import-name.js +11 -0
  486. package/dist-server/shared/mascot-bodies.js +107 -0
  487. package/dist-server/shared/routine-request.js +10 -0
  488. package/dist-server/shared/routine-run.js +1 -0
  489. package/dist-server/shared/skill-request.js +16 -0
  490. package/dist-server/shared/team-backup.js +148 -0
  491. package/dist-server/src/lib/composer-attachments.js +676 -0
  492. package/dist-server/tunnel-guardian.js +390 -0
  493. package/dist-server/vps-container-mcp.js +15209 -0
  494. package/package.json +32 -0
  495. package/skills/create-verification-skill/SKILL.md +65 -0
  496. package/skills/create-verification-skill/manifest.json +13 -0
  497. package/skills/phone-harness/SKILL.md +26 -0
  498. package/skills/phone-harness/agents/openai.yaml +13 -0
  499. package/skills/phone-harness/manifest.json +17 -0
@@ -0,0 +1,31 @@
1
+ // Transparent stdio bridge to the official Cua MCP server in a VPS
2
+ // container. Docker's SSH transport handles authentication through the
3
+ // user's normal SSH config and agent; this process stores no credentials.
4
+ // The piping, drain-safe exit, and dead-transport watchdog live in
5
+ // mcp-bridge.ts, shared with the Local VM entry point.
6
+ import { runMcpBridge } from "./mcp-bridge.js";
7
+ import { vpsContainerMcpArgs, vpsDockerArgs } from "./vps-computer.js";
8
+ const [alias, containerName] = process.argv.slice(2);
9
+ const sshAlias = alias ?? "";
10
+ let args;
11
+ try {
12
+ args = vpsContainerMcpArgs(sshAlias, containerName ?? "");
13
+ }
14
+ catch {
15
+ process.stderr.write("invalid VPS MCP connection\n");
16
+ process.exit(2);
17
+ }
18
+ // The who-is-driving pair rides in env, not argv — argv is world-readable
19
+ // through `ps`, and the token guards a loopback endpoint.
20
+ const controlUrl = process.env.OMB_CONTROL_URL ?? "";
21
+ const controlToken = process.env.OMB_CONTROL_TOKEN ?? "";
22
+ runMcpBridge({
23
+ command: "docker",
24
+ args,
25
+ label: "VPS Cua Driver",
26
+ // The probe checks the TRANSPORT (SSH + daemon), deliberately not the
27
+ // driver: a busy desktop mid-tool-call must never look dead, while an
28
+ // unreachable VPS must, and `docker version` distinguishes exactly that.
29
+ liveness: { command: "docker", args: vpsDockerArgs(sshAlias, ["version", "--format", "{{.Server.Version}}"]) },
30
+ ...(controlUrl && controlToken ? { gate: { url: controlUrl, token: controlToken } } : {}),
31
+ });
@@ -0,0 +1,173 @@
1
+ import { createServer } from "node:http";
2
+ import { z } from "zod";
3
+ import { parseJson } from "./schema.js";
4
+ export const MAX_WEBHOOK_BODY_BYTES = 256 * 1024;
5
+ const statusErrorSchema = z.object({ status: z.number().int().optional() });
6
+ const serverAddressSchema = z.object({ port: z.number().int().min(1).max(65_535) });
7
+ function json(res, status, body) {
8
+ res.writeHead(status, {
9
+ "content-type": "application/json",
10
+ "cache-control": "no-store",
11
+ "x-content-type-options": "nosniff",
12
+ });
13
+ res.end(JSON.stringify(body));
14
+ }
15
+ async function readRawBody(req) {
16
+ const chunks = [];
17
+ let bytes = 0;
18
+ try {
19
+ for await (const chunk of req) {
20
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
21
+ bytes += buffer.length;
22
+ if (bytes > MAX_WEBHOOK_BODY_BYTES) {
23
+ throw Object.assign(new Error("Webhook body is too large"), { status: 413 });
24
+ }
25
+ chunks.push(buffer);
26
+ }
27
+ }
28
+ catch (error) {
29
+ const parsed = statusErrorSchema.safeParse(error);
30
+ if (parsed.success && parsed.data.status === 413)
31
+ throw error;
32
+ throw Object.assign(new Error("Could not read webhook body"), { status: 400 });
33
+ }
34
+ return Buffer.concat(chunks, bytes).toString("utf8");
35
+ }
36
+ function parsePayload(raw, contentType) {
37
+ if (!raw)
38
+ return {};
39
+ if (contentType.includes("application/json") || contentType.includes("+json")) {
40
+ try {
41
+ return parseJson(raw);
42
+ }
43
+ catch {
44
+ throw Object.assign(new Error("Invalid JSON webhook body"), { status: 400 });
45
+ }
46
+ }
47
+ if (contentType.includes("application/x-www-form-urlencoded")) {
48
+ return Object.fromEntries(new URLSearchParams(raw));
49
+ }
50
+ return raw;
51
+ }
52
+ function header(req, name) {
53
+ const value = req.headers[name];
54
+ return Array.isArray(value) ? value[0] : value;
55
+ }
56
+ function bearerSecret(req) {
57
+ const authorization = header(req, "authorization") ?? "";
58
+ const match = authorization.match(/^Bearer\s+(.+)$/i);
59
+ return match?.[1]?.trim() || header(req, "x-openmaus-secret")?.trim() || "";
60
+ }
61
+ function deliveryId(req) {
62
+ return (header(req, "idempotency-key") ??
63
+ header(req, "x-webhook-id") ??
64
+ header(req, "x-github-delivery") ??
65
+ header(req, "webhook-id"))?.trim() || undefined;
66
+ }
67
+ function eventName(req) {
68
+ return (header(req, "x-github-event") ??
69
+ header(req, "x-webhook-event") ??
70
+ header(req, "x-event-type") ??
71
+ header(req, "ce-type"))?.trim() || undefined;
72
+ }
73
+ export function createWebhookIngressHandler(manager) {
74
+ return async (req, res) => {
75
+ const url = new URL(req.url ?? "/", "http://localhost");
76
+ if (req.method === "GET" && url.pathname === "/health") {
77
+ return json(res, 200, { app: "openmausbot-webhooks", ready: true });
78
+ }
79
+ const match = url.pathname.match(/^\/hooks\/(wh_[A-Za-z0-9_-]+)(?:\/([^/]+))?$/);
80
+ if (!match)
81
+ return json(res, 404, { error: "Unknown webhook endpoint" });
82
+ if (req.method !== "POST")
83
+ return json(res, 405, { error: "Webhooks accept POST requests" });
84
+ try {
85
+ const pathSecret = match[2] ? decodeURIComponent(match[2]) : "";
86
+ const secret = pathSecret || bearerSecret(req);
87
+ // Reject bad capability URLs before buffering or parsing attacker input.
88
+ if (!manager.authorize(match[1], secret)) {
89
+ manager.recordRejected(match[1], 401, "Invalid webhook URL or secret", {
90
+ contentType: header(req, "content-type"),
91
+ eventName: eventName(req),
92
+ deliveryId: deliveryId(req),
93
+ });
94
+ return json(res, 401, { error: "Invalid webhook URL or secret" });
95
+ }
96
+ const raw = await readRawBody(req);
97
+ const contentType = header(req, "content-type")?.split(";")[0]?.trim().toLowerCase() ?? "text/plain";
98
+ const payload = parsePayload(raw, contentType);
99
+ const result = manager.receive(match[1], secret, {
100
+ payload,
101
+ contentType,
102
+ eventName: eventName(req),
103
+ userAgent: header(req, "user-agent"),
104
+ deliveryId: deliveryId(req),
105
+ });
106
+ return json(res, 202, { accepted: true, ...result });
107
+ }
108
+ catch (error) {
109
+ const parsedError = statusErrorSchema.safeParse(error);
110
+ const status = parsedError.success ? parsedError.data.status ?? 500 : 500;
111
+ const message = error instanceof Error ? error.message : String(error);
112
+ // Manager-level validation records its own rejection with the parsed
113
+ // payload. Receiver-level failures happen earlier, so record metadata
114
+ // here without buffering untrusted data a second time.
115
+ if (status === 400 || status === 413) {
116
+ manager.recordRejected(match[1], status, message, {
117
+ contentType: header(req, "content-type"),
118
+ eventName: eventName(req),
119
+ deliveryId: deliveryId(req),
120
+ });
121
+ }
122
+ return json(res, status, { error: message });
123
+ }
124
+ };
125
+ }
126
+ /** The base senders are told to use. Behind a proxy or tunnel the listening
127
+ * address is unreachable from outside, so the operator supplies the public
128
+ * one; a trailing slash is tolerated because every hook path adds its own. */
129
+ export function advertisedWebhookBase(raw) {
130
+ let parsed;
131
+ try {
132
+ parsed = new URL(raw);
133
+ }
134
+ catch {
135
+ parsed = undefined;
136
+ }
137
+ if (!parsed || (parsed.protocol !== "http:" && parsed.protocol !== "https:")) {
138
+ throw new Error(`webhook public base URL must be an absolute http(s) URL such as https://bots.example.com, got "${raw}"`);
139
+ }
140
+ return raw.replace(/\/+$/, "");
141
+ }
142
+ export async function listenWebhookIngress(manager, options) {
143
+ const host = options.host ?? "127.0.0.1";
144
+ const advertised = options.publicBaseUrl === undefined ? undefined : advertisedWebhookBase(options.publicBaseUrl);
145
+ const server = createServer(createWebhookIngressHandler(manager));
146
+ await new Promise((resolve, reject) => {
147
+ const onError = (error) => reject(error);
148
+ server.once("error", onError);
149
+ server.listen(options.port, host, () => {
150
+ server.off("error", onError);
151
+ resolve();
152
+ });
153
+ });
154
+ const address = serverAddressSchema.safeParse(server.address());
155
+ if (!address.success) {
156
+ server.close();
157
+ throw new Error("Webhook receiver did not get a TCP address");
158
+ }
159
+ return {
160
+ server,
161
+ host,
162
+ port: address.data.port,
163
+ baseUrl: advertised ?? `http://${host}:${address.data.port}`,
164
+ };
165
+ }
166
+ export function webhookCredential(baseUrl, endpointId, secret) {
167
+ const endpointUrl = `${baseUrl.replace(/\/$/, "")}/hooks/${endpointId}`;
168
+ return {
169
+ endpointUrl,
170
+ secret,
171
+ url: `${endpointUrl}/${encodeURIComponent(secret)}`,
172
+ };
173
+ }
@@ -0,0 +1,491 @@
1
+ import { createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
2
+ import { mkdirSync, readFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { z } from "zod";
5
+ import { writeFileAtomic } from "./atomic.js";
6
+ import { DATA_DIR } from "./config.js";
7
+ import { parseJson, schemaIssue } from "./schema.js";
8
+ const MAX_DELIVERIES = 2_000;
9
+ const MAX_ATTEMPTS = 2_000;
10
+ const MAX_EVENT_CHARS = 48_000;
11
+ const RATE_WINDOW_MS = 60_000;
12
+ const RATE_LIMIT = 10;
13
+ const MAX_PENDING_RUNS = 3;
14
+ const runOnSchema = z.enum(["maus", "cloud"]);
15
+ const eventTypesSchema = z.array(z.string()).max(20).optional();
16
+ const triggerInputSchema = z.object({
17
+ name: z.string(),
18
+ prompt: z.string(),
19
+ botId: z.string(),
20
+ runOn: runOnSchema.optional(),
21
+ enabled: z.boolean().optional(),
22
+ verificationPending: z.boolean().optional(),
23
+ eventTypes: eventTypesSchema,
24
+ });
25
+ const triggerPatchSchema = triggerInputSchema.partial();
26
+ const verificationSampleSchema = z.object({
27
+ receivedAt: z.number().finite().nonnegative(),
28
+ eventName: z.string().optional(),
29
+ contentType: z.string().optional(),
30
+ preview: z.string(),
31
+ });
32
+ const storedWebhookSchema = z.object({
33
+ id: z.string().min(1),
34
+ endpointId: z.string().min(1),
35
+ name: z.string(),
36
+ prompt: z.string(),
37
+ botId: z.string().min(1),
38
+ runOn: runOnSchema,
39
+ enabled: z.boolean(),
40
+ createdAt: z.number().finite().nonnegative(),
41
+ updatedAt: z.number().finite().nonnegative(),
42
+ lastReceivedAt: z.number().finite().nonnegative().optional(),
43
+ lastRunId: z.string().optional(),
44
+ deliveryCount: z.number().int().nonnegative(),
45
+ verificationPending: z.boolean().optional(),
46
+ verifiedAt: z.number().finite().nonnegative().optional(),
47
+ verificationSample: verificationSampleSchema.optional(),
48
+ eventTypes: eventTypesSchema,
49
+ secretHash: z.string().regex(/^[a-f0-9]{64}$/),
50
+ });
51
+ const deliveryReceiptSchema = z.object({
52
+ key: z.string().min(1),
53
+ runId: z.string().min(1),
54
+ at: z.number().finite().nonnegative(),
55
+ });
56
+ const webhookAttemptSchema = z.object({
57
+ id: z.string().min(1),
58
+ webhookId: z.string().min(1),
59
+ receivedAt: z.number().finite().nonnegative(),
60
+ outcome: z.enum(["accepted", "captured", "duplicate", "ignored", "rejected"]),
61
+ statusCode: z.number().int().min(100).max(599),
62
+ eventName: z.string().optional(),
63
+ preview: z.string().optional(),
64
+ deliveryId: z.string().optional(),
65
+ runId: z.string().optional(),
66
+ reason: z.string().optional(),
67
+ });
68
+ const webhookFileSchema = z.object({
69
+ version: z.literal(1),
70
+ webhooks: z.array(storedWebhookSchema),
71
+ deliveries: z.array(deliveryReceiptSchema),
72
+ attempts: z.array(webhookAttemptSchema).optional(),
73
+ });
74
+ const taskPayloadSchema = z.object({ task: z.string().optional(), message: z.string().optional() });
75
+ const statusErrorSchema = z.object({ status: z.number().int().optional() });
76
+ function fail(status, message) {
77
+ throw Object.assign(new Error(message), { status });
78
+ }
79
+ function invalidInput(error) {
80
+ fail(400, schemaIssue(error, "Invalid webhook settings"));
81
+ }
82
+ function hashSecret(secret) {
83
+ return createHash("sha256").update(secret).digest("hex");
84
+ }
85
+ function secretMatches(secret, expectedHex) {
86
+ if (!secret)
87
+ return false;
88
+ const actual = Buffer.from(hashSecret(secret), "hex");
89
+ const expected = Buffer.from(expectedHex, "hex");
90
+ return actual.length === expected.length && timingSafeEqual(actual, expected);
91
+ }
92
+ function newEndpointId() {
93
+ return `wh_${randomBytes(12).toString("base64url")}`;
94
+ }
95
+ function newSecret() {
96
+ return `whsec_${randomBytes(32).toString("base64url")}`;
97
+ }
98
+ function cleanInput(input) {
99
+ const name = input.name.trim().slice(0, 80);
100
+ const prompt = input.prompt.trim().slice(0, 20_000);
101
+ const botId = input.botId.trim();
102
+ const runOn = input.runOn ?? "maus";
103
+ if (!name)
104
+ fail(400, "Give the webhook a name");
105
+ if (!botId)
106
+ fail(400, "Choose a MAUS");
107
+ if (runOn !== "maus" && runOn !== "cloud")
108
+ fail(400, "Choose where this webhook runs");
109
+ const eventTypes = Array.from(new Set((input.eventTypes ?? [])
110
+ .map((value) => value.trim().slice(0, 200))
111
+ .filter(Boolean))).slice(0, 20);
112
+ const enabled = input.enabled !== false;
113
+ const clean = {
114
+ name,
115
+ prompt,
116
+ botId,
117
+ runOn,
118
+ enabled,
119
+ verificationPending: enabled ? false : input.verificationPending === true,
120
+ };
121
+ if (eventTypes.length)
122
+ clean.eventTypes = eventTypes;
123
+ return clean;
124
+ }
125
+ function parseTriggerInput(value) {
126
+ const parsed = triggerInputSchema.safeParse(value);
127
+ if (!parsed.success)
128
+ invalidInput(parsed.error);
129
+ return parsed.data;
130
+ }
131
+ function parseTriggerPatch(value) {
132
+ const parsed = triggerPatchSchema.safeParse(value);
133
+ if (!parsed.success)
134
+ invalidInput(parsed.error);
135
+ return parsed.data;
136
+ }
137
+ function publicTrigger(trigger) {
138
+ const { secretHash: _secretHash, ...safe } = trigger;
139
+ return { ...safe };
140
+ }
141
+ function serializePayload(payload) {
142
+ let text;
143
+ const plainText = z.string().safeParse(payload);
144
+ if (plainText.success)
145
+ text = plainText.data;
146
+ else {
147
+ try {
148
+ text = JSON.stringify(payload, null, 2) ?? String(payload);
149
+ }
150
+ catch {
151
+ text = String(payload);
152
+ }
153
+ }
154
+ if (text.length <= MAX_EVENT_CHARS)
155
+ return text;
156
+ return `${text.slice(0, MAX_EVENT_CHARS)}\n\n[Payload truncated by OpenMausBot]`;
157
+ }
158
+ function previewPayload(payload) {
159
+ return serializePayload(payload).replace(/\s+/g, " ").trim().slice(0, 2_000);
160
+ }
161
+ function taskFromPayload(payload) {
162
+ const parsed = taskPayloadSchema.safeParse(payload);
163
+ if (!parsed.success)
164
+ return "";
165
+ const task = parsed.data.task ?? parsed.data.message ?? "";
166
+ return task.trim().slice(0, 20_000);
167
+ }
168
+ function eventPrompt(trigger, event, receivedAt, deliveryId) {
169
+ const metadata = [
170
+ `Received: ${new Date(receivedAt).toISOString()}`,
171
+ `Delivery ID: ${deliveryId}`,
172
+ event.eventName && `Event: ${event.eventName.slice(0, 200)}`,
173
+ event.contentType && `Content-Type: ${event.contentType.slice(0, 200)}`,
174
+ event.userAgent && `Sender: ${event.userAgent.slice(0, 300)}`,
175
+ ].filter(Boolean);
176
+ const configured = trigger.prompt.trim();
177
+ const requestedTask = configured ? "" : taskFromPayload(event.payload);
178
+ const instructionBlock = configured
179
+ ? ["[USER-CONFIGURED WEBHOOK INSTRUCTIONS]", configured, "[/USER-CONFIGURED WEBHOOK INSTRUCTIONS]"]
180
+ : requestedTask
181
+ ? ["[AUTHENTICATED WEBHOOK TASK]", requestedTask, "[/AUTHENTICATED WEBHOOK TASK]"]
182
+ : [
183
+ "[DEFAULT WEBHOOK INSTRUCTIONS]",
184
+ "Review the incoming event and summarize what happened. Do not take external actions unless the event clearly requires them and existing permissions allow them.",
185
+ "[/DEFAULT WEBHOOK INSTRUCTIONS]",
186
+ ];
187
+ return [
188
+ ...instructionBlock,
189
+ "",
190
+ "[UNTRUSTED WEBHOOK EVENT DATA]",
191
+ ...metadata,
192
+ "",
193
+ serializePayload(event.payload),
194
+ "[/UNTRUSTED WEBHOOK EVENT DATA]",
195
+ ].join("\n");
196
+ }
197
+ export class WebhookManager {
198
+ file;
199
+ now;
200
+ options;
201
+ webhooks = [];
202
+ deliveries = [];
203
+ attempts = [];
204
+ rate = new Map();
205
+ constructor(options) {
206
+ this.options = options;
207
+ this.file = options.file ?? join(DATA_DIR, "webhooks.json");
208
+ this.now = options.now ?? Date.now;
209
+ try {
210
+ const parsed = webhookFileSchema.safeParse(parseJson(readFileSync(this.file, "utf8")));
211
+ if (!parsed.success)
212
+ throw parsed.error;
213
+ this.webhooks = parsed.data.webhooks;
214
+ this.deliveries = parsed.data.deliveries.slice(-MAX_DELIVERIES);
215
+ this.attempts = (parsed.data.attempts ?? []).slice(-MAX_ATTEMPTS);
216
+ }
217
+ catch {
218
+ this.webhooks = [];
219
+ this.deliveries = [];
220
+ this.attempts = [];
221
+ }
222
+ }
223
+ list() {
224
+ return this.webhooks.map(publicTrigger);
225
+ }
226
+ listAttempts() {
227
+ return this.attempts.map((attempt) => ({ ...attempt }));
228
+ }
229
+ create(input) {
230
+ const clean = cleanInput(parseTriggerInput(input));
231
+ if (this.options.botState(clean.botId) === "missing")
232
+ fail(400, "That MAUS no longer exists");
233
+ const now = this.now();
234
+ const secret = newSecret();
235
+ const trigger = {
236
+ id: randomUUID(),
237
+ endpointId: newEndpointId(),
238
+ ...clean,
239
+ secretHash: hashSecret(secret),
240
+ createdAt: now,
241
+ updatedAt: now,
242
+ deliveryCount: 0,
243
+ };
244
+ this.webhooks.unshift(trigger);
245
+ this.save();
246
+ this.emit(trigger);
247
+ return { webhook: publicTrigger(trigger), secret };
248
+ }
249
+ update(id, value) {
250
+ const trigger = this.webhooks.find((candidate) => candidate.id === id);
251
+ if (!trigger)
252
+ return null;
253
+ const patch = parseTriggerPatch(value);
254
+ const clean = cleanInput({
255
+ name: patch.name ?? trigger.name,
256
+ prompt: patch.prompt ?? trigger.prompt,
257
+ botId: patch.botId ?? trigger.botId,
258
+ runOn: patch.runOn ?? trigger.runOn,
259
+ enabled: patch.enabled ?? trigger.enabled,
260
+ verificationPending: patch.verificationPending ?? trigger.verificationPending,
261
+ eventTypes: patch.eventTypes ?? trigger.eventTypes,
262
+ });
263
+ if (this.options.botState(clean.botId) === "missing")
264
+ fail(400, "That MAUS no longer exists");
265
+ Object.assign(trigger, clean, { updatedAt: this.now() });
266
+ if (!clean.eventTypes?.length)
267
+ delete trigger.eventTypes;
268
+ if (patch.enabled === false) {
269
+ this.options.cancelQueued?.(trigger.id, "The webhook was paused before this delivery started");
270
+ }
271
+ this.save();
272
+ this.emit(trigger);
273
+ return publicTrigger(trigger);
274
+ }
275
+ remove(id) {
276
+ const at = this.webhooks.findIndex((candidate) => candidate.id === id);
277
+ if (at === -1)
278
+ return false;
279
+ const [trigger] = this.webhooks.splice(at, 1);
280
+ this.deliveries = this.deliveries.filter((delivery) => !delivery.key.startsWith(`${trigger.endpointId}:`));
281
+ this.attempts = this.attempts.filter((attempt) => attempt.webhookId !== trigger.id);
282
+ this.rate.delete(trigger.endpointId);
283
+ this.options.cancelQueued?.(trigger.id, "The webhook was deleted before this delivery started");
284
+ this.save();
285
+ this.options.emit?.({ kind: "webhook.deleted", webhookId: id });
286
+ return true;
287
+ }
288
+ rotateSecret(id) {
289
+ const trigger = this.webhooks.find((candidate) => candidate.id === id);
290
+ if (!trigger)
291
+ return null;
292
+ const secret = newSecret();
293
+ trigger.secretHash = hashSecret(secret);
294
+ trigger.updatedAt = this.now();
295
+ this.save();
296
+ this.emit(trigger);
297
+ return { webhook: publicTrigger(trigger), secret };
298
+ }
299
+ disableForBot(botId) {
300
+ let changed = false;
301
+ for (const trigger of this.webhooks) {
302
+ if (trigger.botId !== botId || !trigger.enabled)
303
+ continue;
304
+ trigger.enabled = false;
305
+ trigger.updatedAt = this.now();
306
+ this.options.cancelQueued?.(trigger.id, "The assigned MAUS was deleted");
307
+ this.emit(trigger);
308
+ changed = true;
309
+ }
310
+ if (changed)
311
+ this.save();
312
+ }
313
+ authorize(endpointId, secret) {
314
+ const trigger = this.webhooks.find((candidate) => candidate.endpointId === endpointId);
315
+ return Boolean(trigger && secretMatches(secret, trigger.secretHash));
316
+ }
317
+ receive(endpointId, secret, event) {
318
+ const trigger = this.webhooks.find((candidate) => candidate.endpointId === endpointId);
319
+ if (!trigger || !secretMatches(secret, trigger.secretHash))
320
+ fail(401, "Invalid webhook URL or secret");
321
+ if (trigger.verificationPending && !trigger.enabled)
322
+ return this.captureVerification(trigger, event);
323
+ try {
324
+ return this.dispatch(trigger, event);
325
+ }
326
+ catch (error) {
327
+ const parsedError = statusErrorSchema.safeParse(error);
328
+ const status = parsedError.success ? parsedError.data.status ?? 500 : 500;
329
+ this.recordRejectedForTrigger(trigger, status, error instanceof Error ? error.message : String(error), event);
330
+ throw error;
331
+ }
332
+ }
333
+ test(id, payload = { event: "openmaus.test", message: "Test webhook delivery" }) {
334
+ const trigger = this.webhooks.find((candidate) => candidate.id === id);
335
+ if (!trigger)
336
+ return null;
337
+ const eventName = trigger.eventTypes?.[0] ?? "openmaus.test";
338
+ return this.dispatch(trigger, {
339
+ payload,
340
+ contentType: "application/json",
341
+ eventName,
342
+ userAgent: "OpenMausBot webhook tester",
343
+ deliveryId: `test-${randomUUID()}`,
344
+ });
345
+ }
346
+ recordRejected(endpointId, statusCode, reason, event = {}) {
347
+ const trigger = this.webhooks.find((candidate) => candidate.endpointId === endpointId);
348
+ if (!trigger)
349
+ return null;
350
+ return this.recordRejectedForTrigger(trigger, statusCode, reason, event);
351
+ }
352
+ dispatch(trigger, event) {
353
+ if (!trigger.enabled)
354
+ fail(409, "This webhook is paused");
355
+ if (this.options.botState(trigger.botId) === "missing")
356
+ fail(410, "The assigned MAUS no longer exists");
357
+ const allowed = trigger.eventTypes ?? [];
358
+ if (allowed.length > 0 && (!event.eventName || !allowed.includes(event.eventName))) {
359
+ const deliveryId = String(event.deliveryId ?? "").trim().slice(0, 200) || randomUUID();
360
+ this.appendAttempt(trigger, event, {
361
+ outcome: "ignored",
362
+ statusCode: 202,
363
+ deliveryId,
364
+ reason: event.eventName ? `Event type “${event.eventName}” is not enabled` : "Event type is missing",
365
+ });
366
+ this.save();
367
+ return { deliveryId, duplicate: false, ignored: true };
368
+ }
369
+ const now = this.now();
370
+ const requestedDeliveryId = String(event.deliveryId ?? "").trim().slice(0, 200);
371
+ if (requestedDeliveryId) {
372
+ const key = `${trigger.endpointId}:${requestedDeliveryId}`;
373
+ const duplicate = this.deliveries.find((delivery) => delivery.key === key);
374
+ if (duplicate) {
375
+ this.appendAttempt(trigger, event, {
376
+ outcome: "duplicate",
377
+ statusCode: 202,
378
+ deliveryId: requestedDeliveryId,
379
+ runId: duplicate.runId,
380
+ reason: "Duplicate delivery ignored",
381
+ });
382
+ this.save();
383
+ return { runId: duplicate.runId, deliveryId: requestedDeliveryId, duplicate: true };
384
+ }
385
+ }
386
+ // A sender retrying an already-accepted delivery must remain idempotent
387
+ // even while this webhook's queue is full. Only new work consumes a slot.
388
+ if ((this.options.pendingRuns?.(trigger.id) ?? 0) >= MAX_PENDING_RUNS) {
389
+ fail(429, "This webhook already has too many unfinished tasks");
390
+ }
391
+ const recent = (this.rate.get(trigger.endpointId) ?? []).filter((at) => now - at < RATE_WINDOW_MS);
392
+ if (recent.length >= RATE_LIMIT)
393
+ fail(429, "Webhook rate limit exceeded");
394
+ recent.push(now);
395
+ this.rate.set(trigger.endpointId, recent);
396
+ const deliveryId = requestedDeliveryId || randomUUID();
397
+ const run = this.options.enqueue({
398
+ webhookId: trigger.id,
399
+ webhookName: trigger.name,
400
+ prompt: eventPrompt(trigger, event, now, deliveryId),
401
+ botId: trigger.botId,
402
+ runOn: trigger.runOn,
403
+ deliveryId,
404
+ receivedAt: now,
405
+ });
406
+ this.deliveries.push({ key: `${trigger.endpointId}:${deliveryId}`, runId: run.id, at: now });
407
+ if (this.deliveries.length > MAX_DELIVERIES) {
408
+ this.deliveries.splice(0, this.deliveries.length - MAX_DELIVERIES);
409
+ }
410
+ trigger.lastReceivedAt = now;
411
+ trigger.lastRunId = run.id;
412
+ trigger.deliveryCount += 1;
413
+ trigger.updatedAt = now;
414
+ this.appendAttempt(trigger, event, {
415
+ outcome: "accepted",
416
+ statusCode: 202,
417
+ deliveryId,
418
+ runId: run.id,
419
+ });
420
+ this.save();
421
+ this.emit(trigger);
422
+ return { runId: run.id, deliveryId, duplicate: false };
423
+ }
424
+ captureVerification(trigger, event) {
425
+ const receivedAt = this.now();
426
+ const deliveryId = String(event.deliveryId ?? "").trim().slice(0, 200) || randomUUID();
427
+ trigger.verificationPending = false;
428
+ trigger.verifiedAt = receivedAt;
429
+ trigger.lastReceivedAt = receivedAt;
430
+ trigger.updatedAt = receivedAt;
431
+ const sample = {
432
+ receivedAt,
433
+ preview: previewPayload(event.payload),
434
+ };
435
+ if (event.eventName)
436
+ sample.eventName = event.eventName.slice(0, 200);
437
+ if (event.contentType)
438
+ sample.contentType = event.contentType.slice(0, 200);
439
+ trigger.verificationSample = sample;
440
+ this.appendAttempt(trigger, event, {
441
+ outcome: "captured",
442
+ statusCode: 202,
443
+ deliveryId,
444
+ reason: "Test event captured; enable the webhook to start MAUS tasks",
445
+ });
446
+ this.save();
447
+ this.emit(trigger);
448
+ return { deliveryId, duplicate: false, captured: true };
449
+ }
450
+ recordRejectedForTrigger(trigger, statusCode, reason, event) {
451
+ const attempt = this.appendAttempt(trigger, event, {
452
+ outcome: "rejected",
453
+ statusCode,
454
+ reason: reason.slice(0, 500),
455
+ deliveryId: event.deliveryId,
456
+ });
457
+ this.save();
458
+ return attempt;
459
+ }
460
+ appendAttempt(trigger, event, details) {
461
+ const attempt = {
462
+ id: randomUUID(),
463
+ webhookId: trigger.id,
464
+ receivedAt: this.now(),
465
+ outcome: details.outcome,
466
+ statusCode: details.statusCode,
467
+ };
468
+ if (event.eventName)
469
+ attempt.eventName = event.eventName.slice(0, 200);
470
+ if (event.payload !== undefined)
471
+ attempt.preview = previewPayload(event.payload);
472
+ if (details.deliveryId)
473
+ attempt.deliveryId = details.deliveryId.slice(0, 200);
474
+ if (details.runId)
475
+ attempt.runId = details.runId;
476
+ if (details.reason)
477
+ attempt.reason = details.reason;
478
+ this.attempts.push(attempt);
479
+ if (this.attempts.length > MAX_ATTEMPTS)
480
+ this.attempts.splice(0, this.attempts.length - MAX_ATTEMPTS);
481
+ this.options.emit?.({ kind: "webhook.attempt", attempt: { ...attempt } });
482
+ return attempt;
483
+ }
484
+ emit(trigger) {
485
+ this.options.emit?.({ kind: "webhook", webhook: publicTrigger(trigger) });
486
+ }
487
+ save() {
488
+ mkdirSync(dirname(this.file), { recursive: true });
489
+ writeFileAtomic(this.file, JSON.stringify({ version: 1, webhooks: this.webhooks, deliveries: this.deliveries, attempts: this.attempts }, null, 2), { mode: 0o600 });
490
+ }
491
+ }