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,96 @@
1
+ export const RETRY_MAX_ATTEMPTS = 3;
2
+ /** Backoff schedule before attempt N (N is 1-based over retries): 1s / 3s / 8s. */
3
+ export const BACKOFF_BASE_MS = [1_000, 3_000, 8_000];
4
+ const TRANSIENT_PATTERNS = [
5
+ { pattern: /\b(?:429|rate.?limit|too many requests)\b/i, reason: "rate_limited" },
6
+ { pattern: /\boverloaded\b|\bcapacity\b/i, reason: "overloaded" },
7
+ { pattern: /\b5\d{2}\b|\binternal server error\b|\bbad gateway\b|\bservice unavailable\b/i, reason: "server_error" },
8
+ {
9
+ pattern: /\b(?:econnreset|econnrefused|epipe|etimedout|eai_again|connection reset|connection refused|socket hang up|network error|fetch failed)\b/i,
10
+ reason: "connection_reset",
11
+ },
12
+ { pattern: /\btimeout(ed)?\b|\btimed? out\b/i, reason: "timeout" },
13
+ ];
14
+ const TERMINAL_PATTERNS = [
15
+ {
16
+ pattern: /\b(?:40[13]|unauthorized|forbidden|invalid api key|missing bearer|authentication required|not logged in|logged out)\b/i,
17
+ reason: "auth",
18
+ },
19
+ { pattern: /\b402\b|\bquota\b|\bbilling\b|\bsubscription\b/i, reason: "quota" },
20
+ { pattern: /\bmodel not found\b|\bunknown model\b|\bdoes not exist for model\b|\bunsupported model\b/i, reason: "unknown_model" },
21
+ { pattern: /\b400\b|\b422\b|\binvalid request\b|\bmalformed\b|\bunexpected status\b/i, reason: "invalid_request" },
22
+ { pattern: /\b404\b|\bno such thread\b|\bthread gone\b/i, reason: "not_found" },
23
+ // interrupt/cancel vocabulary from the drivers' own stop paths — a turn the
24
+ // user stopped must never come back as an auto-retry
25
+ { pattern: /\b(?:interrupted|cancelled by user)\b/i, reason: "interrupted" },
26
+ ];
27
+ const messageOf = (err) => {
28
+ if (!err)
29
+ return "";
30
+ if (err instanceof Error)
31
+ return `${err.message}${err.cause ? ` ${String(err.cause)}` : ""}`;
32
+ if ("text" in err)
33
+ return err.text;
34
+ return [err.stderr ?? "", ""].join(" ").trim();
35
+ };
36
+ /** Classify a thrown error or a CLI exit into retry-worthy vs terminal.
37
+ *
38
+ * Exit-report shape: a nonzero exit with no error text is treated as
39
+ * terminal (`terminal_exit`) — drivers only reach it after the CLI already
40
+ * reported its own protocol-level failure. A signal kill (negative code) is
41
+ * never retried either.
42
+ */
43
+ export function classifyError(err) {
44
+ const text = messageOf(err);
45
+ if (err && "exitCode" in err) {
46
+ const { exitCode: code } = err;
47
+ if (code !== null && code < 0)
48
+ return { transient: false, reason: "interrupted" };
49
+ for (const { pattern, reason } of TRANSIENT_PATTERNS) {
50
+ if (pattern.test(text))
51
+ return { transient: true, reason };
52
+ }
53
+ for (const { pattern, reason } of TERMINAL_PATTERNS) {
54
+ if (pattern.test(text))
55
+ return { transient: false, reason };
56
+ }
57
+ return { transient: false, reason: "terminal_exit" };
58
+ }
59
+ for (const { pattern, reason } of TERMINAL_PATTERNS) {
60
+ if (pattern.test(text))
61
+ return { transient: false, reason };
62
+ }
63
+ for (const { pattern, reason } of TRANSIENT_PATTERNS) {
64
+ if (pattern.test(text))
65
+ return { transient: true, reason };
66
+ }
67
+ return { transient: false, reason: "unknown" };
68
+ }
69
+ /** Capped exponential delay with jitter, in milliseconds. Attempt 0 (the
70
+ * first retry) waits ~1s, then ~3s, then ~8s; beyond that the cap holds.
71
+ * Jitter stays within ±25% so tests can bound it and a thundering herd of
72
+ * bots doesn't re-sync on the same tick. */
73
+ export function computeBackoff(attempt, random = Math.random) {
74
+ const base = BACKOFF_BASE_MS[Math.min(Math.max(attempt, 0), BACKOFF_BASE_MS.length - 1)];
75
+ const jitter = base * 0.25;
76
+ return Math.round(base - jitter + random() * jitter * 2);
77
+ }
78
+ export function interruptibleDelay(ms, signal) {
79
+ let timer = null;
80
+ let onCancel = null;
81
+ const promise = new Promise((resolve) => {
82
+ timer = setTimeout(() => resolve("elapsed"), Math.max(1, ms));
83
+ timer.unref?.();
84
+ if (signal?.aborted)
85
+ return resolve("cancelled");
86
+ onCancel = () => {
87
+ clearTimeout(timer);
88
+ resolve("cancelled");
89
+ };
90
+ signal?.addEventListener("abort", onCancel, { once: true });
91
+ });
92
+ return {
93
+ promise,
94
+ cancel: () => onCancel?.(),
95
+ };
96
+ }
@@ -0,0 +1,93 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ // Neutral hook point for the source-available enterprise layer.
10
+ //
11
+ // The layer lives in ../enterprise (its own LICENSE) and is loaded only if that
12
+ // folder is present: delete it and this file still compiles, the server still
13
+ // starts, and /api/edition reports the open-source edition. Core never imports
14
+ // the layer statically, so the bundle and the packaged app carry no trace of it.
15
+ // The layer's only obligation is `register()`, which turns OMB_LICENSE_KEY into
16
+ // entitlements; core keeps the resulting status and answers `entitled()`.
17
+ import { existsSync } from "node:fs";
18
+ import { join } from "node:path";
19
+ import { pathToFileURL } from "node:url";
20
+ import { z } from "zod";
21
+ import { SERVER_ROOT } from "./proxy-paths.js";
22
+ /** What the enterprise layer's register() must return; validated because it is external code. */
23
+ const layerSchema = z.object({
24
+ customer: z.string().min(1),
25
+ features: z.array(z.string().min(1)),
26
+ expiresAt: z.string().nullable(),
27
+ });
28
+ const DEFAULT_DIR = join(SERVER_ROOT, "..", "enterprise");
29
+ let current = { edition: "oss", features: [] };
30
+ function oss(notice) {
31
+ current = notice ? { edition: "oss", features: [], notice } : { edition: "oss", features: [] };
32
+ return current;
33
+ }
34
+ /** Resolve the edition once at startup. Never throws: a broken layer or key
35
+ * degrades to the open-source edition with a notice that says what to fix. */
36
+ export async function loadEnterpriseLayer(options = {}) {
37
+ const dir = options.dir ?? process.env.OMB_ENTERPRISE_DIR ?? DEFAULT_DIR;
38
+ const licenseKey = options.licenseKey ?? process.env.OMB_LICENSE_KEY;
39
+ // Source in a checkout, a compiled bundle in an image: same convention as proxy-paths.ts.
40
+ const entry = [join(dir, "server", "index.ts"), join(dir, "server", "index.js")].find((candidate) => existsSync(candidate));
41
+ if (!entry) {
42
+ return oss(licenseKey ? `OMB_LICENSE_KEY is set but no enterprise layer exists at ${dir}` : undefined);
43
+ }
44
+ try {
45
+ const loaded = await import(__rewriteRelativeImportExtension(pathToFileURL(entry).href));
46
+ const register = Reflect.get(Object(loaded), "register");
47
+ if (typeof register !== "function")
48
+ throw new Error(`${entry} does not export register()`);
49
+ if (!licenseKey)
50
+ return oss("enterprise layer present but OMB_LICENSE_KEY is not set");
51
+ const registered = await register({ licenseKey });
52
+ const layer = layerSchema.parse(registered);
53
+ current = {
54
+ edition: "enterprise",
55
+ customer: layer.customer,
56
+ features: [...new Set(layer.features)].sort(),
57
+ expiresAt: layer.expiresAt,
58
+ };
59
+ return current;
60
+ }
61
+ catch (error) {
62
+ return oss(`enterprise layer disabled: ${error instanceof Error ? error.message : String(error)}`);
63
+ }
64
+ }
65
+ /** A license that expires while the server keeps running stops granting
66
+ * features at that moment, not at the next restart. */
67
+ function expired(now) {
68
+ if (current.edition !== "enterprise" || !current.expiresAt)
69
+ return false;
70
+ return now >= new Date(current.expiresAt).getTime();
71
+ }
72
+ export function editionStatus(now = Date.now()) {
73
+ if (!expired(now))
74
+ return current;
75
+ return {
76
+ edition: "oss",
77
+ features: [],
78
+ notice: `enterprise layer disabled: OMB_LICENSE_KEY expired on ${current.expiresAt}; renew it to keep enterprise features`,
79
+ };
80
+ }
81
+ /** Feature gates in core ask this and nothing else. Unknown ids are simply not
82
+ * granted, and the open-source edition always carries an empty feature list. */
83
+ export function entitled(feature, now = Date.now()) {
84
+ return !expired(now) && current.features.includes(feature);
85
+ }
86
+ /** One line for the startup log. */
87
+ export function describeEdition(status) {
88
+ if (status.edition === "enterprise") {
89
+ const until = status.expiresAt ? ` until ${status.expiresAt}` : "";
90
+ return `openmausbot enterprise edition for ${status.customer}${until}: ${status.features.join(", ") || "no features"}`;
91
+ }
92
+ return `openmausbot open-source edition${status.notice ? ` (${status.notice})` : ""}`;
93
+ }
@@ -0,0 +1,329 @@
1
+ // PATH augmentation for GUI launches — the fix for "CLI not found" when
2
+ // the app is opened from Finder (issues #8, #12).
3
+ //
4
+ // A macOS app launched from Finder inherits a bare PATH
5
+ // (/usr/bin:/bin:...): no ~/.local/bin (the claude installer default),
6
+ // no /opt/homebrew/bin, and no nvm/volta/asdf shims — those only exist
7
+ // in interactive shells. The terminal sees the CLIs; the packaged app
8
+ // doesn't. So every spawn of an agent CLI goes through augmentedPath():
9
+ // the inherited PATH, plus the well-known install locations that exist
10
+ // on this machine, plus (async, best-effort) whatever PATH the user's
11
+ // real login shell reports.
12
+ import { execFile } from "node:child_process";
13
+ import { closeSync, existsSync, openSync, readFileSync, readSync, statSync, readdirSync } from "node:fs";
14
+ import { homedir } from "node:os";
15
+ import { basename, delimiter, dirname, extname, join } from "node:path";
16
+ /** nvm keeps every node version's bin dir separately; newest first so a
17
+ * CLI installed under the latest node wins. */
18
+ function nvmBinDirs() {
19
+ try {
20
+ const base = join(homedir(), ".nvm", "versions", "node");
21
+ return readdirSync(base)
22
+ .filter((v) => v.startsWith("v"))
23
+ .sort((a, b) => b.localeCompare(a, undefined, { numeric: true }))
24
+ .map((v) => join(base, v, "bin"));
25
+ }
26
+ catch {
27
+ return [];
28
+ }
29
+ }
30
+ function knownDirs() {
31
+ const home = homedir();
32
+ return [
33
+ join(home, ".local", "bin"), // claude installer default
34
+ join(home, ".npm-global", "bin"), // npm prefix ~/.npm-global (claude, opencode)
35
+ join(home, ".kimi-code", "bin"), // kimi-code installer
36
+ join(home, ".grok", "bin"), // x.ai installer
37
+ join(home, ".opencode", "bin"), // opencode installer
38
+ join(home, ".claude", "local"), // claude "local install"
39
+ "/opt/homebrew/bin", // brew, Apple silicon
40
+ "/usr/local/bin", // brew Intel / classic installs
41
+ join(home, ".volta", "bin"),
42
+ join(home, ".bun", "bin"),
43
+ join(home, ".asdf", "shims"),
44
+ join(home, ".deno", "bin"),
45
+ join(home, "bin"),
46
+ ...nvmBinDirs(),
47
+ ];
48
+ }
49
+ /** Windows equivalents of knownDirs. A GUI app inherits the user PATH at
50
+ * launch, but only at launch: a CLI installed while the app is running is
51
+ * invisible until it restarts, because Windows never pushes PATH changes
52
+ * into a live process. Scanning the standard install locations recovers
53
+ * those without a restart — `~/.grok/bin` (the x.ai installer) and
54
+ * `%APPDATA%\npm` (global npm shims), plus `%LOCALAPPDATA%\agy\bin`, cover
55
+ * every engine we ship an install command for. */
56
+ function windowsKnownDirs() {
57
+ const home = homedir();
58
+ const appData = process.env.APPDATA ?? join(home, "AppData", "Roaming");
59
+ const localAppData = process.env.LOCALAPPDATA ?? join(home, "AppData", "Local");
60
+ return [
61
+ join(appData, "npm"), // npm -g shims: claude, codex
62
+ join(home, ".grok", "bin"), // x.ai installer
63
+ join(localAppData, "agy", "bin"), // Antigravity installer
64
+ join(home, ".local", "bin"), // claude native installer
65
+ join(home, ".claude", "local"),
66
+ join(home, "bin"), // Factory droid installer (%USERPROFILE%\bin)
67
+ join(home, ".bun", "bin"),
68
+ join(home, ".deno", "bin"),
69
+ join(home, "go", "bin"),
70
+ ];
71
+ }
72
+ let cached = null;
73
+ let probed = false;
74
+ let loginShellPath = null;
75
+ /** Drop the memoized PATH so the next augmentedPath() rescans. Called when
76
+ * the app re-probes engines, so "check again" can find something installed
77
+ * since launch instead of answering from the PATH we booted with. `probed`
78
+ * must reset too: the login-shell probe merges rc-file PATH entries (e.g.
79
+ * ~/.kimi-code/bin exported from .zshrc) into the cache asynchronously,
80
+ * and without resetting it a rescan would rebuild the cache without those
81
+ * entries and never re-probe — "check again" would permanently lose
82
+ * anything only the login shell's rc file knows about. */
83
+ export function resetPathCache() {
84
+ cached = null;
85
+ probed = false;
86
+ }
87
+ /** Current best PATH, synchronously. Cheap after the first call. */
88
+ export function augmentedPath() {
89
+ if (cached === null) {
90
+ cached = mergePaths([
91
+ ...(process.env.OMB_EXTRA_PATH ? process.env.OMB_EXTRA_PATH.split(delimiter) : []),
92
+ ...(process.env.PATH ? process.env.PATH.split(delimiter) : []),
93
+ // Keep the last successful login-shell result while a rescan starts a
94
+ // fresh asynchronous probe. Otherwise resetPathCache() would make
95
+ // rc-only CLIs disappear again for the response that triggered it.
96
+ ...(loginShellPath ? loginShellPath.split(delimiter) : []),
97
+ // Both platforms scan their standard install locations; only the
98
+ // login-shell probe below stays unix-only, since Windows has no
99
+ // equivalent rc file to source.
100
+ ...(process.platform === "win32" ? windowsKnownDirs() : knownDirs()).filter((d) => existsSync(d)),
101
+ ]);
102
+ }
103
+ // belt-and-braces: fold in the login shell's PATH once, in the
104
+ // background — catches anything the known-dirs list doesn't (custom
105
+ // rc exports). Never blocks a spawn; the next one benefits.
106
+ if (!probed && !process.env.VITEST && process.platform !== "win32") {
107
+ probed = true;
108
+ probeLoginShellPath();
109
+ }
110
+ return cached;
111
+ }
112
+ function mergePaths(parts) {
113
+ return [...new Set(parts.filter(Boolean))].join(delimiter);
114
+ }
115
+ function probeLoginShellPath() {
116
+ const shell = process.env.SHELL || "/bin/zsh";
117
+ // -l -i: nvm and friends live in .zshrc/.bashrc, which only interactive
118
+ // shells read. A marker isolates $PATH from any rc-file noise.
119
+ execFile(shell, ["-l", "-i", "-c", 'printf "__OMB_PATH__%s" "$PATH"'], { timeout: 5000 }, (err, stdout) => {
120
+ if (err || !stdout)
121
+ return;
122
+ const m = /__OMB_PATH__([^\n]*)/.exec(stdout);
123
+ if (!m || !m[1])
124
+ return;
125
+ loginShellPath = m[1];
126
+ cached = mergePaths([...(cached ?? "").split(delimiter), ...m[1].split(delimiter)]);
127
+ });
128
+ }
129
+ /** Test hook — the cache is process-wide otherwise. */
130
+ export function resetPathCacheForTests() {
131
+ cached = null;
132
+ probed = false;
133
+ loginShellPath = null;
134
+ }
135
+ /** Every `name` binary on the augmented PATH as absolute paths, in PATH
136
+ * order (first = what a bare name would run). Used by the Engines panel's
137
+ * "detected" dropdown and the /api/cli-candidates endpoint. A path-ish
138
+ * name is echoed back as-is — it already IS a location. */
139
+ export function findCliCandidates(name) {
140
+ if (!name || /[\n\r]/.test(name))
141
+ return [];
142
+ if (/[/\\]/.test(name) || /^[a-zA-Z]:/.test(name))
143
+ return [name];
144
+ const exts = process.platform === "win32" ? (process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
145
+ const out = [];
146
+ for (const dir of augmentedPath().split(delimiter)) {
147
+ if (!dir)
148
+ continue;
149
+ for (const ext of exts) {
150
+ const p = join(dir, name + ext);
151
+ if (existsSync(p)) {
152
+ out.push(p);
153
+ break;
154
+ }
155
+ }
156
+ }
157
+ return out;
158
+ }
159
+ /** Split a `cli` string into [command, ...fixedArgs] on unquoted whitespace —
160
+ * a mini tokenizer, never a shell. Quotes group segments (paths with spaces,
161
+ * fixed args with spaces); no escapes, no substitution, nothing evaluated. */
162
+ export function splitCliString(cli) {
163
+ const out = [];
164
+ let cur = "";
165
+ let quote = null;
166
+ for (const ch of cli.trim()) {
167
+ if (quote) {
168
+ if (ch === quote)
169
+ quote = null;
170
+ else
171
+ cur += ch;
172
+ }
173
+ else if (ch === '"' || ch === "'") {
174
+ quote = ch;
175
+ }
176
+ else if (/\s/.test(ch)) {
177
+ if (cur)
178
+ out.push(cur);
179
+ cur = "";
180
+ }
181
+ else {
182
+ cur += ch;
183
+ }
184
+ }
185
+ if (cur)
186
+ out.push(cur);
187
+ return out;
188
+ }
189
+ function isFile(p) {
190
+ try {
191
+ return statSync(p, { throwIfNoEntry: false })?.isFile() ?? false;
192
+ }
193
+ catch {
194
+ return false;
195
+ }
196
+ }
197
+ /** PATHEXT-aware `which`. A path-ish cli is probed where it points. */
198
+ function whichWin(cli) {
199
+ const exts = (process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean);
200
+ // an extensionless name is not runnable on Windows, so PATHEXT wins over
201
+ // the bare file — npm installs both `claude` (a sh script) and `claude.cmd`
202
+ const probe = (base) => {
203
+ const order = extname(base) ? [base, ...exts.map((e) => base + e)] : [...exts.map((e) => base + e), base];
204
+ return order.find(isFile) ?? null;
205
+ };
206
+ if (/[\\/]/.test(cli) || /^[a-zA-Z]:/.test(cli))
207
+ return probe(cli);
208
+ for (const dir of augmentedPath().split(delimiter)) {
209
+ if (!dir)
210
+ continue;
211
+ const hit = probe(join(dir, cli));
212
+ if (hit)
213
+ return hit;
214
+ }
215
+ return null;
216
+ }
217
+ /** node.exe to run a script with: the one npm's shim would pick, else PATH,
218
+ * else this executable only when it really is Node. In a packaged app,
219
+ * process.execPath is Electron and must never be mistaken for node.exe. */
220
+ function nodeExe(near) {
221
+ const local = join(near, "node.exe");
222
+ if (isFile(local))
223
+ return local;
224
+ // Ask for the executable explicitly so a custom PATHEXT ordering cannot
225
+ // make a stray node.cmd hide the real node.exe beside it.
226
+ const onPath = whichWin("node.exe");
227
+ if (onPath && extname(onPath).toLowerCase() === ".exe")
228
+ return onPath;
229
+ return process.versions.electron ? null : process.execPath;
230
+ }
231
+ /** npm/pnpm .cmd shims all spell their target as "%dp0%\..." (or
232
+ * "%~dp0\..."). Whatever of those exists on disk is what the shim runs. */
233
+ function parseCmdShim(shim) {
234
+ let text;
235
+ try {
236
+ text = readFileSync(shim, "utf8");
237
+ }
238
+ catch {
239
+ return null;
240
+ }
241
+ const dir = dirname(shim);
242
+ const targets = [...text.matchAll(/"%~?dp0%?\\?([^"]+)"/g)]
243
+ .map((m) => join(dir, m[1]))
244
+ .filter((p) => isFile(p) && basename(p).toLowerCase() !== "node.exe");
245
+ const script = targets.find((p) => /\.[cm]?js$/i.test(p));
246
+ if (script) {
247
+ const node = nodeExe(dir);
248
+ if (node)
249
+ return { command: node, args: [script] };
250
+ }
251
+ const exe = targets.find((p) => extname(p).toLowerCase() === ".exe");
252
+ return exe ? { command: exe, args: [] } : null;
253
+ }
254
+ /** `#!/usr/bin/env node` → `node <script>`. Only node: nothing else has a
255
+ * meaningful Windows equivalent worth guessing at. */
256
+ function parseNodeShebang(file) {
257
+ let head = "";
258
+ let fd = null;
259
+ try {
260
+ fd = openSync(file, "r");
261
+ const buf = Buffer.alloc(128);
262
+ const n = readSync(fd, buf, 0, buf.length, 0);
263
+ head = buf.subarray(0, n).toString("utf8").split("\n", 1)[0];
264
+ }
265
+ catch {
266
+ return null;
267
+ }
268
+ finally {
269
+ if (fd !== null) {
270
+ try {
271
+ closeSync(fd);
272
+ }
273
+ catch {
274
+ /* best-effort descriptor cleanup */
275
+ }
276
+ }
277
+ }
278
+ if (!/^#!.*\bnode(\.exe)?\b/.test(head))
279
+ return null;
280
+ const node = nodeExe(dirname(file));
281
+ return node ? { command: node, args: [file] } : null;
282
+ }
283
+ /**
284
+ * How to actually spawn `cli` with `args` on this platform. Identity
285
+ * everywhere but win32 — POSIX already resolves PATH and #! itself.
286
+ */
287
+ /** Resolve a single command word (no tokenizer) — the platform spawn rules. */
288
+ function resolveWord(cli, args) {
289
+ if (process.platform !== "win32")
290
+ return { command: cli, args };
291
+ const file = whichWin(cli);
292
+ // not found: hand back the name so spawn reports its own ENOENT
293
+ if (!file)
294
+ return { command: cli, args };
295
+ const ext = extname(file).toLowerCase();
296
+ if (ext === ".cmd" || ext === ".bat") {
297
+ const direct = parseCmdShim(file);
298
+ return direct ? { command: direct.command, args: [...direct.args, ...args] } : { command: file, args };
299
+ }
300
+ if (ext === ".exe" || ext === ".com")
301
+ return { command: file, args };
302
+ const viaNode = parseNodeShebang(file);
303
+ return viaNode ? { command: viaNode.command, args: [...viaNode.args, ...args] } : { command: file, args };
304
+ }
305
+ export function resolveCliSpawn(cli, args) {
306
+ // An EXISTING FILE wins over the tokenizer: paths with spaces come from
307
+ // our own candidate list unquoted ("/Applications/My Tools/claude"), and
308
+ // splitting those would shred them. Only a bare word (no spaces) or an
309
+ // explicitly-quoted/wrapper string reaches the split below.
310
+ const trimmed = cli.trim();
311
+ if (trimmed.includes(" ") && existsSync(trimmed))
312
+ return resolveWord(trimmed, args);
313
+ // A `cli` value may carry fixed leading arguments — wrapper scripts like
314
+ // `/usr/local/bin/ag claude agp` are one string in the Engines panel. ONE
315
+ // tokenizer pass, then resolve the head directly (never re-tokenized: a
316
+ // quoted token may itself contain spaces, so feeding it back through the
317
+ // splitter would shred it). Fixed args go BEFORE invocation args — a
318
+ // wrapper's subcommand must lead (`ag claude agp --help`), or the wrapper
319
+ // swallows the flag itself.
320
+ const split = splitCliString(cli);
321
+ if (split.length > 1 || split[0] !== trimmed) {
322
+ const [head, ...fixed] = split;
323
+ // empty input → hand the raw string to spawn so IT reports the ENOENT
324
+ if (!head)
325
+ return { command: cli, args };
326
+ return resolveWord(head, [...fixed, ...args]);
327
+ }
328
+ return resolveWord(cli, args);
329
+ }
@@ -0,0 +1,105 @@
1
+ // What a client learns about this server before it authenticates: a stable
2
+ // identity, a label, the version, and what it can do. Served without auth at
3
+ // /.well-known/openmausbot/environment so a saved connection can check it is
4
+ // still talking to the same server, and so version skew is visible.
5
+ import { randomUUID } from "node:crypto";
6
+ import { closeSync, fsyncSync, linkSync, mkdirSync, openSync, readFileSync, unlinkSync, writeFileSync, } from "node:fs";
7
+ import { hostname } from "node:os";
8
+ import { dirname, join } from "node:path";
9
+ import { SERVER_ROOT } from "./proxy-paths.js";
10
+ const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
11
+ function hasCode(error, code) {
12
+ return error instanceof Error && "code" in error && error.code === code;
13
+ }
14
+ function readEnvironmentId(file) {
15
+ let contents;
16
+ try {
17
+ contents = readFileSync(file, "utf8");
18
+ }
19
+ catch (error) {
20
+ if (hasCode(error, "ENOENT"))
21
+ return undefined;
22
+ throw new Error(`Cannot read the existing environment identity at ${file}; refusing to replace it.`, {
23
+ cause: error,
24
+ });
25
+ }
26
+ const id = contents.trim();
27
+ if (!UUID_PATTERN.test(id)) {
28
+ throw new Error(`The existing environment identity at ${file} is not a valid UUID; refusing to replace it.`);
29
+ }
30
+ return id;
31
+ }
32
+ /** Read or create the id. Written once, never rotated by the server itself. */
33
+ export function loadEnvironmentId(dataDir) {
34
+ const file = join(dataDir, "environment-id");
35
+ const existing = readEnvironmentId(file);
36
+ if (existing)
37
+ return existing;
38
+ const directory = dirname(file);
39
+ mkdirSync(directory, { recursive: true, mode: 0o700 });
40
+ const id = randomUUID();
41
+ const temporaryFile = join(directory, `.environment-id.${process.pid}.${randomUUID()}.tmp`);
42
+ let descriptor;
43
+ try {
44
+ descriptor = openSync(temporaryFile, "wx", 0o600);
45
+ writeFileSync(descriptor, id + "\n", "utf8");
46
+ fsyncSync(descriptor);
47
+ closeSync(descriptor);
48
+ descriptor = undefined;
49
+ try {
50
+ // The temporary file is complete before it becomes visible at the final
51
+ // path. A hard link is an atomic, no-replace publish on every supported
52
+ // desktop platform, unlike rename (which overwrites on POSIX).
53
+ linkSync(temporaryFile, file);
54
+ return id;
55
+ }
56
+ catch (error) {
57
+ if (!hasCode(error, "EEXIST"))
58
+ throw error;
59
+ const winner = readEnvironmentId(file);
60
+ if (winner)
61
+ return winner;
62
+ throw new Error(`The environment identity at ${file} disappeared while it was being created.`);
63
+ }
64
+ }
65
+ finally {
66
+ if (descriptor !== undefined)
67
+ closeSync(descriptor);
68
+ try {
69
+ unlinkSync(temporaryFile);
70
+ }
71
+ catch {
72
+ // A leftover private temporary file is harmless and must not make a
73
+ // successfully published identity unusable.
74
+ }
75
+ }
76
+ }
77
+ /** The desktop app passes its own version; a checkout reads package.json;
78
+ * an image sets OMB_APP_VERSION at build time. */
79
+ export function serverVersion() {
80
+ const fromEnv = process.env.OMB_APP_VERSION?.trim();
81
+ if (fromEnv)
82
+ return fromEnv;
83
+ try {
84
+ const pkg = JSON.parse(readFileSync(join(SERVER_ROOT, "..", "package.json"), "utf8"));
85
+ const version = Reflect.get(Object(pkg), "version");
86
+ if (typeof version === "string" && version)
87
+ return version;
88
+ }
89
+ catch {
90
+ /* no package.json next to the bundle */
91
+ }
92
+ return "unknown";
93
+ }
94
+ export function environmentDescriptor(input) {
95
+ return {
96
+ environmentId: input.environmentId,
97
+ label: process.env.OMB_ENVIRONMENT_LABEL?.trim() || hostname(),
98
+ platform: process.platform,
99
+ version: serverVersion(),
100
+ capabilities: {
101
+ remoteSessions: true,
102
+ selfUpdate: input.desktopManaged ? "desktop-managed" : "operator",
103
+ },
104
+ };
105
+ }
@@ -0,0 +1,39 @@
1
+ import { IMAGE_MAX_BYTES } from "./attachments.js";
2
+ const MAX_BASE64_CHARS = Math.ceil(IMAGE_MAX_BYTES / 3) * 4 + 8;
3
+ function sniffRaster(bytes) {
4
+ if (bytes.length >= 8 && bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
5
+ return "image/png";
6
+ }
7
+ if (bytes.length >= 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {
8
+ return "image/jpeg";
9
+ }
10
+ const head = bytes.subarray(0, 6).toString("ascii");
11
+ if (head === "GIF87a" || head === "GIF89a")
12
+ return "image/gif";
13
+ if (bytes.length >= 12 &&
14
+ bytes.subarray(0, 4).toString("ascii") === "RIFF" &&
15
+ bytes.subarray(8, 12).toString("ascii") === "WEBP") {
16
+ return "image/webp";
17
+ }
18
+ return null;
19
+ }
20
+ /** Decode an untrusted provider image without trusting its claimed MIME.
21
+ * Codex normally sends raw base64, but accepting a raster data URL makes the
22
+ * boundary resilient to app-server shape changes without widening formats. */
23
+ export function decodeGeneratedImage(input) {
24
+ const trimmed = input.trim();
25
+ const comma = trimmed.startsWith("data:") ? trimmed.indexOf(",") : -1;
26
+ const encoded = comma >= 0 ? trimmed.slice(comma + 1) : trimmed;
27
+ if (!encoded || encoded.length > MAX_BASE64_CHARS || !/^[A-Za-z0-9+/\s]*={0,2}$/.test(encoded)) {
28
+ throw new Error("generated image payload is invalid or too large");
29
+ }
30
+ const compact = encoded.replace(/\s/g, "");
31
+ const bytes = Buffer.from(compact, "base64");
32
+ if (bytes.length === 0 || bytes.length > IMAGE_MAX_BYTES) {
33
+ throw new Error(`generated image exceeds ${IMAGE_MAX_BYTES} bytes`);
34
+ }
35
+ const mime = sniffRaster(bytes);
36
+ if (!mime)
37
+ throw new Error("generated image is not a supported raster format");
38
+ return { bytes, mime };
39
+ }