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,439 @@
1
+ // A bot may link to a file it created in the workspace for one conversation.
2
+ // Opening that link from a phone must not become a general-purpose host file
3
+ // reader: the HTTP route supplies only roots derived from the exact bot
4
+ // message, and this helper keeps the eventual file handle inside one of them.
5
+ import { constants } from "node:fs";
6
+ import { open, realpath, stat } from "node:fs/promises";
7
+ import { basename, extname, isAbsolute, posix, relative, resolve, sep, win32 } from "node:path";
8
+ import { fileURLToPath } from "node:url";
9
+ import { fromMarkdown } from "mdast-util-from-markdown";
10
+ export const MESSAGE_FILE_MAX_BYTES = 25 * 1024 * 1024;
11
+ export function messageFileRoots(options) {
12
+ const conversationRoot = options.pinnedCwd === undefined ? options.configuredCwd : options.pinnedCwd;
13
+ return [...new Set([
14
+ ...(typeof conversationRoot === "string" ? [conversationRoot] : []),
15
+ options.senderWorkspace,
16
+ options.attachments,
17
+ ])];
18
+ }
19
+ function statusError(status, message) {
20
+ return Object.assign(new Error(message), { status });
21
+ }
22
+ function decodePathWithSuffixRemoved(href) {
23
+ // Split before decoding so an encoded `?` or `#` remains part of the
24
+ // filename, while a real Markdown query/fragment never reaches the file
25
+ // lookup. Decode exactly once so authorization and opening see the same
26
+ // path without making double-encoded input more privileged.
27
+ const path = href.split(/[?#]/, 1)[0];
28
+ if (!path)
29
+ throw statusError(400, "path must be a non-empty file link");
30
+ try {
31
+ return decodeURIComponent(path);
32
+ }
33
+ catch {
34
+ throw statusError(400, "path must be a valid file link");
35
+ }
36
+ }
37
+ function referencedPath(href, portableFileURL = false, allowForwardSlashUNC = true) {
38
+ if (!href || Buffer.byteLength(href) > 8_192 || href.includes("\0")) {
39
+ throw statusError(400, "path must be a non-empty file link");
40
+ }
41
+ // A Windows drive prefix is a path, not a one-letter URL scheme. UNC is
42
+ // also already an absolute local path on Windows and must not be mistaken
43
+ // for a protocol-relative web URL.
44
+ if (/^[a-z]:[\\/]/i.test(href) || href.startsWith("\\\\")) {
45
+ return decodePathWithSuffixRemoved(href);
46
+ }
47
+ // In Markdown, //host/path is a protocol-relative web URL. It is accepted
48
+ // only as the normalized request spelling of an explicit file:// UNC link,
49
+ // never as the authored capability itself.
50
+ if (href.startsWith("//")) {
51
+ if (!allowForwardSlashUNC) {
52
+ throw statusError(400, "protocol-relative web links are not local files");
53
+ }
54
+ return decodePathWithSuffixRemoved(href);
55
+ }
56
+ if (/^[a-z][a-z\d+.-]*:/i.test(href)) {
57
+ let url;
58
+ try {
59
+ url = new URL(href);
60
+ }
61
+ catch {
62
+ throw statusError(400, "path must be a valid file link");
63
+ }
64
+ if (url.protocol !== "file:" || url.username || url.password || url.port || url.search || url.hash) {
65
+ throw statusError(400, "only local file links can be downloaded here");
66
+ }
67
+ if (url.hostname && url.hostname !== "localhost") {
68
+ try {
69
+ return `//${url.hostname}${decodeURIComponent(url.pathname)}`;
70
+ }
71
+ catch {
72
+ throw statusError(400, "path must be a valid file link");
73
+ }
74
+ }
75
+ if (!portableFileURL) {
76
+ try {
77
+ return fileURLToPath(url);
78
+ }
79
+ catch {
80
+ throw statusError(400, "path must be a valid file link");
81
+ }
82
+ }
83
+ try {
84
+ const decoded = decodeURIComponent(url.pathname);
85
+ // WHATWG file URLs always spell drive paths as /C:/..., even when the
86
+ // URL is parsed on macOS or Linux. Strip only that drive sentinel; an
87
+ // ordinary /Users/... URL must remain a POSIX path on every host.
88
+ return /^\/[a-z]:[\\/]/i.test(decoded) ? decoded.slice(1) : decoded;
89
+ }
90
+ catch {
91
+ throw statusError(400, "path must be a valid file link");
92
+ }
93
+ }
94
+ // Query strings and fragments belong to the Markdown link, not the local
95
+ // filename. Percent-encoding is common for spaces in relative hrefs.
96
+ return decodePathWithSuffixRemoved(href);
97
+ }
98
+ /**
99
+ * A lexical path identity used only for matching a requested file against a
100
+ * rendered Markdown link. Native `resolve` and `fileURLToPath` follow the
101
+ * runner OS, which makes a Unix link compare differently on Windows CI and a
102
+ * Windows link compare differently on macOS. Keeping the path flavour in the
103
+ * identity also prevents a POSIX path such as `/C:/notes.md` from being
104
+ * mistaken for the Windows path `C:\\notes.md`.
105
+ */
106
+ function referencedPathIdentity(href, allowForwardSlashUNC = true) {
107
+ const path = referencedPath(href, true, allowForwardSlashUNC);
108
+ if (/^[a-z]:[\\/]/i.test(path) || path.startsWith("\\\\") || path.startsWith("//")) {
109
+ return `windows:${win32.resolve(path)}`;
110
+ }
111
+ if (path.startsWith("/"))
112
+ return `posix:${posix.resolve(path)}`;
113
+ return `relative:${posix.normalize(path)}`;
114
+ }
115
+ function walkMarkdown(node, visit) {
116
+ const pending = [node];
117
+ while (pending.length > 0) {
118
+ const current = pending.pop();
119
+ visit(current);
120
+ const children = current.children ?? [];
121
+ for (let index = children.length - 1; index >= 0; index -= 1) {
122
+ pending.push(children[index]);
123
+ }
124
+ }
125
+ }
126
+ function renderedMarkdownTargets(markdown) {
127
+ const definitions = new Map();
128
+ const links = [];
129
+ const references = [];
130
+ walkMarkdown(fromMarkdown(markdown), (node) => {
131
+ if (node.type === "definition" && node.identifier && node.url) {
132
+ if (!definitions.has(node.identifier))
133
+ definitions.set(node.identifier, node.url);
134
+ }
135
+ else if ((node.type === "link" || node.type === "image") && node.url) {
136
+ links.push(node.url);
137
+ }
138
+ else if ((node.type === "linkReference" || node.type === "imageReference") && node.identifier) {
139
+ references.push(node.identifier);
140
+ }
141
+ });
142
+ for (const identifier of references) {
143
+ const target = definitions.get(identifier);
144
+ if (target)
145
+ links.push(target);
146
+ }
147
+ return links;
148
+ }
149
+ /** Resolve the local image authored at one Markdown source offset. The
150
+ * browser can use this small message-scoped reference instead of putting an
151
+ * absolute host path in a GET URL. Definitions are collected first because
152
+ * CommonMark permits them to appear after the image reference. */
153
+ export function messageImageTargetAt(text, sourceOffset) {
154
+ if (!Number.isSafeInteger(sourceOffset) || sourceOffset < 0)
155
+ return null;
156
+ const definitions = new Map();
157
+ let direct = null;
158
+ let reference = null;
159
+ walkMarkdown(fromMarkdown(text), (node) => {
160
+ if (node.type === "definition" && node.identifier && node.url) {
161
+ if (!definitions.has(node.identifier))
162
+ definitions.set(node.identifier, node.url);
163
+ return;
164
+ }
165
+ if (node.position?.start.offset !== sourceOffset)
166
+ return;
167
+ if (node.type === "image" && node.url)
168
+ direct = node.url;
169
+ else if (node.type === "imageReference" && node.identifier)
170
+ reference = node.identifier;
171
+ });
172
+ return direct ?? (reference ? definitions.get(reference) ?? null : null);
173
+ }
174
+ /**
175
+ * Confirm that the requested path is carried by this message, tolerating the
176
+ * one representation change native URL APIs make for us: a file href with
177
+ * percent-encoded spaces arrives from iOS as a decoded filesystem path.
178
+ * Normalisation is applied only to rendered Markdown link targets, never to
179
+ * arbitrary prose in the message.
180
+ */
181
+ export function messageReferencesFile(text, requested) {
182
+ let wanted;
183
+ try {
184
+ wanted = referencedPathIdentity(requested);
185
+ }
186
+ catch {
187
+ return false;
188
+ }
189
+ for (const target of renderedMarkdownTargets(text)) {
190
+ try {
191
+ if (referencedPathIdentity(target, false) === wanted)
192
+ return true;
193
+ }
194
+ catch {
195
+ // A malformed candidate is not the link the client asked to open.
196
+ }
197
+ }
198
+ return false;
199
+ }
200
+ /** Decode exactly the entity spellings emitted by the composer. A single
201
+ * pass is intentional: double-encoded input must not turn into a path only
202
+ * while it is being authorised. */
203
+ function decodeAttachmentAttribute(value) {
204
+ return value.replace(/&(quot|lt|gt|amp);|&#(9|10|13);/g, (entity, named, numeric) => {
205
+ if (numeric === "9")
206
+ return "\t";
207
+ if (numeric === "10")
208
+ return "\n";
209
+ if (numeric === "13")
210
+ return "\r";
211
+ if (named === "quot")
212
+ return '"';
213
+ if (named === "lt")
214
+ return "<";
215
+ if (named === "gt")
216
+ return ">";
217
+ if (named === "amp")
218
+ return "&";
219
+ return entity;
220
+ });
221
+ }
222
+ function utf8Prefix(value, maximumBytes) {
223
+ let bytes = 0;
224
+ let result = "";
225
+ for (const character of value) {
226
+ const size = Buffer.byteLength(character);
227
+ if (bytes + size > maximumBytes)
228
+ break;
229
+ result += character;
230
+ bytes += size;
231
+ }
232
+ return result;
233
+ }
234
+ /** Keep the eventual native filename below common 255-byte component limits.
235
+ * 180 bytes leaves room for the app's temporary-file suffix. */
236
+ function boundedDisplayName(value, maximumBytes = 180) {
237
+ if (Buffer.byteLength(value) <= maximumBytes)
238
+ return value;
239
+ const extension = extname(value);
240
+ const extensionBytes = Buffer.byteLength(extension);
241
+ if (extension && extensionBytes <= 32 && extensionBytes < maximumBytes) {
242
+ const stem = utf8Prefix(value.slice(0, -extension.length), maximumBytes - extensionBytes);
243
+ if (stem)
244
+ return `${stem}${extension}`;
245
+ }
246
+ return utf8Prefix(value, maximumBytes) || "download";
247
+ }
248
+ function safeDisplayName(value) {
249
+ const portable = value.split(/[\\/]/).at(-1) ?? "";
250
+ const clean = Array.from(portable, (character) => {
251
+ const code = character.codePointAt(0) ?? 0;
252
+ const invalid = code <= 31 || (code >= 127 && code <= 159)
253
+ || (code >= 0xd800 && code <= 0xdfff)
254
+ || (code >= 0x202a && code <= 0x202e)
255
+ || (code >= 0x2066 && code <= 0x2069);
256
+ return invalid ? "_" : character;
257
+ }).join("").trim();
258
+ return boundedDisplayName(clean || "download");
259
+ }
260
+ /**
261
+ * Confirm that a stored user message carries the requested attachment as an
262
+ * exact standalone transport tag. Plain prose, inline examples, fenced code,
263
+ * and near-matching paths do not grant access. The HTTP route pairs this
264
+ * message capability with ATTACHMENTS_DIR containment, so this can never
265
+ * become an arbitrary host-file reader.
266
+ */
267
+ export function messageReferencesAttachment(text, requested) {
268
+ return messageAttachmentName(text, requested) !== null;
269
+ }
270
+ /** Return the user-facing name carried by an authorised attachment tag. */
271
+ export function messageAttachmentName(text, requested) {
272
+ let wanted;
273
+ try {
274
+ wanted = referencedPathIdentity(requested);
275
+ }
276
+ catch {
277
+ return null;
278
+ }
279
+ const tag = /^<attached-(?:image|file)[\t ]+path="([^"\r\n]*)"(?:[\t ]+name="([^"\r\n]*)")?[\t ]*\/>$/;
280
+ let found = null;
281
+ walkMarkdown(fromMarkdown(text), (node) => {
282
+ if (found !== null)
283
+ return;
284
+ if (node.type !== "html" || !node.value || !node.position)
285
+ return;
286
+ const start = node.position.start.offset;
287
+ const end = node.position.end.offset;
288
+ if (start === undefined || end === undefined)
289
+ return;
290
+ const lineStart = text.lastIndexOf("\n", start - 1) + 1;
291
+ const nextLine = text.indexOf("\n", end);
292
+ const lineEnd = nextLine < 0 ? text.length : nextLine;
293
+ if (text.slice(lineStart, start).trim() || text.slice(end, lineEnd).trim())
294
+ return;
295
+ const match = tag.exec(node.value);
296
+ if (!match)
297
+ return;
298
+ try {
299
+ if (referencedPathIdentity(decodeAttachmentAttribute(match[1])) === wanted) {
300
+ found = safeDisplayName(match[2]
301
+ ? decodeAttachmentAttribute(match[2])
302
+ : decodeAttachmentAttribute(match[1]));
303
+ }
304
+ }
305
+ catch {
306
+ // A malformed transport tag grants no capability.
307
+ }
308
+ });
309
+ return found;
310
+ }
311
+ function containedBy(root, candidate) {
312
+ const suffix = relative(root, candidate);
313
+ return suffix === "" || (suffix !== ".." && !suffix.startsWith(`..${sep}`) && !isAbsolute(suffix));
314
+ }
315
+ function mimeFor(path) {
316
+ switch (extname(path).toLowerCase()) {
317
+ case ".md": return "text/markdown; charset=utf-8";
318
+ case ".txt": return "text/plain; charset=utf-8";
319
+ case ".csv": return "text/csv; charset=utf-8";
320
+ case ".tsv": return "text/tab-separated-values; charset=utf-8";
321
+ case ".json": return "application/json";
322
+ case ".pdf": return "application/pdf";
323
+ case ".rtf": return "application/rtf";
324
+ case ".png": return "image/png";
325
+ case ".jpg":
326
+ case ".jpeg": return "image/jpeg";
327
+ case ".gif": return "image/gif";
328
+ case ".webp": return "image/webp";
329
+ case ".doc": return "application/msword";
330
+ case ".docx": return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
331
+ case ".xls": return "application/vnd.ms-excel";
332
+ case ".xlsx": return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
333
+ case ".ppt": return "application/vnd.ms-powerpoint";
334
+ case ".pptx": return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
335
+ case ".odt": return "application/vnd.oasis.opendocument.text";
336
+ case ".ods": return "application/vnd.oasis.opendocument.spreadsheet";
337
+ case ".odp": return "application/vnd.oasis.opendocument.presentation";
338
+ default: return "application/octet-stream";
339
+ }
340
+ }
341
+ /**
342
+ * Open a message-linked file under one of the supplied roots. The returned
343
+ * handle, not the pathname, is what the caller streams. We canonicalise both
344
+ * before and after opening and compare the handle with the post-open path;
345
+ * this rejects symlink escapes and directory swaps instead of checking a
346
+ * path and then opening a potentially different file.
347
+ */
348
+ export async function openMessageFile(href, roots) {
349
+ const requested = referencedPath(href);
350
+ const canonicalRoots = (await Promise.all(roots.map(async (root) => {
351
+ try {
352
+ const canonical = await realpath(root);
353
+ return (await stat(canonical)).isDirectory() ? canonical : null;
354
+ }
355
+ catch {
356
+ return null;
357
+ }
358
+ }))).filter((root) => Boolean(root));
359
+ if (canonicalRoots.length === 0)
360
+ throw statusError(404, "the linked file is unavailable");
361
+ const candidates = isAbsolute(requested)
362
+ ? [resolve(requested)]
363
+ : canonicalRoots.map((root) => resolve(root, requested));
364
+ let sawOutsideRoot = false;
365
+ for (const candidate of new Set(candidates)) {
366
+ let canonicalBefore;
367
+ try {
368
+ canonicalBefore = await realpath(candidate);
369
+ }
370
+ catch {
371
+ continue;
372
+ }
373
+ const root = canonicalRoots.find((allowed) => containedBy(allowed, canonicalBefore));
374
+ if (!root) {
375
+ sawOutsideRoot = true;
376
+ continue;
377
+ }
378
+ let handle;
379
+ try {
380
+ const noFollow = typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
381
+ handle = await open(canonicalBefore, constants.O_RDONLY | noFollow);
382
+ const opened = await handle.stat();
383
+ if (!opened.isFile())
384
+ throw statusError(400, "the link does not point to a regular file");
385
+ if (opened.size > MESSAGE_FILE_MAX_BYTES) {
386
+ throw statusError(413, `file exceeds ${MESSAGE_FILE_MAX_BYTES} bytes`);
387
+ }
388
+ const canonicalAfter = await realpath(candidate);
389
+ if (!containedBy(root, canonicalAfter))
390
+ throw statusError(403, "the linked file is outside this conversation's workspace");
391
+ const after = await stat(canonicalAfter);
392
+ if (opened.dev !== after.dev || opened.ino !== after.ino) {
393
+ throw statusError(409, "the linked file changed while it was being opened");
394
+ }
395
+ return {
396
+ handle,
397
+ bytes: opened.size,
398
+ name: basename(canonicalAfter),
399
+ mime: mimeFor(canonicalAfter),
400
+ };
401
+ }
402
+ catch (error) {
403
+ await handle?.close().catch(() => undefined);
404
+ if (error && typeof error === "object" && "status" in error)
405
+ throw error;
406
+ continue;
407
+ }
408
+ }
409
+ if (sawOutsideRoot)
410
+ throw statusError(403, "the linked file is outside this conversation's workspace");
411
+ throw statusError(404, "the linked file is unavailable");
412
+ }
413
+ /** A safe attachment header with a readable ASCII fallback and UTF-8 name. */
414
+ export function messageFileDisposition(name) {
415
+ const safeName = safeDisplayName(name);
416
+ const fallback = safeName
417
+ .normalize("NFKD")
418
+ .replace(/[^\x20-\x7e]/g, "_")
419
+ .replace(/["\\]/g, "_")
420
+ .slice(0, 180) || "download";
421
+ const encoded = encodeURIComponent(safeName).replace(/[!'()*]/g, (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`);
422
+ return `attachment; filename="${fallback}"; filename*=UTF-8''${encoded}`;
423
+ }
424
+ /** Keep a friendly transport name without allowing it to disguise the bytes'
425
+ * canonical extension (for example PDF bytes named setup.exe). */
426
+ export function messageFileDownloadName(displayName, canonicalName) {
427
+ const canonical = safeDisplayName(canonicalName);
428
+ if (!displayName)
429
+ return canonical;
430
+ const display = safeDisplayName(displayName);
431
+ const actualExtension = extname(canonical);
432
+ if (!actualExtension)
433
+ return canonical;
434
+ if (extname(display).toLowerCase() === actualExtension.toLowerCase())
435
+ return display;
436
+ const displayExtension = extname(display);
437
+ const stem = displayExtension ? display.slice(0, -displayExtension.length) : display;
438
+ return safeDisplayName(`${stem || "download"}${actualExtension}`);
439
+ }
@@ -0,0 +1,26 @@
1
+ // Bot name generator — a curated local list beats a naming API: instant,
2
+ // offline, and every name is on-brand (short, friendly, a little pet-like,
3
+ // which suits the Maus). Picks avoid names already in use; when the pool is
4
+ // exhausted it falls back to "Name 2", "Name 3", …
5
+ const NAMES = [
6
+ "Scout", "Pixel", "Atlas", "Nova", "Juno", "Koda", "Miso", "Mochi",
7
+ "Biscuit", "Pepper", "Clover", "Ember", "Willow", "Comet", "Orbit", "Echo",
8
+ "Indigo", "Sage", "Zephyr", "Poppy", "Maple", "Cosmo", "Luna", "Otto",
9
+ "Ivy", "Finch", "Wren", "Basil", "Hazel", "Nimbus", "Onyx", "Pearl",
10
+ "Quill", "Rocket", "Sunny", "Tango", "Vega", "Waffle", "Ziggy", "Noodle",
11
+ "Pickle", "Churro", "Panko", "Dumpling", "Pesto", "Olive", "Cocoa", "Taffy",
12
+ "Bramble", "Fig", "Juniper", "Moss", "Pebble", "Rio", "Skye", "Tuli",
13
+ "Ursa", "Yuki", "Zuko", "Momo", "Kiwi", "Plum", "Sprout", "Turnip",
14
+ ];
15
+ export function pickBotName(taken) {
16
+ const used = new Set([...taken].map((n) => n.trim().toLowerCase()));
17
+ const free = NAMES.filter((n) => !used.has(n.toLowerCase()));
18
+ if (free.length > 0)
19
+ return free[Math.floor(Math.random() * free.length)];
20
+ // pool exhausted — number a random base name
21
+ const base = NAMES[Math.floor(Math.random() * NAMES.length)];
22
+ for (let i = 2;; i++) {
23
+ if (!used.has(`${base.toLowerCase()} ${i}`))
24
+ return `${base} ${i}`;
25
+ }
26
+ }
@@ -0,0 +1,69 @@
1
+ // Notifications — what is worth interrupting someone for.
2
+ //
3
+ // `BotRecord.notifications` has been a switch in the settings panel that
4
+ // nothing read. This is the thing that reads it. The rule it encodes is
5
+ // small and deliberate: a bot that is *blocked on you* is worth a buzz, and
6
+ // a bot that *finished* is worth one if you asked for it; everything else a
7
+ // bot does while it works is not.
8
+ //
9
+ // A turn that dies before it starts is the first case, not the last: the
10
+ // bot is not working, and the fix is usually a setting only a person can
11
+ // change, so a retry cannot clear it. A routine failure already buzzed;
12
+ // this makes an interactive turn behave the same way.
13
+ //
14
+ // Delivery is a separate concern. The harness emits a frame; whoever is
15
+ // listening decides what to do with it — desktop and paired-phone local
16
+ // notifications today, and closed-app APNs delivery once a relay exists.
17
+ /** One line, short enough for a lock screen, with the newlines and code
18
+ * fences of a model's answer flattened out of it. */
19
+ export function summarize(text, max = 140) {
20
+ const line = text.replace(/```[\s\S]*?```/g, " ").replace(/\s+/g, " ").trim();
21
+ return line.length > max ? `${line.slice(0, max - 1).trimEnd()}…` : line;
22
+ }
23
+ /** Where a "blocked on you" notification has to open. A bot speaking in a
24
+ * room is not reachable in its own 1:1 thread — the turn, its screen and the
25
+ * card all live in the room — so the room wins while it owns that bot. A
26
+ * room it merely belongs to, or one another member is speaking in, is not
27
+ * where this bot is: those fall back to its own thread. */
28
+ export function blockedTarget(bot, room) {
29
+ if (!room || room.busyBotId !== bot.id)
30
+ return { threadId: bot.threadId };
31
+ return { threadId: room.threadId, group: { id: room.id, name: room.name } };
32
+ }
33
+ /** Build the frame for one event, or null when it should stay quiet.
34
+ *
35
+ * Kept pure and separate from the event fold so the policy — which is the
36
+ * part people will argue about — can be read and tested on its own. */
37
+ export function buildNotification(kind, bot, threadId, detail, extra) {
38
+ // The toggle means what it says: off is off, including for approvals.
39
+ // A bot whose notifications you turned off can still block waiting for
40
+ // you — that is the choice you made, and the chat still shows the card.
41
+ if (bot.notifications === false)
42
+ return null;
43
+ const body = summarize(detail);
44
+ // A bot working in a room is not "Scout" to whoever reads the banner — it
45
+ // is Scout, in that room. Name the room or the notification reads as if it
46
+ // came from the 1:1 thread it will not open.
47
+ const who = extra?.group ? `${bot.name} in ${extra.group.name}` : bot.name;
48
+ const title = kind === "approval"
49
+ ? `${who} needs approval`
50
+ : kind === "question"
51
+ ? `${who} has a question`
52
+ : kind === "takeover"
53
+ ? `${who} needs your hands`
54
+ : kind === "routine-failed"
55
+ ? `${who}'s routine failed`
56
+ : kind === "turn-failed"
57
+ ? `${who} couldn't start`
58
+ : `${who} finished`;
59
+ // A "finished" with nothing to say is not worth a notification — the
60
+ // badge in the sidebar already carries that much.
61
+ if (kind === "done" && !body)
62
+ return null;
63
+ const notification = { kind, botId: bot.id, botName: bot.name, threadId, title, body };
64
+ if (extra?.avatarUrl)
65
+ notification.avatarUrl = extra.avatarUrl;
66
+ if (extra?.group)
67
+ notification.groupId = extra.group.id;
68
+ return notification;
69
+ }