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,904 @@
1
+ // Generic ACP (Agent Client Protocol) driver core — one JSON-RPC-2.0-over-
2
+ // stdio session runtime that every ACP CLI harness (Grok Build, Gemini CLI,
3
+ // …) rides. Modeled on t3code's AcpSessionRuntime + per-agent AcpSupport
4
+ // split: the protocol mechanics live here, the per-harness quirks (spawn
5
+ // argv, auth method, model catalog, sign-in check) live in a small support
6
+ // object. Adding a harness = write server/drivers/acp/<name>.ts.
7
+ //
8
+ // ACP has no `turn/completed` notification: the `session/prompt` RPC *result*
9
+ // is the completion signal (it carries stopReason + usage). Permission
10
+ // requests arrive as server→client `session/request_permission` and surface
11
+ // as canonical request.opened events, answered fail-closed (nothing approved
12
+ // unless the agent explicitly offered an `allow`-kind option — option ORDER
13
+ // is never a security contract). session/load REPLAYS history as ordinary
14
+ // session/update notifications, so updates are double-gated: nothing emits
15
+ // before the prompt is sent, and `_meta.isReplay` updates are dropped.
16
+ import { homedir } from "node:os";
17
+ import { lstat, mkdir, readFile, realpath, stat, writeFile } from "node:fs/promises";
18
+ import { basename, dirname, isAbsolute, relative, resolve } from "node:path";
19
+ import { PROVIDER_CREDENTIAL_ENV, WORKSPACE_CREDENTIAL_ENV } from "../../config.js";
20
+ import { decodeInjectId } from "../local-inject.js";
21
+ import { describeSpawnFailure, execCli, killCliTree, spawnCli } from "../../procs.js";
22
+ /**
23
+ * A `host::model` pick talks to a loopback server with its own key.
24
+ * Subscription ACP login (grok.com cached_token) must not fail that turn.
25
+ */
26
+ export function skipSubscriptionAuthForLocalInject(model) {
27
+ return Boolean(decodeInjectId(model));
28
+ }
29
+ import { newEventId, newId } from "../../contracts.js";
30
+ import { computerProxyEnv } from "../../container-computer.js";
31
+ import { augmentedPath } from "../../env-path.js";
32
+ import { supportsApprovalMode } from "../../../shared/approval-mode.js";
33
+ // Resolved from the server root, never relative to this file: bundling inlines
34
+ // this module two directories up, so the `".."` pair here would climb past the
35
+ // packaged server dir entirely. See server/proxy-paths.ts.
36
+ const COMPUTER_PROXY_PATH = SPAWNED_PROXIES.computer;
37
+ import { appendNative } from "../native.js";
38
+ import { SPAWNED_PROXIES } from "../../proxy-paths.js";
39
+ const envOr = (key, fallback) => Number(process.env[key] ?? fallback);
40
+ const INIT_TIMEOUT = envOr("OPENMAUS_ACP_INIT_TIMEOUT_MS", 300_000);
41
+ const SESSION_CONFIG_TIMEOUT = envOr("OPENMAUS_ACP_SESSION_CONFIG_TIMEOUT_MS", 300_000); // configureSession's per-request default
42
+ const NEW_SESSION_TIMEOUT = envOr("OPENMAUS_ACP_NEW_SESSION_TIMEOUT_MS", 300_000);
43
+ const LOAD_SESSION_TIMEOUT = envOr("OPENMAUS_ACP_LOAD_SESSION_TIMEOUT_MS", 120_000); // history replay on a long thread is slow
44
+ const CLIENT_FILE_MAX_BYTES = 8 * 1024 * 1024;
45
+ const TOOL_LOG_TEXT_LIMIT = 64_000;
46
+ async function readAcpImageBlocks(images) {
47
+ return Promise.all(images.map(async (image) => ({
48
+ type: "image",
49
+ data: (await readFile(image.path)).toString("base64"),
50
+ mimeType: image.mime,
51
+ })));
52
+ }
53
+ function sanitizeToolLogValue(value, budget, depth = 0) {
54
+ if (depth > 12 || budget.nodes-- <= 0)
55
+ return undefined;
56
+ if (typeof value === "string") {
57
+ if (/^data:image\//iu.test(value) || budget.text <= 0)
58
+ return undefined;
59
+ const limit = Math.min(TOOL_LOG_TEXT_LIMIT, budget.text);
60
+ const text = value.length <= limit ? value : `[Earlier output truncated]\n\n${value.slice(-limit)}`;
61
+ budget.text -= text.length;
62
+ return text;
63
+ }
64
+ if (Array.isArray(value)) {
65
+ return value.flatMap((entry) => {
66
+ const sanitized = sanitizeToolLogValue(entry, budget, depth + 1);
67
+ return sanitized === undefined ? [] : [sanitized];
68
+ });
69
+ }
70
+ if (!value || typeof value !== "object")
71
+ return value;
72
+ const record = value;
73
+ return Object.fromEntries(Object.entries(record).flatMap(([key, entry]) => {
74
+ if ((record.type === "image" && (key === "data" || key === "blob")) ||
75
+ (key === "blob" && typeof record.mimeType === "string" && record.mimeType.startsWith("image/")))
76
+ return [];
77
+ const sanitized = sanitizeToolLogValue(entry, budget, depth + 1);
78
+ return sanitized === undefined ? [] : [[key, sanitized]];
79
+ }));
80
+ }
81
+ function sanitizeAcpToolMessage(message) {
82
+ const isToolUpdate = message?.method === "session/update"
83
+ && ["tool_call", "tool_call_update"].includes(message?.params?.update?.sessionUpdate);
84
+ const isPermission = message?.method === "session/request_permission";
85
+ if (!isToolUpdate && !isPermission)
86
+ return message;
87
+ return sanitizeToolLogValue(message, { nodes: 512, text: TOOL_LOG_TEXT_LIMIT });
88
+ }
89
+ function decodeAcpConfig(defaultCli) {
90
+ return (raw) => {
91
+ const o = (raw ?? {});
92
+ return {
93
+ cli: typeof o.cli === "string" ? o.cli : defaultCli,
94
+ fullAuto: o.fullAuto === true,
95
+ workspace: typeof o.workspace === "string" ? o.workspace : undefined,
96
+ };
97
+ };
98
+ }
99
+ /**
100
+ * ACP JSON-RPC-over-stdio driver. Harness differences (argv, auth, catalog)
101
+ * live in `support`; this is the shared handshake and turn runtime.
102
+ */
103
+ export function createAcpDriver(support) {
104
+ const DRIVER_KIND = support.driverKind;
105
+ const SOURCE = support.nativeSource;
106
+ const decodeConfig = decodeAcpConfig(support.defaultCli);
107
+ const DENY_TIMEOUT_NOTE = "OpenMausBot: nobody answered this permission request in time. Skip this action and finish what you can without it.";
108
+ return {
109
+ driverKind: DRIVER_KIND,
110
+ metadata: {
111
+ displayName: support.displayName,
112
+ supportsMultipleInstances: true,
113
+ access: support.access ?? "subscription",
114
+ },
115
+ install: support.install,
116
+ models: support.models,
117
+ decodeConfig,
118
+ defaultConfig: () => decodeConfig({}),
119
+ async create(input) {
120
+ const { instanceId, config } = input;
121
+ const childEnv = (activeConfig = config) => {
122
+ const env = {
123
+ ...process.env,
124
+ ...input.environment,
125
+ PATH: augmentedPath(),
126
+ };
127
+ const allowedCredentials = new Set(support.credentialEnv ?? []);
128
+ // two lists, one rule: foreign PROVIDER keys must not flip a CLI's
129
+ // billing off its own login, and WORKSPACE credentials (box token,
130
+ // voice key, …) are the harness's secrets — riding along in
131
+ // `...process.env` is not a grant. A driver keeps only what its
132
+ // credentialEnv allowlist names.
133
+ for (const key of [...PROVIDER_CREDENTIAL_ENV, ...WORKSPACE_CREDENTIAL_ENV]) {
134
+ if (!allowedCredentials.has(key))
135
+ delete env[key];
136
+ }
137
+ support.transformEnv?.(env, activeConfig, instanceId);
138
+ return env;
139
+ };
140
+ let models = support.models;
141
+ const refreshModels = async () => {
142
+ if (!support.resolveModels)
143
+ return;
144
+ try {
145
+ const resolved = await support.resolveModels(childEnv(), config, instanceId);
146
+ if (resolved.options.length)
147
+ models = resolved;
148
+ }
149
+ catch {
150
+ // Keep the last usable catalog when an optional discovery source is down.
151
+ }
152
+ };
153
+ if (support.resolveModelsOnCreate !== false)
154
+ await refreshModels();
155
+ const listeners = new Set();
156
+ const active = new Map();
157
+ const emit = (event) => {
158
+ for (const listener of listeners)
159
+ listener(event);
160
+ };
161
+ // ACP content blocks may carry a complete raster image inline. Keep the
162
+ // bytes on the wire, but never duplicate megabytes of base64 into the
163
+ // provider-native diagnostic log in either direction.
164
+ const nativeLogMessage = (msg) => {
165
+ let redacted = msg;
166
+ const prompt = msg?.method === "session/prompt" ? msg?.params?.prompt : null;
167
+ if (Array.isArray(prompt)) {
168
+ redacted = {
169
+ ...msg,
170
+ params: {
171
+ ...msg.params,
172
+ prompt: prompt.map((content) => content?.type === "image" && typeof content.data === "string"
173
+ ? { ...content, data: `[image data: ${content.data.length} base64 chars]` }
174
+ : content),
175
+ },
176
+ };
177
+ }
178
+ const content = redacted?.params?.update?.content;
179
+ if (redacted?.method !== "session/update" ||
180
+ redacted?.params?.update?.sessionUpdate !== "agent_message_chunk" ||
181
+ content?.type !== "image" ||
182
+ typeof content.data !== "string")
183
+ return support.sanitizeToolPayload ? sanitizeAcpToolMessage(redacted) : redacted;
184
+ redacted = {
185
+ ...redacted,
186
+ params: {
187
+ ...redacted.params,
188
+ update: {
189
+ ...redacted.params.update,
190
+ content: { ...content, data: `[image data: ${content.data.length} base64 chars]` },
191
+ },
192
+ },
193
+ };
194
+ return support.sanitizeToolPayload ? sanitizeAcpToolMessage(redacted) : redacted;
195
+ };
196
+ const base = (threadId, turnId) => ({
197
+ eventId: newEventId(),
198
+ provider: DRIVER_KIND,
199
+ threadId,
200
+ turnId,
201
+ createdAt: new Date().toISOString(),
202
+ });
203
+ // ACP session mcpServers: stdio is the baseline every ACP agent
204
+ // supports (mcpCapabilities.http/.sse only add EXTRA transports), so
205
+ // an injected stdio proxy — e.g. the peer-agent comms tool — attaches
206
+ // fine here. env is the ACP {name,value}[] shape.
207
+ const acpMcpServers = (turn) => {
208
+ const servers = [];
209
+ const acpEnv = (env) => Object.entries(env).map(([name, value]) => ({ name, value: String(value) }));
210
+ const agents = turn.integrations?.agents;
211
+ if (agents) {
212
+ servers.push({ name: "agents", command: agents.command, args: agents.args, env: acpEnv(agents.env) });
213
+ }
214
+ const composio = turn.integrations?.composio;
215
+ if (composio) {
216
+ servers.push({
217
+ name: "composio",
218
+ command: composio.command,
219
+ args: composio.args,
220
+ env: acpEnv(composio.env),
221
+ });
222
+ }
223
+ const browser = turn.integrations?.browser;
224
+ if (browser) {
225
+ servers.push({ name: "browser", command: browser.command, args: browser.args, env: acpEnv(browser.env) });
226
+ }
227
+ // The bot's computer, mounted exactly like the Claude driver does.
228
+ // Cloud boxes use the REST adapter; host and sandbox Cua connections
229
+ // expose Cua Driver's official MCP server directly.
230
+ const computer = turn.integrations?.computer;
231
+ if (computer) {
232
+ servers.push({
233
+ name: "computer",
234
+ command: process.execPath,
235
+ args: [COMPUTER_PROXY_PATH],
236
+ env: acpEnv({ ELECTRON_RUN_AS_NODE: "1", ...computerProxyEnv(computer) }),
237
+ });
238
+ }
239
+ else if (turn.integrations?.localComputer) {
240
+ const local = turn.integrations.localComputer;
241
+ servers.push({
242
+ name: "computer",
243
+ command: local.command,
244
+ args: local.args,
245
+ env: acpEnv(local.env ?? {}),
246
+ });
247
+ }
248
+ // user-configured servers, after the built-ins: a residual name
249
+ // collision keeps the built-in (reserved names are filtered at the
250
+ // config boundary; this is defense in depth).
251
+ for (const [name, server] of Object.entries(turn.integrations?.custom ?? {})) {
252
+ if (servers.some((existing) => existing.name === name))
253
+ continue;
254
+ servers.push({ name, command: server.command, args: server.args, env: acpEnv(server.env) });
255
+ }
256
+ return servers;
257
+ };
258
+ const sendTurn = async (turn) => {
259
+ const { threadId } = turn;
260
+ if (active.has(threadId))
261
+ throw new Error("a turn is already running on this thread");
262
+ // Provider-instance `fullAuto` predates per-bot approval levels. Every
263
+ // harness turn now carries the bot's mode, so Ask/Auto must explicitly
264
+ // put the native agent back into its interactive mode. Otherwise a
265
+ // legacy Grok bypassPermissions / Cursor --force / Droid auto-high /
266
+ // Antigravity yolo setting would silently outrank the selector. Calls
267
+ // that omit approvalMode retain the old adapter-level behavior for
268
+ // embedders and tests outside the harness.
269
+ const turnConfig = turn.approvalMode === undefined
270
+ ? config
271
+ : { ...config, fullAuto: turn.approvalMode === "full" && supportsApprovalMode(DRIVER_KIND, "full") };
272
+ const controlsHost = turn.integrations?.localComputer?.scope === "local-computer";
273
+ if (controlsHost && turnConfig.fullAuto && turn.approvalMode !== "full") {
274
+ throw new Error("local computer control requires interactive provider approvals");
275
+ }
276
+ const turnId = newId();
277
+ const cwd = turn.cwd ?? turnConfig.workspace ?? homedir();
278
+ const env = childEnv(turnConfig);
279
+ if (support.requireAuthenticationBeforeSpawn
280
+ && !skipSubscriptionAuthForLocalInject(turn.model)
281
+ && !(await support.isAuthenticated(env, turnConfig, instanceId))) {
282
+ emit({ ...base(threadId, turnId), type: "turn.started" });
283
+ emit({ ...base(threadId, turnId), type: "runtime.error", message: support.loginNote, setup: true });
284
+ emit({ ...base(threadId, turnId), type: "turn.completed", ok: false, stopReason: "auth_required", cost: null });
285
+ return { turnId };
286
+ }
287
+ const resolvedModel = support.resolveTurnModel?.(turn.model, env);
288
+ support.applyTurnEnv?.(env, { model: resolvedModel, requestedModel: turn.model });
289
+ const cliTurn = resolvedModel !== undefined && resolvedModel !== turn.model
290
+ ? { ...turn, model: resolvedModel }
291
+ : turn;
292
+ const mcpServers = acpMcpServers(turn);
293
+ let launch;
294
+ try {
295
+ launch = support.resolveCommand
296
+ ? await support.resolveCommand(env, turnConfig, instanceId)
297
+ : { command: turnConfig.cli };
298
+ }
299
+ catch (error) {
300
+ emit({ ...base(threadId, turnId), type: "turn.started" });
301
+ emit({
302
+ ...base(threadId, turnId),
303
+ type: "runtime.error",
304
+ message: error instanceof Error ? error.message : String(error),
305
+ setup: true,
306
+ });
307
+ emit({ ...base(threadId, turnId), type: "turn.completed", ok: false, stopReason: "setup_required", cost: null });
308
+ return { turnId };
309
+ }
310
+ const child = spawnCli(launch.command, [...(launch.args ?? []), ...support.spawnArgs(turnConfig, cliTurn)], {
311
+ cwd,
312
+ env: launch.env ?? env,
313
+ stdio: ["pipe", "pipe", "pipe"],
314
+ });
315
+ const state = { settled: false, promptSent: false, text: "" };
316
+ const asks = new Map();
317
+ let nextId = 1;
318
+ let sessionId = null;
319
+ let interruptTimer = null;
320
+ const rpcPending = new Map();
321
+ const send = (obj) => {
322
+ try {
323
+ child.stdin.write(JSON.stringify(obj) + "\n");
324
+ }
325
+ catch { }
326
+ appendNative(threadId, { dir: "out", source: SOURCE, msg: nativeLogMessage(obj) });
327
+ };
328
+ const request = (method, params, timeoutMs) => new Promise((resolve, reject) => {
329
+ const id = nextId++;
330
+ let timer = null;
331
+ if (timeoutMs) {
332
+ timer = setTimeout(() => {
333
+ rpcPending.delete(id);
334
+ reject(new Error(`${method} timed out`));
335
+ }, timeoutMs);
336
+ timer.unref?.();
337
+ }
338
+ rpcPending.set(id, { resolve, reject, timer });
339
+ send({ jsonrpc: "2.0", id, method, params });
340
+ });
341
+ const stop = () => killCliTree(child);
342
+ const resolveClientPath = async (requestPath) => {
343
+ if (typeof requestPath !== "string" || !isAbsolute(requestPath)) {
344
+ throw new Error("ACP file paths must be absolute.");
345
+ }
346
+ const workspace = await realpath(cwd).catch(() => resolve(cwd));
347
+ const requested = resolve(requestPath);
348
+ const lexical = relative(resolve(cwd), requested);
349
+ if (lexical === ".." || lexical.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || isAbsolute(lexical)) {
350
+ throw new Error("ACP file path is outside the session workspace.");
351
+ }
352
+ const suffix = [basename(requested)];
353
+ let ancestor = dirname(requested);
354
+ while (!(await lstat(ancestor).catch(() => null))) {
355
+ const parent = dirname(ancestor);
356
+ if (parent === ancestor)
357
+ throw new Error("ACP file path has no accessible parent.");
358
+ suffix.unshift(basename(ancestor));
359
+ ancestor = parent;
360
+ }
361
+ const candidate = resolve(await realpath(ancestor), ...suffix);
362
+ const rel = relative(workspace, candidate);
363
+ if (rel === ".." || rel.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || isAbsolute(rel)) {
364
+ throw new Error("ACP file path is outside the session workspace.");
365
+ }
366
+ const existing = await lstat(candidate).catch(() => null);
367
+ if (existing?.isSymbolicLink())
368
+ throw new Error("ACP file path cannot be a symbolic link.");
369
+ return candidate;
370
+ };
371
+ const handleClientFileRequest = async (msg) => {
372
+ const fail = (error) => send({
373
+ jsonrpc: "2.0",
374
+ id: msg.id,
375
+ error: { code: -32602, message: error instanceof Error ? error.message : String(error) },
376
+ });
377
+ try {
378
+ if (!support.clientFileSystem)
379
+ throw new Error("Client file access is disabled.");
380
+ const params = msg.params ?? {};
381
+ const path = await resolveClientPath(params.path);
382
+ if (msg.method === "fs/read_text_file") {
383
+ const info = await stat(path);
384
+ if (!info.isFile() || info.size > CLIENT_FILE_MAX_BYTES) {
385
+ throw new Error(`ACP can only read text files under ${CLIENT_FILE_MAX_BYTES} bytes.`);
386
+ }
387
+ const content = await readFile(path, "utf8");
388
+ if (params.line == null && params.limit == null) {
389
+ send({ jsonrpc: "2.0", id: msg.id, result: { content } });
390
+ return;
391
+ }
392
+ const line = Number.isInteger(params.line) && params.line > 0 ? params.line : 1;
393
+ const limit = Number.isInteger(params.limit) && params.limit >= 0 ? params.limit : undefined;
394
+ const lines = content.split("\n");
395
+ const start = line - 1;
396
+ send({
397
+ jsonrpc: "2.0",
398
+ id: msg.id,
399
+ result: { content: lines.slice(start, limit === undefined ? undefined : start + limit).join("\n") },
400
+ });
401
+ return;
402
+ }
403
+ if (typeof params.content !== "string" || Buffer.byteLength(params.content) > CLIENT_FILE_MAX_BYTES) {
404
+ throw new Error(`ACP can only write text files under ${CLIENT_FILE_MAX_BYTES} bytes.`);
405
+ }
406
+ await mkdir(dirname(path), { recursive: true });
407
+ await writeFile(path, params.content, "utf8");
408
+ send({ jsonrpc: "2.0", id: msg.id, result: {} });
409
+ }
410
+ catch (error) {
411
+ fail(error);
412
+ }
413
+ };
414
+ /** Emit buffered assistant text as its own item, then clear it. */
415
+ const flushAssistantText = () => {
416
+ const text = state.text;
417
+ state.text = "";
418
+ if (!text.trim())
419
+ return;
420
+ emit({ ...base(threadId, turnId), type: "item.completed", itemType: "assistant_text", text });
421
+ };
422
+ const settle = (ok, stopReason) => {
423
+ if (state.settled)
424
+ return;
425
+ state.settled = true;
426
+ if (interruptTimer)
427
+ clearTimeout(interruptTimer);
428
+ for (const finish of asks.values())
429
+ finish("cancel", "system");
430
+ for (const p of rpcPending.values()) {
431
+ if (p.timer)
432
+ clearTimeout(p.timer);
433
+ p.reject(new Error("turn settled"));
434
+ }
435
+ rpcPending.clear();
436
+ active.delete(threadId);
437
+ flushAssistantText();
438
+ emit({ ...base(threadId, turnId), type: "turn.completed", ok, stopReason, cost: null });
439
+ stop(); // the agent process does not exit on its own
440
+ };
441
+ // server→client permission request → canonical request.opened
442
+ const handleServerRequest = (msg) => {
443
+ if (msg.method === "fs/read_text_file" || msg.method === "fs/write_text_file") {
444
+ void handleClientFileRequest(msg);
445
+ return;
446
+ }
447
+ if (msg.method !== "session/request_permission") {
448
+ // never leave an unknown server request hanging — the agent blocks
449
+ return send({ jsonrpc: "2.0", id: msg.id, error: { code: -32601, message: "method not found" } });
450
+ }
451
+ const params = msg.params ?? {};
452
+ flushAssistantText();
453
+ const options = Array.isArray(params.options) ? params.options : [];
454
+ const optionFor = (want) => options.find((o) => o.kind === `${want}_once` && typeof o.optionId === "string")?.optionId
455
+ ?? options.find((o) => String(o.kind ?? "").startsWith(want) && typeof o.optionId === "string")?.optionId
456
+ ?? null;
457
+ const cancelled = { outcome: { outcome: "cancelled" } };
458
+ const missing = (want) => emit({
459
+ ...base(threadId, turnId),
460
+ type: "runtime.error",
461
+ message: `${DRIVER_KIND} offered no "${want}" permission option — cancelling the request instead of guessing`,
462
+ });
463
+ const toolCall = params.toolCall ?? {};
464
+ const isQuestion = String(toolCall.toolCallId ?? "").startsWith("interaction_");
465
+ if (turnConfig.fullAuto && turn.approvalMode === undefined && !isQuestion) {
466
+ const allow = optionFor("allow");
467
+ if (!allow)
468
+ missing("allow");
469
+ return send({
470
+ jsonrpc: "2.0",
471
+ id: msg.id,
472
+ result: allow ? { outcome: { outcome: "selected", optionId: allow } } : cancelled,
473
+ });
474
+ }
475
+ const kind = String(toolCall.kind ?? "");
476
+ const tool = kind === "execute" ? "shell" : kind === "edit" ? "edit" : kind || "tool";
477
+ const summary = String(toolCall.rawInput?.command ?? toolCall.title ?? tool).slice(0, 200);
478
+ const requestId = newId();
479
+ const finish = (behavior, source = "user", message) => {
480
+ if (!asks.delete(requestId))
481
+ return;
482
+ clearTimeout(timer);
483
+ const want = behavior === "allow" ? "allow" : "reject";
484
+ const named = isQuestion && behavior === "answer"
485
+ ? options.filter((option) => option.optionId === message || option.name?.trim() === message)
486
+ : [];
487
+ const optionId = behavior === "cancel"
488
+ ? null
489
+ : isQuestion
490
+ ? named.length === 1 && typeof named[0].optionId === "string" ? named[0].optionId : null
491
+ : optionFor(want);
492
+ if (behavior !== "cancel" && !optionId)
493
+ missing(isQuestion ? "matching answer" : want);
494
+ send({
495
+ jsonrpc: "2.0",
496
+ id: msg.id,
497
+ result: optionId ? { outcome: { outcome: "selected", optionId } } : cancelled,
498
+ });
499
+ emit({
500
+ ...base(threadId, turnId),
501
+ type: "request.resolved",
502
+ requestId,
503
+ behavior: optionId && isQuestion ? "answer" : optionId && behavior === "allow" ? "allow" : "deny",
504
+ source: optionId ? source : "system",
505
+ approvalScope: controlsHost ? "local-computer" : undefined,
506
+ });
507
+ };
508
+ const timer = setTimeout(() => {
509
+ emit({ ...base(threadId, turnId), type: "runtime.error", message: DENY_TIMEOUT_NOTE });
510
+ finish("deny", "timeout");
511
+ }, 15 * 60_000);
512
+ timer.unref?.();
513
+ asks.set(requestId, finish);
514
+ emit({
515
+ ...base(threadId, turnId),
516
+ type: "request.opened",
517
+ requestId,
518
+ requestType: isQuestion ? "question" : "permission",
519
+ tool,
520
+ summary,
521
+ choices: isQuestion
522
+ ? options.flatMap((option) => typeof option.name === "string" && option.name.trim() ? [option.name.trim()] : [])
523
+ : undefined,
524
+ approvalScope: controlsHost ? "local-computer" : undefined,
525
+ });
526
+ };
527
+ const handleNotification = (msg) => {
528
+ // Vendor side-channels (e.g. grok's `_x.ai/*`) are teed to the
529
+ // native log but never normalized: the prompt result is the settle.
530
+ if (msg.method !== "session/update")
531
+ return;
532
+ const p = msg.params ?? {};
533
+ if (!state.promptSent || p._meta?.isReplay === true)
534
+ return;
535
+ const u = p.update ?? {};
536
+ switch (u.sessionUpdate) {
537
+ case "agent_message_chunk": {
538
+ const content = u.content;
539
+ const delta = content?.text;
540
+ if (content?.type === "image" && typeof content.data === "string" && content.data) {
541
+ flushAssistantText();
542
+ emit({
543
+ ...base(threadId, turnId),
544
+ type: "item.completed",
545
+ itemType: "assistant_image",
546
+ data: content.data,
547
+ alt: "Generated image",
548
+ });
549
+ }
550
+ else if (typeof delta === "string" && delta) {
551
+ state.text += delta;
552
+ emit({ ...base(threadId, turnId), type: "content.delta", streamKind: "assistant_text", delta });
553
+ }
554
+ break;
555
+ }
556
+ case "agent_thought_chunk": {
557
+ const delta = u.content?.text;
558
+ if (typeof delta === "string" && delta) {
559
+ emit({ ...base(threadId, turnId), type: "content.delta", streamKind: "reasoning_text", delta });
560
+ }
561
+ break;
562
+ }
563
+ case "tool_call": {
564
+ flushAssistantText();
565
+ emit({
566
+ ...base(threadId, turnId),
567
+ type: "item.started",
568
+ itemType: "tool",
569
+ itemId: u.toolCallId,
570
+ title: String(u.rawInput?.command ?? u.title ?? "tool").slice(0, 80),
571
+ });
572
+ break;
573
+ }
574
+ case "tool_call_update": {
575
+ if (u.status === "completed" || u.status === "failed") {
576
+ emit({
577
+ ...base(threadId, turnId),
578
+ type: "item.completed",
579
+ itemType: "tool",
580
+ itemId: u.toolCallId,
581
+ ok: u.status !== "failed",
582
+ });
583
+ }
584
+ break;
585
+ }
586
+ }
587
+ };
588
+ let buf = "";
589
+ // decode as UTF-8 across chunk boundaries — a raw `buf += chunk` splits
590
+ // multibyte characters that straddle two reads and corrupts the text
591
+ child.stdout.setEncoding("utf8");
592
+ child.stdout.on("data", (chunk) => {
593
+ buf += chunk;
594
+ let nl;
595
+ while ((nl = buf.indexOf("\n")) !== -1) {
596
+ const line = buf.slice(0, nl);
597
+ buf = buf.slice(nl + 1);
598
+ if (!line.trim())
599
+ continue;
600
+ let msg;
601
+ try {
602
+ msg = JSON.parse(line);
603
+ }
604
+ catch {
605
+ continue;
606
+ }
607
+ appendNative(threadId, { dir: "in", source: SOURCE, msg: nativeLogMessage(msg) });
608
+ if (msg.id !== undefined && (msg.result !== undefined || msg.error !== undefined)) {
609
+ const pend = rpcPending.get(msg.id);
610
+ if (pend) {
611
+ rpcPending.delete(msg.id);
612
+ if (pend.timer)
613
+ clearTimeout(pend.timer);
614
+ if (msg.error) {
615
+ const error = new Error(msg.error.message ?? JSON.stringify(msg.error));
616
+ Object.assign(error, { code: msg.error.code, data: msg.error.data });
617
+ pend.reject(error);
618
+ }
619
+ else {
620
+ pend.resolve(msg.result);
621
+ }
622
+ }
623
+ }
624
+ else if (msg.id !== undefined && msg.method) {
625
+ handleServerRequest(msg);
626
+ }
627
+ else if (msg.method) {
628
+ handleNotification(msg);
629
+ }
630
+ }
631
+ });
632
+ let stderr = "";
633
+ child.stderr.on("data", (c) => {
634
+ if (!support.redactStderr)
635
+ stderr += c;
636
+ if (stderr.length > 8192)
637
+ stderr = stderr.slice(-8192);
638
+ });
639
+ child.on("error", (e) => {
640
+ emit({ ...base(threadId, turnId), type: "runtime.error", ...describeSpawnFailure(e, launch.command) });
641
+ settle(false, "spawn_error");
642
+ });
643
+ child.on("close", (code) => {
644
+ if (!state.settled) {
645
+ emit({
646
+ ...base(threadId, turnId),
647
+ type: "runtime.error",
648
+ message: `${DRIVER_KIND} exited ${code} before the prompt result${stderr ? `: ${stderr.trim().slice(-300)}` : ""}`,
649
+ });
650
+ settle(false, "exit_before_result");
651
+ }
652
+ });
653
+ const interrupt = () => {
654
+ if (sessionId)
655
+ send({ jsonrpc: "2.0", method: "session/cancel", params: { sessionId } });
656
+ else
657
+ stop();
658
+ if (interruptTimer)
659
+ clearTimeout(interruptTimer);
660
+ interruptTimer = setTimeout(() => settle(true, "cancelled"), 5_000);
661
+ interruptTimer.unref?.();
662
+ };
663
+ active.set(threadId, { stop, interrupt, turnId, asks });
664
+ emit({ ...base(threadId, turnId), type: "turn.started" });
665
+ (async () => {
666
+ try {
667
+ const init = await request("initialize", {
668
+ protocolVersion: 1,
669
+ clientInfo: { name: "openmausbot", version: "0.0.0" },
670
+ clientCapabilities: {
671
+ fs: {
672
+ readTextFile: support.clientFileSystem === true,
673
+ writeTextFile: support.clientFileSystem === true,
674
+ },
675
+ terminal: false,
676
+ },
677
+ }, INIT_TIMEOUT);
678
+ const methods = Array.isArray(init?.authMethods) ? init.authMethods : [];
679
+ const methodId = support.pickAuthMethod(methods);
680
+ if (!skipSubscriptionAuthForLocalInject(turn.model)) {
681
+ if (methodId) {
682
+ try {
683
+ await request("authenticate", { methodId }, INIT_TIMEOUT);
684
+ }
685
+ catch {
686
+ if (support.authFailure === "fail")
687
+ throw new Error(support.loginNote);
688
+ // else: proceed on an ambient login
689
+ }
690
+ }
691
+ else if (support.authFailure === "fail") {
692
+ throw new Error(support.loginNote);
693
+ }
694
+ }
695
+ const images = turn.images ?? [];
696
+ const runtimeAcceptsImages = init?.agentCapabilities?.promptCapabilities?.image === true;
697
+ if (images.length && support.images === true && !runtimeAcceptsImages) {
698
+ throw new Error(`${support.displayName} is configured for image attachments, but this installed runtime does not advertise ACP image input. Update the ${support.displayName} CLI or send the message without an image.`);
699
+ }
700
+ const cursor = typeof turn.resumeCursor === "string" ? turn.resumeCursor : null;
701
+ let sessionResult = null;
702
+ if (cursor) {
703
+ try {
704
+ sessionResult = await request(support.resumeMethod === "resume" ? "session/resume" : "session/load", { sessionId: cursor, cwd, mcpServers }, LOAD_SESSION_TIMEOUT);
705
+ if (sessionResult)
706
+ sessionId = cursor;
707
+ }
708
+ catch {
709
+ /* session gone, load unsupported, or too slow — start fresh */
710
+ }
711
+ }
712
+ if (!sessionId) {
713
+ sessionResult = await request("session/new", { cwd, mcpServers }, NEW_SESSION_TIMEOUT);
714
+ sessionId = typeof sessionResult?.sessionId === "string" ? sessionResult.sessionId : null;
715
+ if (!sessionId)
716
+ throw new Error("session/new returned no sessionId");
717
+ }
718
+ let selectedModel = null;
719
+ let sessionStarted = false;
720
+ const emitSessionStarted = () => {
721
+ if (sessionStarted)
722
+ return;
723
+ sessionStarted = true;
724
+ emit({
725
+ ...base(threadId, turnId),
726
+ type: "session.started",
727
+ sessionId,
728
+ model: selectedModel ?? init?._meta?.modelState?.currentModelId ?? cliTurn.model ?? null,
729
+ });
730
+ };
731
+ try {
732
+ if (support.selectModel) {
733
+ const { configId } = support.selectModel;
734
+ const currentOf = (r) => (Array.isArray(r?.configOptions) ? r.configOptions : []).find((o) => o?.id === configId)
735
+ ?.currentValue ?? null;
736
+ selectedModel = currentOf(sessionResult);
737
+ if (cliTurn.model && cliTurn.model !== selectedModel) {
738
+ selectedModel = currentOf(await request("session/set_config_option", { sessionId, configId, value: cliTurn.model }, INIT_TIMEOUT));
739
+ // an agent that answers OK but keeps its old model is worse than
740
+ // one that errors: it burns a paid turn on the wrong thing
741
+ if (selectedModel !== cliTurn.model) {
742
+ throw new Error(`${DRIVER_KIND} did not switch to ${cliTurn.model} (still ${selectedModel ?? "unknown"})`);
743
+ }
744
+ }
745
+ }
746
+ if (support.configureSession) {
747
+ await support.configureSession({
748
+ request: (method, params, timeoutMs) => request(method, params, timeoutMs ?? SESSION_CONFIG_TIMEOUT),
749
+ sessionId,
750
+ config: turnConfig,
751
+ turn: cliTurn,
752
+ sessionModels: Array.isArray(sessionResult?.models?.availableModels)
753
+ ? sessionResult.models.availableModels
754
+ : [],
755
+ });
756
+ // initialize's currentModelId is the CLI default (grok-4.6),
757
+ // not the model this turn asked for. After a successful pin,
758
+ // report the slug we set so the UI does not claim otherwise.
759
+ if (!selectedModel && cliTurn.model)
760
+ selectedModel = cliTurn.model;
761
+ }
762
+ }
763
+ catch (error) {
764
+ // session.started is the only place the resume cursor is recorded,
765
+ // so a rejected setting must not orphan a session we just created.
766
+ emitSessionStarted();
767
+ throw error;
768
+ }
769
+ emitSessionStarted();
770
+ state.promptSent = true;
771
+ const text = support.buildPromptText
772
+ ? support.buildPromptText(turn)
773
+ : turn.system
774
+ ? `${turn.system}\n\n${turn.text}`
775
+ : turn.text;
776
+ const imageBlocks = support.images === true && runtimeAcceptsImages
777
+ ? await readAcpImageBlocks(images)
778
+ : [];
779
+ const result = await request("session/prompt", {
780
+ sessionId,
781
+ prompt: [{ type: "text", text }, ...imageBlocks],
782
+ });
783
+ // opencode 1.18.18 reports usage at the result root; grok and
784
+ // gemini put it under _meta. Read both rather than lose the count.
785
+ const usage = result?.usage ?? result?._meta ?? {};
786
+ if (typeof usage.inputTokens === "number" || typeof usage.outputTokens === "number") {
787
+ emit({
788
+ ...base(threadId, turnId),
789
+ type: "thread.token-usage.updated",
790
+ input: usage.inputTokens ?? 0,
791
+ output: usage.outputTokens ?? 0,
792
+ });
793
+ }
794
+ const reason = result?.stopReason;
795
+ if (reason === "end_turn")
796
+ settle(true, null);
797
+ else if (reason === "cancelled")
798
+ settle(true, "cancelled");
799
+ else {
800
+ const errorMessage = typeof result?.error === "string" && result.error
801
+ ? result.error
802
+ : typeof result?.message === "string" && result.message
803
+ ? result.message
804
+ : `Model turn failed: ${reason ?? "unknown error"}`;
805
+ emit({
806
+ ...base(threadId, turnId),
807
+ type: "runtime.error",
808
+ message: errorMessage,
809
+ });
810
+ settle(false, reason ?? "failed");
811
+ }
812
+ }
813
+ catch (e) {
814
+ if (!state.settled) {
815
+ const message = e instanceof Error ? e.message : String(e);
816
+ const code = support.classifyError?.(e);
817
+ // Authentication setup is a user action, not a retry. The
818
+ // classifier is preferred; loginNote remains a compatibility
819
+ // fallback for existing ACP supports.
820
+ const needsAuth = code === "invalid_credentials" || code === "inactive_subscription"
821
+ || message === support.loginNote;
822
+ emit({
823
+ ...base(threadId, turnId),
824
+ type: "runtime.error",
825
+ message,
826
+ ...(needsAuth ? { setup: true } : {}),
827
+ });
828
+ settle(false, needsAuth ? "auth_required" : "rpc_error");
829
+ }
830
+ }
831
+ })();
832
+ return { turnId };
833
+ };
834
+ const snapshot = async () => {
835
+ const env = childEnv();
836
+ if (support.snapshot)
837
+ return support.snapshot(env, config, instanceId);
838
+ const version = await new Promise((resolve) => {
839
+ execCli(config.cli, ["--version"], { timeout: 8000, env }, (err, stdout) => resolve(err ? null : stdout.trim()));
840
+ });
841
+ if (!version)
842
+ return { state: "unavailable", reason: `\`${config.cli}\` CLI not found` };
843
+ return { state: "available", version, authenticated: await support.isAuthenticated(env, config, instanceId) };
844
+ };
845
+ return {
846
+ instanceId,
847
+ driverKind: DRIVER_KIND,
848
+ displayName: input.displayName,
849
+ enabled: input.enabled,
850
+ get models() {
851
+ return models;
852
+ },
853
+ refreshModels: support.resolveModels ? refreshModels : undefined,
854
+ snapshot,
855
+ adapter: {
856
+ provider: DRIVER_KIND,
857
+ capabilities: {
858
+ sessionModelSwitch: "unsupported",
859
+ agentsMcp: true,
860
+ customMcp: true,
861
+ computerMcp: true,
862
+ composioMcp: true,
863
+ browserMcp: true,
864
+ images: support.images !== false,
865
+ nativeImageInput: support.images === true,
866
+ effortLevels: support.effortLevels,
867
+ // OpenMausBot supplies a per-bot approvalMode on every harness
868
+ // turn, which safely overrides a legacy instance fullAuto value.
869
+ // Direct adapter calls that omit it still fail closed in sendTurn.
870
+ localComputerMcp: true,
871
+ },
872
+ sendTurn,
873
+ interruptTurn: async (threadId) => active.get(threadId)?.interrupt(),
874
+ respondToRequest: async (threadId, requestId, decision) => {
875
+ const turn = active.get(threadId);
876
+ const finish = turn?.asks.get(requestId);
877
+ if (!finish)
878
+ return "unavailable"; // settled, timed out, or turn gone
879
+ finish(decision.behavior, "user", decision.message);
880
+ return decision.behavior === "allow"
881
+ ? "allowed-once"
882
+ : decision.behavior === "answer"
883
+ ? "answered"
884
+ : "rejected";
885
+ },
886
+ hasSession: (threadId) => active.has(threadId),
887
+ stopAll: async () => {
888
+ for (const { stop } of active.values())
889
+ stop();
890
+ },
891
+ onEvent: (listener) => {
892
+ listeners.add(listener);
893
+ return () => listeners.delete(listener);
894
+ },
895
+ },
896
+ dispose: async () => {
897
+ for (const { stop } of active.values())
898
+ stop();
899
+ listeners.clear();
900
+ },
901
+ };
902
+ },
903
+ };
904
+ }