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,107 @@
1
+ // Where a bot's hands land — and therefore where the person goes when it
2
+ // needs them. A turn can mount two places at once (a computer plus the
3
+ // built-in browser), which is exactly what confused people: "do this on the
4
+ // web" landed in the cloud box's Chrome one turn and in the Browser tab the
5
+ // next, and the "needs your hands" plea never said which. Everything that
6
+ // decides or describes a surface lives here, so the picker, the dispatch,
7
+ // the system prompt and the notification cannot drift apart.
8
+ const SURFACES = new Set(["cloud", "vm", "local", "browser"]);
9
+ /** Parse a surface arriving over the wire; anything else is "not said". */
10
+ export function parseSurface(value) {
11
+ // SAFETY: the set membership check is the narrowing — only the four
12
+ // literal strings pass, and the assertion just names that fact to the type.
13
+ return typeof value === "string" && SURFACES.has(value) ? value : undefined;
14
+ }
15
+ /** The per-turn computer kinds the dispatch tracks, folded to a surface. */
16
+ export function surfaceOfComputerKind(kind) {
17
+ if (kind === "box" || kind === "vps")
18
+ return "cloud";
19
+ return kind;
20
+ }
21
+ const NO_BROWSER_NOTE = " This bot is set to work in the built-in browser, but the built-in browser is switched off in App Settings, so you have no browser and no computer this turn — say so instead of guessing.";
22
+ /** Decide what a turn mounts from the bot's destination, the task's pin
23
+ * and what is actually reachable. Explicit choices are strict: a computer
24
+ * destination keeps whatever browser the bot has (the prompt tells the
25
+ * model which to use), a browser destination mounts only the browser. Auto
26
+ * follows the task's pin while the pinned place still exists, and otherwise
27
+ * re-resolves the way it always has. */
28
+ export function resolveSurface(input) {
29
+ const { destination, browserOn } = input;
30
+ if (destination === "browser") {
31
+ return browserOn
32
+ ? { computer: "off", browser: true, pinned: null, clearPin: false, note: "" }
33
+ : { computer: "off", browser: false, pinned: null, clearPin: false, note: NO_BROWSER_NOTE };
34
+ }
35
+ if (destination !== undefined) {
36
+ return { computer: destination, browser: browserOn, pinned: null, clearPin: false, note: "" };
37
+ }
38
+ const pin = input.pinnedSurface ?? null;
39
+ if (pin === null) {
40
+ return { computer: undefined, browser: browserOn, pinned: null, clearPin: false, note: "" };
41
+ }
42
+ const reachable = pin === "browser" ? browserOn : input.available?.[pin] === true;
43
+ if (!reachable) {
44
+ return { computer: undefined, browser: browserOn, pinned: null, clearPin: true, note: "" };
45
+ }
46
+ return pin === "browser"
47
+ ? { computer: "off", browser: true, pinned: "browser", clearPin: false, note: "" }
48
+ : { computer: pin, browser: false, pinned: pin, clearPin: false, note: "" };
49
+ }
50
+ /** How the prompt and the app name a surface. Deliberately the same words
51
+ * the panel uses, so "tell them it is on the cloud computer" points at a
52
+ * label the person can find. */
53
+ export function surfaceLabel(surface) {
54
+ switch (surface) {
55
+ case "cloud":
56
+ return "the cloud computer";
57
+ case "vm":
58
+ return "the Local VM";
59
+ case "local":
60
+ return "this computer";
61
+ case "browser":
62
+ return "the built-in browser";
63
+ }
64
+ }
65
+ /** The one paragraph that says where this turn's work happens. Assembled
66
+ * from what was actually mounted, never from the setting, so the model is
67
+ * only ever told about tools it can call. */
68
+ export function surfacePrompt(mounted, opts = {}) {
69
+ const computer = mounted.computer ? surfaceLabel(mounted.computer) : null;
70
+ let text = "";
71
+ if (computer && mounted.browser) {
72
+ text =
73
+ ` Two surfaces are mounted this turn: the built-in browser (the browser server's browser_navigate, browser_snapshot, browser_click, browser_fill and friends) and ${computer} (the computer server's tools). Web tasks → the built-in browser. Desktop apps, files and shell → ${computer} tools. Pick one surface for a task and stay on it; if you need the user to sign in, say which surface — the Browser tab or ${computer}.`;
74
+ }
75
+ else if (computer) {
76
+ text =
77
+ ` Everything you do on screen happens on ${computer}, web pages included, through its own browser; there is no separate built-in browser this turn. If you need the user to sign in, tell them it is on ${computer}.`;
78
+ }
79
+ else if (mounted.browser) {
80
+ text =
81
+ " Everything you do on screen happens in the built-in browser tab; there is no desktop, file or shell computer this turn. If you need the user to sign in, tell them it is in the Browser tab of the Computer panel.";
82
+ }
83
+ if (opts.pinned) {
84
+ text += ` This task has been running on ${surfaceLabel(opts.pinned)}; keep using it unless the user says otherwise.`;
85
+ }
86
+ return text + (opts.note ?? "");
87
+ }
88
+ /** Tool names that touch a screen, for engines that report bare names.
89
+ * Mirrors the screen-poller regex in the harness. */
90
+ const SCREEN_TOOL = /^(?:screenshot|click|type_text|press_key|scroll|open_url|wait_for|computer_|browser_)/i;
91
+ /** Which surface a completed tool call landed on, or null when it cannot
92
+ * be told apart. The Claude driver namespaces MCP tools by server, which
93
+ * is the only fully reliable signal; a bare name is trusted only when one
94
+ * surface was mounted, because both servers expose `browser_snapshot`. */
95
+ export function surfaceForTool(toolName, mounted) {
96
+ if (toolName.startsWith("mcp__browser__"))
97
+ return mounted.browser ? "browser" : null;
98
+ if (toolName.startsWith("mcp__computer__"))
99
+ return mounted.computer;
100
+ if (!SCREEN_TOOL.test(toolName))
101
+ return null;
102
+ if (mounted.computer && !mounted.browser)
103
+ return mounted.computer;
104
+ if (!mounted.computer && mounted.browser && /^browser_/i.test(toolName))
105
+ return "browser";
106
+ return null;
107
+ }
@@ -0,0 +1,103 @@
1
+ // Serving over a tailnet: find the Tailscale CLI, read this machine's
2
+ // MagicDNS name, and ask Tailscale to terminate HTTPS for the server.
3
+ // Nothing here logs Tailscale's raw stderr: it can contain auth keys and
4
+ // node names, so failures are classified into a closed set of reasons.
5
+ import { execFile } from "node:child_process";
6
+ import { searchPath, tailscaleCandidates } from "../companion/src/listener.js";
7
+ /** Turn Tailscale's stderr into a reason without repeating it. */
8
+ export function classifyTailscaleStderr(text) {
9
+ const t = text.toLowerCase();
10
+ if (/not logged in|logged out|needs login|please log in/.test(t))
11
+ return "not-logged-in";
12
+ if (/is tailscale running|tailscaled is not running|connection refused|failed to connect to local tailscaled/.test(t))
13
+ return "not-running";
14
+ if (/access denied|permission denied|operator|must be root|not permitted/.test(t))
15
+ return "needs-operator";
16
+ if (/https is not enabled|enable https|cert|tls certs/.test(t))
17
+ return "https-not-enabled";
18
+ if (/magicdns/.test(t))
19
+ return "no-magicdns";
20
+ return "unknown";
21
+ }
22
+ /** What to do about it, for a person. */
23
+ export function explainTailscaleFailure(reason) {
24
+ switch (reason) {
25
+ case "not-installed":
26
+ return "Tailscale is not installed: https://tailscale.com/download";
27
+ case "not-logged-in":
28
+ return "Tailscale is installed but not signed in: run `tailscale up` (or sign in from the Tailscale app)";
29
+ case "not-running":
30
+ return "Tailscale is not running: start it, then try again";
31
+ case "no-magicdns":
32
+ return "this machine has no MagicDNS name: enable MagicDNS in the tailnet's DNS settings";
33
+ case "needs-operator":
34
+ return "Tailscale refused: on Linux run `sudo tailscale set --operator=$USER` once, then try again";
35
+ case "https-not-enabled":
36
+ return "HTTPS certificates are off for this tailnet: enable them in the admin console (DNS → HTTPS Certificates)";
37
+ default:
38
+ return "Tailscale reported an error; run `tailscale status` and `tailscale serve status` to see it";
39
+ }
40
+ }
41
+ function run(cli, args, timeoutMs) {
42
+ return new Promise((resolve) => {
43
+ execFile(cli, args, { timeout: timeoutMs, killSignal: "SIGKILL", maxBuffer: 16 * 1024 * 1024, env: { ...process.env, PATH: searchPath() } }, (error, stdout, stderr) => {
44
+ const code = error && "code" in error && typeof error.code === "number" ? error.code : error ? null : 0;
45
+ resolve({ ok: !error, stdout: String(stdout ?? ""), stderr: String(stderr ?? ""), code });
46
+ });
47
+ });
48
+ }
49
+ /** Parse `tailscale status --json`. Exported for tests. */
50
+ export function parseTailscaleStatus(cli, stdout) {
51
+ let parsed;
52
+ try {
53
+ parsed = JSON.parse(stdout);
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ const self = Reflect.get(Object(parsed), "Self");
59
+ const dns = Reflect.get(Object(self), "DNSName");
60
+ const ips = Reflect.get(Object(self), "TailscaleIPs");
61
+ const state = Reflect.get(Object(parsed), "BackendState");
62
+ return {
63
+ cli,
64
+ dnsName: typeof dns === "string" && dns ? dns.replace(/\.$/, "") : null,
65
+ addresses: Array.isArray(ips) ? ips.filter((v) => typeof v === "string") : [],
66
+ backendState: typeof state === "string" ? state : "unknown",
67
+ };
68
+ }
69
+ /** Find a working Tailscale CLI and read its status. */
70
+ export async function tailscaleStatus() {
71
+ let sawCli = false;
72
+ for (const cli of tailscaleCandidates()) {
73
+ const result = await run(cli, ["status", "--json"], 5_000);
74
+ if (!result.ok && !result.stdout && result.code === null)
75
+ continue; // not found or timed out
76
+ sawCli = true;
77
+ const status = parseTailscaleStatus(cli, result.stdout);
78
+ if (status) {
79
+ if (status.backendState === "NeedsLogin")
80
+ return { failure: "not-logged-in" };
81
+ if (status.backendState !== "Running")
82
+ return { failure: "not-running" };
83
+ return { status };
84
+ }
85
+ if (result.stderr)
86
+ return { failure: classifyTailscaleStderr(result.stderr) };
87
+ }
88
+ return { failure: sawCli ? "unknown" : "not-installed" };
89
+ }
90
+ /** `tailscale serve --bg --https=<httpsPort> http://127.0.0.1:<localPort>`:
91
+ * Tailscale terminates TLS with its own certificate and forwards with the
92
+ * forwarded headers the server expects. Returns the public origin. */
93
+ export async function tailscaleServe(status, localPort, httpsPort = 443) {
94
+ if (!status.dnsName)
95
+ return { failure: "no-magicdns" };
96
+ const result = await run(status.cli, ["serve", "--bg", `--https=${httpsPort}`, `http://127.0.0.1:${localPort}`], 20_000);
97
+ if (!result.ok)
98
+ return { failure: classifyTailscaleStderr(result.stderr || result.stdout) };
99
+ return { origin: httpsPort === 443 ? `https://${status.dnsName}` : `https://${status.dnsName}:${httpsPort}` };
100
+ }
101
+ export async function tailscaleServeOff(status, httpsPort = 443) {
102
+ await run(status.cli, ["serve", `--https=${httpsPort}`, "off"], 10_000);
103
+ }
@@ -0,0 +1,183 @@
1
+ import { newId } from "./contracts.js";
2
+ import { botMascotBody } from "../shared/mascot-bodies.js";
3
+ import { takeImportName } from "../shared/import-name.js";
4
+ import { MAX_TEAM_BACKUP_BYTES, parseTeamBackup } from "../shared/team-backup.js";
5
+ /** Preserve readable history without importing executable cards, live queue
6
+ * entries, approval requests, local paths or provider session handles. */
7
+ function messageText(message) {
8
+ const parts = [message.text ?? ""];
9
+ if (message.card)
10
+ parts.push(message.card.title, message.card.subtitle, ...message.card.options, message.card.answered ?? "");
11
+ if (message.tool)
12
+ parts.push(`[${message.tool.name}${message.tool.ok === false ? ": failed" : ""}]`);
13
+ if (message.kind === "connector")
14
+ parts.push("[Connection card — reconnect in Settings]");
15
+ if (message.kind === "secret")
16
+ parts.push("[Secret request — not restored]");
17
+ if (message.routineRun)
18
+ parts.push(`[Routine: ${message.routineRun.routineName} — ${message.routineRun.status}]`, message.routineRun.summary ?? "", message.routineRun.error ?? "");
19
+ if (message.goalRun)
20
+ parts.push(`[Room goal: ${message.goalRun.status}]`, message.goalRun.goal, message.goalRun.detail ?? "");
21
+ if (message.kind === "screen" || message.attachments?.length)
22
+ parts.push("[Image or attachment — file not included in this backup]");
23
+ return parts.filter(Boolean).join("\n");
24
+ }
25
+ export function createTeamBackup(store, routines, name) {
26
+ const botIds = new Set(store.bots.map((bot) => bot.id));
27
+ const warnings = [];
28
+ const history = (record) => {
29
+ const tasks = record.tasks?.length ? record.tasks : [{ threadId: record.threadId, title: "Conversation", createdAt: record.createdAt }];
30
+ return tasks.map((task) => ({
31
+ key: task.threadId, title: task.title, createdAt: task.createdAt,
32
+ activeLeafId: store.activeLeaf(task.threadId),
33
+ messages: store.messagesFor(task.threadId).map((message) => ({
34
+ id: message.id, role: message.role, text: messageText(message), at: message.at,
35
+ parentId: message.parentId ?? null, replyToId: message.replyToId,
36
+ from: message.from, peerPost: message.peerPost,
37
+ })),
38
+ }));
39
+ };
40
+ const groups = store.groups.map((group) => {
41
+ const memberIds = group.memberIds.filter((id) => botIds.has(id));
42
+ if (memberIds.length !== group.memberIds.length)
43
+ warnings.push(`Room “${group.name}” contains deleted bots. Its conversation is included with the remaining members.`);
44
+ return {
45
+ key: group.id, name: group.name, section: group.section, dm: Boolean(group.dm) && memberIds.length === 2,
46
+ bulletin: group.bulletin, memberIds,
47
+ defaultResponder: group.defaultResponder.kind === "member" && !memberIds.includes(group.defaultResponder.botId)
48
+ ? { kind: "mentions" } : group.defaultResponder,
49
+ activeTask: group.threadId, tasks: history(group),
50
+ };
51
+ });
52
+ const validRoutines = routines.filter((routine) => {
53
+ const room = groups.find((group) => group.key === routine.groupId);
54
+ const valid = botIds.has(routine.botId) && (routine.target !== "room-goal" || (room && !room.dm && room.memberIds.includes(routine.botId)));
55
+ if (!valid)
56
+ warnings.push(`Routine “${routine.name}” is not included because its bot, room or coordinator was deleted.`);
57
+ return valid;
58
+ });
59
+ const document = parseTeamBackup({
60
+ format: "openmaus.backup", version: 1, name, exportedAt: Date.now(),
61
+ warnings,
62
+ bots: store.bots.map((bot) => ({
63
+ key: bot.id, name: bot.name, title: bot.title, description: bot.description,
64
+ section: bot.section, color: bot.color,
65
+ mascotExpression: bot.mascotExpression ?? undefined, mascotBody: bot.mascotBody ?? undefined,
66
+ chiefOfStaff: Boolean(bot.chiefOfStaff), hidden: Boolean(bot.hidden), playbooks: bot.playbooks ?? [],
67
+ activeTask: bot.threadId, tasks: history(bot),
68
+ })),
69
+ groups,
70
+ routines: validRoutines.map((routine) => ({
71
+ name: routine.name, prompt: routine.prompt, target: routine.target, botId: routine.botId,
72
+ groupId: routine.groupId, runOn: routine.runOn, schedule: routine.schedule,
73
+ durationMinutes: routine.durationMinutes, timeoutMinutes: routine.timeoutMinutes,
74
+ })),
75
+ });
76
+ // Never download a file our own importer cannot read; never truncate history.
77
+ if (Buffer.byteLength(JSON.stringify(document)) > MAX_TEAM_BACKUP_BYTES) {
78
+ throw new Error("This backup exceeds the 50 MB portable-backup limit. Nothing was exported or changed.");
79
+ }
80
+ return document;
81
+ }
82
+ /** Import is always additive, including sections and Chiefs. Rollback owns
83
+ * only the fresh records below and cannot touch any pre-existing bot/chat. */
84
+ export function importTeamBackup(store, routines, input, selection) {
85
+ const backup = parseTeamBackup(input);
86
+ const bots = [];
87
+ const groups = [];
88
+ const createdRoutines = [];
89
+ const existingBotIds = new Set(store.bots.map((bot) => bot.id));
90
+ const existingGroupIds = new Set(store.groups.map((group) => group.id));
91
+ const botIds = new Map();
92
+ const groupIds = new Map();
93
+ const takenNames = new Set(store.bots.map((bot) => bot.name.trim().toLowerCase()));
94
+ const takenGroups = new Set(store.groups.map((group) => group.name.trim().toLowerCase()));
95
+ const takenSections = new Set([...store.bots, ...store.groups].map((record) => record.section?.trim().toLowerCase() ?? ""));
96
+ const sections = new Map();
97
+ const sectionFor = (section) => {
98
+ const key = section?.trim() ?? "";
99
+ if (!sections.has(key))
100
+ sections.set(key, takeImportName(section?.trim() || "Imported bots", takenSections, 60));
101
+ return sections.get(key);
102
+ };
103
+ const restore = (task, threadId) => {
104
+ const ids = new Map(task.messages.map((message) => [message.id, newId()]));
105
+ const messages = task.messages.map((message) => ({
106
+ id: ids.get(message.id), kind: "text", role: message.role, text: message.text, at: message.at,
107
+ parentId: message.parentId ? ids.get(message.parentId) : null,
108
+ replyToId: message.replyToId ? ids.get(message.replyToId) : undefined,
109
+ // Removed historical senders retain their name in the text, never a
110
+ // link to an unrelated local bot with a colliding file key.
111
+ ...(message.from && botIds.has(message.from.botId)
112
+ ? { from: { ...message.from, botId: botIds.get(message.from.botId) } }
113
+ : message.from ? { text: `${message.from.name}:\n${message.text}` } : {}),
114
+ peerPost: message.peerPost,
115
+ }));
116
+ store.importTranscript(threadId, messages, task.activeLeafId ? ids.get(task.activeLeafId) : null);
117
+ };
118
+ try {
119
+ // Allocate all bot IDs before remapping any conversation participants.
120
+ for (const source of backup.bots) {
121
+ const bot = store.createBot({
122
+ name: takeImportName(source.name, takenNames), title: source.title, description: source.description,
123
+ color: source.color, mascotExpression: source.mascotExpression,
124
+ mascotBody: botMascotBody(source.mascotBody),
125
+ modelSelection: selection, section: sectionFor(source.section),
126
+ }, { seedMessages: false });
127
+ bots.push(bot);
128
+ botIds.set(source.key, bot.id);
129
+ store.patchBot(bot.id, { composio: false, computer: "off", browser: false, approvalMode: "ask", autoApprove: false,
130
+ hidden: source.hidden, chiefOfStaff: source.chiefOfStaff, playbooks: source.playbooks });
131
+ }
132
+ for (const source of backup.bots) {
133
+ const bot = store.bot(botIds.get(source.key));
134
+ const tasks = source.tasks.map((task, i) => ({
135
+ threadId: i === 0 ? bot.threadId : newId(), title: task.title, createdAt: task.createdAt, resumeCursors: {},
136
+ }));
137
+ // Own the task IDs before writing their transcripts, so rollback also
138
+ // removes partially imported history if persistence fails midway.
139
+ store.patchBot(bot.id, { tasks, threadId: tasks[source.tasks.findIndex((task) => task.key === source.activeTask)].threadId });
140
+ source.tasks.forEach((task, i) => restore(task, tasks[i].threadId));
141
+ }
142
+ for (const source of backup.groups) {
143
+ const group = store.createGroup(takeImportName(source.name, takenGroups), source.memberIds.map((id) => botIds.get(id)), source.dm, sectionFor(source.section));
144
+ groups.push(group);
145
+ groupIds.set(source.key, group.id);
146
+ const responder = source.defaultResponder;
147
+ store.patchGroup(group.id, { bulletin: source.bulletin, setupCompletedAt: Date.now(), defaultResponder: responder.kind === "member" ? { kind: "member", botId: botIds.get(responder.botId) } : responder });
148
+ // Use the existing task APIs for rooms; direct-message rooms have one.
149
+ const threads = source.tasks.map((task, i) => {
150
+ if (i === 0) {
151
+ if (!source.dm)
152
+ store.renameGroupTask(group.id, group.threadId, task.title);
153
+ return group.threadId;
154
+ }
155
+ return store.createGroupTask(group.id, task.title, false).threadId;
156
+ });
157
+ source.tasks.forEach((task, i) => restore(task, threads[i]));
158
+ if (!source.dm) {
159
+ group.tasks = source.tasks.map((task, i) => ({ threadId: threads[i], title: task.title, createdAt: task.createdAt }));
160
+ store.switchGroupTask(group.id, threads[source.tasks.findIndex((task) => task.key === source.activeTask)]);
161
+ }
162
+ }
163
+ for (const source of backup.routines) {
164
+ createdRoutines.push(routines.create({ ...source, botId: botIds.get(source.botId),
165
+ groupId: source.target === "room-goal" ? groupIds.get(source.groupId) : undefined, enabled: false }));
166
+ }
167
+ return { name: backup.name, bots, groups, routines: createdRoutines };
168
+ }
169
+ catch (error) {
170
+ for (const routine of createdRoutines)
171
+ routines.remove(routine.id);
172
+ // createBot/createGroup can throw during persistence before returning.
173
+ // This synchronous import cannot interleave another writer, so include
174
+ // every fresh ID, even a record that never reached the result arrays.
175
+ for (const group of store.groups)
176
+ if (!existingGroupIds.has(group.id))
177
+ store.deleteGroup(group.id);
178
+ for (const bot of store.bots)
179
+ if (!existingBotIds.has(bot.id))
180
+ store.deleteBot(bot.id);
181
+ throw error;
182
+ }
183
+ }
@@ -0,0 +1,205 @@
1
+ import { parseJson } from "./schema.js";
2
+ import { isBotPackage, parseBotPackage } from "./bot-package.js";
3
+ import { parseTeamManifest } from "./team-manifest.js";
4
+ export const TEAM_LIBRARY_REPOSITORY = "https://github.com/milind-soni/openmausbot-teams";
5
+ export const TEAM_LIBRARY_RAW_ROOT = "https://raw.githubusercontent.com/milind-soni/openmausbot-teams/main";
6
+ export const TEAM_LIBRARY_CATALOG_URL = `${TEAM_LIBRARY_RAW_ROOT}/catalog.json`;
7
+ const MAX_CATALOG_BYTES = 256_000;
8
+ const MAX_MANIFEST_BYTES = 1_000_000;
9
+ const isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
10
+ function text(value, field, max) {
11
+ if (typeof value !== "string" || !value.trim())
12
+ throw new Error(`${field} is required`);
13
+ const normalized = value.trim();
14
+ if (normalized.length > max)
15
+ throw new Error(`${field} is too long`);
16
+ return normalized;
17
+ }
18
+ function relativeFile(value, field, suffix, prefix) {
19
+ const path = text(value, field, 300);
20
+ if (path.startsWith("/") ||
21
+ path.includes("\\") ||
22
+ path.split("/").some((part) => !part || part === "." || part === "..") ||
23
+ !path.startsWith(prefix) ||
24
+ !path.endsWith(suffix)) {
25
+ throw new Error(`${field} is not a safe catalog path`);
26
+ }
27
+ return path;
28
+ }
29
+ function stringList(value, field, maxItems) {
30
+ if (!Array.isArray(value) || value.length > maxItems)
31
+ throw new Error(`${field} is invalid`);
32
+ return value.map((item, index) => text(item, `${field}[${index}]`, 100));
33
+ }
34
+ /** Validate the remotely maintained index before any of it reaches the renderer. */
35
+ export function parseTeamCatalog(value) {
36
+ if (!isRecord(value) || value.format !== "openmaus.catalog" || value.version !== 1) {
37
+ throw new Error("The team library catalog is not supported");
38
+ }
39
+ if (!Array.isArray(value.teams) || value.teams.length > 100) {
40
+ throw new Error("The team library catalog is invalid");
41
+ }
42
+ const slugs = new Set();
43
+ const teams = value.teams.map((raw, index) => {
44
+ const field = `teams[${index}]`;
45
+ if (!isRecord(raw))
46
+ throw new Error(`${field} is invalid`);
47
+ const slug = text(raw.slug, `${field}.slug`, 80);
48
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(slug) || slugs.has(slug)) {
49
+ throw new Error(`${field}.slug is invalid`);
50
+ }
51
+ slugs.add(slug);
52
+ const prefix = `teams/${slug}/`;
53
+ const requires = isRecord(raw.requires) ? raw.requires : {};
54
+ return {
55
+ slug,
56
+ name: text(raw.name, `${field}.name`, 100),
57
+ summary: text(raw.summary, `${field}.summary`, 300),
58
+ category: text(raw.category, `${field}.category`, 80),
59
+ ...(typeof raw.outcome === "string" ? { outcome: text(raw.outcome, `${field}.outcome`, 300) } : {}),
60
+ ...(typeof raw.setupMinutes === "number" && Number.isSafeInteger(raw.setupMinutes) && raw.setupMinutes > 0 && raw.setupMinutes <= 240
61
+ ? { setupMinutes: raw.setupMinutes }
62
+ : {}),
63
+ ...(typeof raw.featured === "boolean" ? { featured: raw.featured } : {}),
64
+ ...(raw.package !== undefined
65
+ ? { package: relativeFile(raw.package, `${field}.package`, ".md", "packages/") }
66
+ : {}),
67
+ manifest: relativeFile(raw.manifest, `${field}.manifest`, ".mausteam.json", prefix),
68
+ readme: relativeFile(raw.readme, `${field}.readme`, "README.md", prefix),
69
+ members: typeof raw.members === "number" && Number.isSafeInteger(raw.members) && raw.members > 0 && raw.members <= 200
70
+ ? raw.members
71
+ : (() => { throw new Error(`${field}.members is invalid`); })(),
72
+ skills: Array.isArray(raw.skills)
73
+ ? raw.skills.map((skill, skillIndex) => relativeFile(skill, `${field}.skills[${skillIndex}]`, "SKILL.md", `${prefix}skills/`))
74
+ : (() => { throw new Error(`${field}.skills is invalid`); })(),
75
+ requires: { apps: stringList(requires.apps ?? [], `${field}.requires.apps`, 30) },
76
+ };
77
+ });
78
+ return {
79
+ format: "openmaus.catalog",
80
+ version: 1,
81
+ repositoryUrl: TEAM_LIBRARY_REPOSITORY,
82
+ teams,
83
+ };
84
+ }
85
+ async function fetchJson(url, maxBytes, fetcher) {
86
+ const response = await fetcher(url, {
87
+ headers: { accept: "application/json, text/plain;q=0.9" },
88
+ redirect: "error",
89
+ signal: AbortSignal.timeout(10_000),
90
+ });
91
+ if (!response.ok) {
92
+ const error = Object.assign(new Error(`GitHub returned HTTP ${response.status}`), { status: response.status });
93
+ throw error;
94
+ }
95
+ const announced = Number(response.headers.get("content-length") ?? 0);
96
+ if (announced > maxBytes)
97
+ throw new Error("The remote team file is too large");
98
+ const raw = await response.text();
99
+ if (Buffer.byteLength(raw) > maxBytes)
100
+ throw new Error("The remote team file is too large");
101
+ try {
102
+ return parseJson(raw);
103
+ }
104
+ catch {
105
+ throw new Error("GitHub did not return valid JSON");
106
+ }
107
+ }
108
+ async function fetchText(url, maxBytes, fetcher) {
109
+ const response = await fetcher(url, {
110
+ headers: { accept: "text/markdown, text/plain;q=0.9" },
111
+ redirect: "error",
112
+ signal: AbortSignal.timeout(10_000),
113
+ });
114
+ if (!response.ok)
115
+ throw Object.assign(new Error(`GitHub returned HTTP ${response.status}`), { status: response.status });
116
+ const announced = Number(response.headers.get("content-length") ?? 0);
117
+ if (announced > maxBytes)
118
+ throw new Error("The remote team file is too large");
119
+ const raw = await response.text();
120
+ if (Buffer.byteLength(raw) > maxBytes)
121
+ throw new Error("The remote team file is too large");
122
+ return raw;
123
+ }
124
+ export async function fetchTeamCatalog(fetcher = fetch) {
125
+ return parseTeamCatalog(await fetchJson(TEAM_LIBRARY_CATALOG_URL, MAX_CATALOG_BYTES, fetcher));
126
+ }
127
+ function parseShareable(value) {
128
+ if (typeof value === "string")
129
+ return parseBotPackage(value);
130
+ return isBotPackage(value) ? parseBotPackage(value) : parseTeamManifest(value);
131
+ }
132
+ async function fetchShareable(url, fetcher) {
133
+ return url.endsWith(".md")
134
+ ? parseBotPackage(await fetchText(url, MAX_MANIFEST_BYTES, fetcher))
135
+ : parseShareable(await fetchJson(url, MAX_MANIFEST_BYTES, fetcher));
136
+ }
137
+ export async function fetchLibraryTeam(slug, fetcher = fetch) {
138
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(slug))
139
+ throw new Error("That team name is invalid");
140
+ const catalog = await fetchTeamCatalog(fetcher);
141
+ const entry = catalog.teams.find((team) => team.slug === slug);
142
+ if (!entry)
143
+ throw Object.assign(new Error("That library team was not found"), { status: 404 });
144
+ return fetchShareable(`${TEAM_LIBRARY_RAW_ROOT}/${entry.package ?? entry.manifest}`, fetcher);
145
+ }
146
+ function safeSegment(value) {
147
+ return /^[A-Za-z0-9._-]+$/.test(value) && value !== "." && value !== "..";
148
+ }
149
+ /** Resolve only public GitHub Markdown playbooks and legacy JSON team files.
150
+ * Other hosts never reach server fetch. */
151
+ export function githubManifestUrls(input) {
152
+ let url;
153
+ try {
154
+ url = new URL(input.trim());
155
+ }
156
+ catch {
157
+ throw new Error("Enter a valid GitHub URL");
158
+ }
159
+ if (url.protocol !== "https:" || url.username || url.password || url.port) {
160
+ throw new Error("Only public HTTPS GitHub links are supported");
161
+ }
162
+ const parts = url.pathname.split("/").filter(Boolean).map((part) => decodeURIComponent(part));
163
+ if (!parts.every(safeSegment))
164
+ throw new Error("That GitHub path is not supported");
165
+ if (url.hostname === "github.com" || url.hostname === "www.github.com") {
166
+ if (parts.length === 2) {
167
+ const [owner, repo] = parts;
168
+ return [
169
+ `https://raw.githubusercontent.com/${owner}/${repo}/main/botmrr.md`,
170
+ `https://raw.githubusercontent.com/${owner}/${repo}/main/team.md`,
171
+ `https://raw.githubusercontent.com/${owner}/${repo}/main/team.mausteam.json`,
172
+ `https://raw.githubusercontent.com/${owner}/${repo}/master/botmrr.md`,
173
+ `https://raw.githubusercontent.com/${owner}/${repo}/master/team.md`,
174
+ `https://raw.githubusercontent.com/${owner}/${repo}/master/team.mausteam.json`,
175
+ ];
176
+ }
177
+ if (parts.length >= 5 && (parts[2] === "blob" || parts[2] === "raw")) {
178
+ const [owner, repo, , ref, ...file] = parts;
179
+ if (!file.at(-1)?.match(/\.(?:md|json)$/))
180
+ throw new Error("The GitHub link must point to a Markdown playbook or JSON team file");
181
+ return [`https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${file.join("/")}`];
182
+ }
183
+ }
184
+ if (url.hostname === "raw.githubusercontent.com" && parts.length >= 4) {
185
+ if (!parts.at(-1)?.match(/\.(?:md|json)$/))
186
+ throw new Error("The GitHub link must point to a Markdown playbook or JSON team file");
187
+ return [`https://raw.githubusercontent.com/${parts.join("/")}`];
188
+ }
189
+ throw new Error("Paste a GitHub repository, Markdown playbook, or legacy JSON team link");
190
+ }
191
+ export async function fetchGithubTeam(input, fetcher = fetch) {
192
+ const urls = githubManifestUrls(input);
193
+ let lastError;
194
+ for (const url of urls) {
195
+ try {
196
+ return await fetchShareable(url, fetcher);
197
+ }
198
+ catch (error) {
199
+ lastError = error;
200
+ if (error.status !== 404)
201
+ throw error;
202
+ }
203
+ }
204
+ throw lastError ?? new Error("No botmrr.md, team.md, or legacy team file was found in that repository");
205
+ }