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,224 @@
1
+ import { z } from "zod";
2
+ import { schemaIssue } from "./schema.js";
3
+ import { botMascotBody } from "../shared/mascot-bodies.js";
4
+ import { takeImportName } from "../shared/import-name.js";
5
+ export const TEAM_MANIFEST_FORMAT = "openmaus.team";
6
+ export const TEAM_MANIFEST_VERSION = 2;
7
+ export const LEGACY_TEAM_MANIFEST_VERSION = 1;
8
+ export const MAX_TEAM_MEMBERS = 200;
9
+ const COLORS = [
10
+ "green",
11
+ "blue",
12
+ "red",
13
+ "orange",
14
+ "purple",
15
+ "cyan",
16
+ "pink",
17
+ "yellow",
18
+ "teal",
19
+ "coral",
20
+ ];
21
+ const requiredText = (max) => z.string({ error: "must be text" }).trim().min(1, { message: "is required" }).max(max, { message: "is too long" });
22
+ const optionalText = (max) => z
23
+ .union([z.string({ error: "must be text" }), z.null(), z.undefined()])
24
+ .transform((value) => value?.trim() || undefined)
25
+ .refine((value) => value === undefined || value.length <= max, { message: "is too long" })
26
+ .optional();
27
+ const responderSchema = z.discriminatedUnion("kind", [
28
+ z.object({ kind: z.literal("member"), member: requiredText(64) }),
29
+ z.object({ kind: z.literal("everyone") }),
30
+ z.object({ kind: z.literal("mentions") }),
31
+ ]);
32
+ const memberSchema = z.object({
33
+ key: requiredText(64).regex(/^[a-z0-9][a-z0-9_-]*$/, {
34
+ message: "may only contain lowercase letters, numbers, - and _",
35
+ }),
36
+ name: requiredText(100),
37
+ title: optionalText(200),
38
+ description: optionalText(4_000),
39
+ appearance: z.object({
40
+ color: z.enum(COLORS, { error: "is not supported" }),
41
+ mascotExpression: optionalText(80),
42
+ mascotBody: optionalText(40),
43
+ }),
44
+ });
45
+ const membersSchema = z
46
+ .array(memberSchema)
47
+ .min(1, { message: "A team needs at least one member" })
48
+ .max(MAX_TEAM_MEMBERS, { message: `A team can have at most ${MAX_TEAM_MEMBERS} members` });
49
+ const manifestSchema = z.discriminatedUnion("version", [
50
+ z.object({
51
+ format: z.literal(TEAM_MANIFEST_FORMAT, { error: "This is not an OpenMaus team file" }),
52
+ version: z.literal(LEGACY_TEAM_MANIFEST_VERSION),
53
+ team: z.object({
54
+ name: requiredText(100),
55
+ description: optionalText(2_000),
56
+ members: membersSchema,
57
+ room: z.object({
58
+ name: requiredText(100),
59
+ bulletin: optionalText(12_000),
60
+ defaultResponder: responderSchema,
61
+ }),
62
+ }),
63
+ }),
64
+ z.object({
65
+ format: z.literal(TEAM_MANIFEST_FORMAT, { error: "This is not an OpenMaus team file" }),
66
+ version: z.literal(TEAM_MANIFEST_VERSION),
67
+ team: z.object({
68
+ name: requiredText(100),
69
+ description: optionalText(2_000),
70
+ members: membersSchema,
71
+ }),
72
+ }),
73
+ ]);
74
+ export function parseTeamManifest(value) {
75
+ const parsed = manifestSchema.safeParse(value);
76
+ if (!parsed.success) {
77
+ const formatIssue = parsed.error.issues.find((issue) => issue.path[0] === "format");
78
+ if (formatIssue)
79
+ throw new Error(formatIssue.message);
80
+ const versionIssue = parsed.error.issues.find((issue) => issue.path[0] === "version");
81
+ if (versionIssue)
82
+ throw new Error("Team file version is not supported");
83
+ throw new Error(schemaIssue(parsed.error, "This is not a team file"));
84
+ }
85
+ const seenKeys = new Set();
86
+ const members = parsed.data.team.members.map((member) => {
87
+ if (seenKeys.has(member.key))
88
+ throw new Error(`Duplicate member key: ${member.key}`);
89
+ seenKeys.add(member.key);
90
+ const appearance = { color: member.appearance.color };
91
+ if (member.appearance.mascotExpression)
92
+ appearance.mascotExpression = member.appearance.mascotExpression;
93
+ if (member.appearance.mascotBody)
94
+ appearance.mascotBody = member.appearance.mascotBody;
95
+ return {
96
+ key: member.key,
97
+ name: member.name,
98
+ title: member.title ?? "",
99
+ description: member.description ?? "",
100
+ appearance,
101
+ };
102
+ });
103
+ const result = {
104
+ format: TEAM_MANIFEST_FORMAT,
105
+ version: parsed.data.version,
106
+ team: {
107
+ name: parsed.data.team.name,
108
+ members,
109
+ },
110
+ };
111
+ if (parsed.data.team.description)
112
+ result.team.description = parsed.data.team.description;
113
+ if (parsed.data.version === LEGACY_TEAM_MANIFEST_VERSION) {
114
+ const defaultResponder = parsed.data.team.room.defaultResponder;
115
+ if (defaultResponder.kind === "member" && !seenKeys.has(defaultResponder.member)) {
116
+ throw new Error(`Unknown default responder: ${defaultResponder.member}`);
117
+ }
118
+ result.team.room = {
119
+ name: parsed.data.team.room.name,
120
+ bulletin: parsed.data.team.room.bulletin ?? "",
121
+ defaultResponder,
122
+ };
123
+ }
124
+ return result;
125
+ }
126
+ /** Everything an untrusted manifest may seed into a brand-new bot — and
127
+ * nothing else.
128
+ *
129
+ * A team file can come from the remote catalog, a GitHub repo, or a file
130
+ * someone shared, so import is additive-only: a manifest is a persona
131
+ * description, never a grant, and never a handle on records the user
132
+ * already has. Two rules are enforced here, at the single point where a
133
+ * member becomes bot fields:
134
+ *
135
+ * 1. Allowlist, not blocklist. The returned object is built field by field
136
+ * from the parsed member, so every privilege-bearing BotRecord field —
137
+ * approvalMode, autoApprove, autoReview, alwaysAllow, chiefOfStaff, approvePeerComms, composio,
138
+ * computer, cloudBackend, cwd — is structurally absent, whatever the
139
+ * file claimed. parseTeamManifest already drops unknown member keys;
140
+ * this keeps the guarantee even if the schema grows a field later,
141
+ * because nothing new can reach a bot record without someone
142
+ * consciously widening this return type. The caller must still force
143
+ * composio: false on the created record — that is the one privilege
144
+ * where *absence* means allowed, so leaving it unset is not safe.
145
+ *
146
+ * 2. No name captures. Display names are identity wherever bots address
147
+ * each other — @mention resolution in rooms, the Chief of Staff roster,
148
+ * peer-approval prompts — so an imported member wearing an existing
149
+ * bot's name could be mentioned, granted, or listed as if it were that
150
+ * bot. A colliding name is therefore visibly numbered ("Scout" →
151
+ * "Scout 2"), the same convention the name generator uses when its pool
152
+ * runs out. Matching is case-insensitive because @mention matching is.
153
+ * `takenNames` (lowercased) is mutated as names are claimed, so one
154
+ * import batch also stays unique against itself; a suffixed name never
155
+ * exceeds the member-name cap.
156
+ */
157
+ export function importedMemberProfile(member, takenNames) {
158
+ const name = takeImportName(member.name, takenNames);
159
+ const profile = {
160
+ name,
161
+ title: member.title,
162
+ description: member.description,
163
+ color: member.appearance.color,
164
+ };
165
+ if (member.appearance.mascotExpression)
166
+ profile.mascotExpression = member.appearance.mascotExpression;
167
+ // The manifest carries the body as free text (parseTeamManifest only
168
+ // bounds its length); an untrusted or stale value must never reach a
169
+ // BotRecord unvalidated, so it is safe-parsed here — the one point where
170
+ // an imported member becomes bot fields — falling back to the default
171
+ // body rather than rejecting the whole import over a cosmetic field.
172
+ if (member.appearance.mascotBody)
173
+ profile.mascotBody = botMascotBody(member.appearance.mascotBody);
174
+ return profile;
175
+ }
176
+ function memberKey(name, index, used) {
177
+ const stem = name
178
+ .normalize("NFKD")
179
+ .replace(/[\u0300-\u036f]/g, "")
180
+ .toLowerCase()
181
+ .replace(/[^a-z0-9]+/g, "-")
182
+ .replace(/^-|-$/g, "")
183
+ .slice(0, 48) || `member-${index + 1}`;
184
+ let key = stem;
185
+ let suffix = 2;
186
+ while (used.has(key))
187
+ key = `${stem}-${suffix++}`;
188
+ used.add(key);
189
+ return key;
190
+ }
191
+ /** Build a shareable definition only: no IDs, transcripts, engines or permissions. */
192
+ export function createTeamManifest(team, bots) {
193
+ const byId = new Map(bots.map((bot) => [bot.id, bot]));
194
+ const usedKeys = new Set();
195
+ const members = team.memberIds.map((id, index) => {
196
+ const bot = byId.get(id);
197
+ if (!bot)
198
+ throw new Error(`Team member ${id} no longer exists`);
199
+ const key = memberKey(bot.name, index, usedKeys);
200
+ const appearance = { color: bot.color };
201
+ if (bot.mascotExpression)
202
+ appearance.mascotExpression = bot.mascotExpression;
203
+ if (bot.mascotBody)
204
+ appearance.mascotBody = bot.mascotBody;
205
+ return {
206
+ key,
207
+ name: bot.name,
208
+ title: bot.title,
209
+ description: bot.description,
210
+ appearance,
211
+ };
212
+ });
213
+ const manifest = {
214
+ format: TEAM_MANIFEST_FORMAT,
215
+ version: TEAM_MANIFEST_VERSION,
216
+ team: {
217
+ name: team.name,
218
+ members,
219
+ },
220
+ };
221
+ // Keep export and import in lockstep: a file produced here must satisfy
222
+ // the exact same limits and normalization as an untrusted shared file.
223
+ return parseTeamManifest(manifest);
224
+ }
@@ -0,0 +1,226 @@
1
+ // The inspector's data: what a thread's turn actually looked like on the
2
+ // wire. Nothing new is captured here — the harness already tees two logs
3
+ // per thread, and this just reads them back:
4
+ //
5
+ // events/<threadId>.ndjson — the normalized RuntimeEvent stream the bus
6
+ // publishes (server/harness/bus.ts)
7
+ // native/<threadId>.ndjson — the provider's own protocol messages,
8
+ // verbatim and secret-redacted
9
+ // (server/drivers/native.ts)
10
+ //
11
+ // Merged by timestamp so a tool call and the raw message behind it sit
12
+ // next to each other. Newest-`limit` only: a long-lived thread has
13
+ // thousands of native lines and the panel wants the recent ones first.
14
+ import { closeSync, fstatSync, openSync, readSync } from "node:fs";
15
+ import { join } from "node:path";
16
+ const DEFAULT_LIMIT = 300;
17
+ const MAX_LIMIT = 2000;
18
+ const READ_CHUNK = 64 * 1024;
19
+ const MAX_TAIL_BYTES = 8 * 1024 * 1024;
20
+ // Counts are incremental per append-only log. The first request scans bytes
21
+ // once (without decoding or parsing every JSON record); later requests inspect
22
+ // only bytes appended since the cached size. Keep this bounded across threads.
23
+ const lineCounts = new Map();
24
+ const LINE_COUNT_CACHE_MAX = 256;
25
+ /** Thread ids are uuids the harness minted; anything else is not a file we
26
+ * should be reading. */
27
+ function assertThreadId(threadId) {
28
+ if (!/^[\w-]+$/.test(threadId))
29
+ throw new Error("invalid thread id");
30
+ }
31
+ function countLines(fd, file, stat) {
32
+ const previous = lineCounts.get(file);
33
+ const appended = previous &&
34
+ previous.dev === stat.dev &&
35
+ previous.ino === stat.ino &&
36
+ stat.size >= previous.size &&
37
+ (stat.size > previous.size || stat.mtimeMs === previous.mtimeMs);
38
+ if (appended && stat.size === previous.size)
39
+ return previous.complete + Number(previous.trailing);
40
+ let offset = appended ? previous.size : 0;
41
+ let complete = appended ? previous.complete : 0;
42
+ let trailing = appended ? previous.trailing : false;
43
+ while (offset < stat.size) {
44
+ const length = Math.min(READ_CHUNK, stat.size - offset);
45
+ const chunk = Buffer.allocUnsafe(length);
46
+ const read = readSync(fd, chunk, 0, length, offset);
47
+ if (read <= 0)
48
+ break;
49
+ for (let i = 0; i < read; i++) {
50
+ if (chunk[i] === 0x0a) {
51
+ if (trailing)
52
+ complete++;
53
+ trailing = false;
54
+ }
55
+ else if (chunk[i] !== 0x0d) {
56
+ trailing = true;
57
+ }
58
+ }
59
+ offset += read;
60
+ }
61
+ const next = { dev: stat.dev, ino: stat.ino, size: stat.size, mtimeMs: stat.mtimeMs, complete, trailing };
62
+ lineCounts.delete(file);
63
+ lineCounts.set(file, next);
64
+ while (lineCounts.size > LINE_COUNT_CACHE_MAX)
65
+ lineCounts.delete(lineCounts.keys().next().value);
66
+ return complete + Number(trailing);
67
+ }
68
+ function parseRecent(text, includeFirst, limit, valid) {
69
+ const lines = text.split("\n");
70
+ if (!includeFirst)
71
+ lines.shift();
72
+ const out = [];
73
+ for (const raw of lines) {
74
+ if (!raw)
75
+ continue;
76
+ try {
77
+ const value = JSON.parse(raw);
78
+ if (valid(value))
79
+ out.push(value);
80
+ }
81
+ catch {
82
+ // A torn line during a write, or a hand-edited record. Keep looking
83
+ // farther back until we still have `limit` valid recent entries.
84
+ }
85
+ }
86
+ return out.slice(-limit);
87
+ }
88
+ function readRecentLines(file, limit, valid) {
89
+ let fd;
90
+ try {
91
+ fd = openSync(file, "r");
92
+ }
93
+ catch {
94
+ return { lines: [], total: 0 };
95
+ }
96
+ try {
97
+ const stat = fstatSync(fd);
98
+ const total = countLines(fd, file, stat);
99
+ let position = stat.size;
100
+ let bytes = Buffer.alloc(0);
101
+ let lines = [];
102
+ while (position > 0 && bytes.length < MAX_TAIL_BYTES) {
103
+ const remaining = MAX_TAIL_BYTES - bytes.length;
104
+ const start = Math.max(0, position - Math.min(READ_CHUNK, remaining));
105
+ const length = position - start;
106
+ const chunk = Buffer.allocUnsafe(length);
107
+ const read = readSync(fd, chunk, 0, length, start);
108
+ if (read <= 0)
109
+ break;
110
+ bytes = Buffer.concat([chunk.subarray(0, read), bytes]);
111
+ position = start;
112
+ // The first line is partial until we reach byte zero. Parse only once
113
+ // enough complete candidates exist; corrupt candidates make us keep
114
+ // walking backwards rather than returning fewer valid rows.
115
+ const text = bytes.toString("utf8");
116
+ if (position === 0 || text.split("\n").length - 1 >= limit) {
117
+ lines = parseRecent(text, position === 0, limit, valid);
118
+ if (lines.length >= limit || position === 0)
119
+ break;
120
+ }
121
+ }
122
+ if (lines.length === 0 && bytes.length > 0) {
123
+ lines = parseRecent(bytes.toString("utf8"), position === 0, limit, valid);
124
+ }
125
+ return { lines, total };
126
+ }
127
+ finally {
128
+ closeSync(fd);
129
+ }
130
+ }
131
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
132
+ const stringOrMissing = (value) => value === undefined || typeof value === "string";
133
+ const stringOrNullOrMissing = (value) => value === undefined || value === null || typeof value === "string";
134
+ const numberOrNullOrMissing = (value) => value === undefined || value === null || typeof value === "number";
135
+ const stringsOrMissing = (value) => value === undefined || (Array.isArray(value) && value.every((item) => typeof item === "string"));
136
+ function isRuntimeEvent(value) {
137
+ if (!isRecord(value) ||
138
+ typeof value.eventId !== "string" ||
139
+ typeof value.provider !== "string" ||
140
+ typeof value.threadId !== "string" ||
141
+ typeof value.createdAt !== "string" ||
142
+ typeof value.type !== "string" ||
143
+ !stringOrMissing(value.providerInstanceId) ||
144
+ !stringOrMissing(value.turnId) ||
145
+ !stringOrMissing(value.itemId) ||
146
+ !stringOrMissing(value.requestId))
147
+ return false;
148
+ switch (value.type) {
149
+ case "session.started":
150
+ return (value.sessionId === null || typeof value.sessionId === "string") && stringOrNullOrMissing(value.model);
151
+ case "session.exited":
152
+ return stringOrMissing(value.reason);
153
+ case "turn.started":
154
+ return true;
155
+ case "turn.retrying":
156
+ return (typeof value.attempt === "number" &&
157
+ Number.isInteger(value.attempt) &&
158
+ value.attempt >= 1 &&
159
+ typeof value.delayMs === "number" &&
160
+ Number.isFinite(value.delayMs) &&
161
+ value.delayMs >= 0 &&
162
+ typeof value.reason === "string");
163
+ case "turn.completed":
164
+ return (typeof value.ok === "boolean" &&
165
+ stringOrNullOrMissing(value.stopReason) &&
166
+ numberOrNullOrMissing(value.cost) &&
167
+ stringsOrMissing(value.denials) &&
168
+ (value.usage === undefined ||
169
+ (isRecord(value.usage) && typeof value.usage.input === "number" && typeof value.usage.output === "number")));
170
+ case "item.started":
171
+ return (value.itemType === "tool" || value.itemType === "reasoning") && stringOrMissing(value.title);
172
+ case "item.updated":
173
+ return (value.itemType === "tool" || value.itemType === "reasoning") && numberOrNullOrMissing(value.tokens);
174
+ case "item.completed":
175
+ return value.itemType === "assistant_text" ? typeof value.text === "string" : value.itemType === "tool" && typeof value.ok === "boolean";
176
+ case "content.delta":
177
+ return (value.streamKind === "assistant_text" || value.streamKind === "reasoning_text") && typeof value.delta === "string";
178
+ case "request.opened":
179
+ return ((value.requestType === "permission" || value.requestType === "question") &&
180
+ typeof value.tool === "string" &&
181
+ typeof value.summary === "string" &&
182
+ stringsOrMissing(value.choices));
183
+ case "request.resolved":
184
+ return ((value.behavior === "allow" || value.behavior === "deny" || value.behavior === "answer") &&
185
+ (value.source === "user" ||
186
+ value.source === "auto" ||
187
+ value.source === "timeout" ||
188
+ value.source === "system" ||
189
+ value.source === "unavailable" ||
190
+ value.source === "peer"));
191
+ case "thread.token-usage.updated":
192
+ return typeof value.input === "number" && typeof value.output === "number";
193
+ case "runtime.error":
194
+ return typeof value.message === "string" && (value.setup === undefined || typeof value.setup === "boolean");
195
+ default:
196
+ return false;
197
+ }
198
+ }
199
+ function isNativeRecord(value) {
200
+ return (isRecord(value) &&
201
+ typeof value.at === "string" &&
202
+ (value.dir === "in" || value.dir === "out") &&
203
+ typeof value.source === "string" &&
204
+ Object.hasOwn(value, "msg"));
205
+ }
206
+ export function readThreadEvents(input) {
207
+ const { eventsDir, nativeDir, threadId } = input;
208
+ assertThreadId(threadId);
209
+ const requested = input.limit ?? DEFAULT_LIMIT;
210
+ const limit = Number.isFinite(requested) ? Math.max(1, Math.min(Math.trunc(requested), MAX_LIMIT)) : DEFAULT_LIMIT;
211
+ const runtime = readRecentLines(join(eventsDir, `${threadId}.ndjson`), limit, isRuntimeEvent);
212
+ const native = readRecentLines(join(nativeDir, `${threadId}.ndjson`), limit, isNativeRecord);
213
+ // cap each log on its own, then merge: the native tee is several times
214
+ // chattier than the runtime stream, and one shared cap would leave the
215
+ // Events lens with a handful of rows behind hundreds of raw ones
216
+ const merged = [
217
+ ...runtime.lines.map((data) => ({ kind: "runtime", at: data.createdAt, data })),
218
+ ...native.lines.map((data) => ({ kind: "native", at: data.at, data })),
219
+ ];
220
+ // stable sort: ties keep file order, which is emit order
221
+ merged.sort((a, b) => (a.at < b.at ? -1 : a.at > b.at ? 1 : 0));
222
+ return {
223
+ entries: merged,
224
+ total: { runtime: runtime.total, native: native.total },
225
+ };
226
+ }
@@ -0,0 +1,92 @@
1
+ // ElevenLabs, the one voice.
2
+ //
3
+ // Everything about talking to the service lives in this file: verifying a
4
+ // key, listing voices, and turning one utterance into mp3 bytes. It runs on
5
+ // the HARNESS, never the renderer, because the key must not leave the
6
+ // server — GET /api/config reports configured-or-not booleans and nothing
7
+ // else, and that invariant is worth more than a saved round trip.
8
+ //
9
+ // One request per utterance rather than the streaming-input WebSocket: the
10
+ // client already splits text into utterances and fetches the next while the
11
+ // current one plays, which gets the same perceived latency with far fewer
12
+ // moving parts — and no socket to leak when a turn is interrupted.
13
+ const API = process.env.OMB_ELEVENLABS_API || "https://api.elevenlabs.io/v1";
14
+ const MODEL = "eleven_flash_v2_5";
15
+ // 64kbps mono is indistinguishable for speech and a third of the bytes
16
+ const FORMAT = "mp3_44100_64";
17
+ async function safeJson(res) {
18
+ try {
19
+ return await res.json();
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ }
25
+ /** Prefer ElevenLabs' own words over anything we can invent — it knows the
26
+ * plan, the quota and the model name. Mirrors box.boxErrorMessage. */
27
+ function message(status, what, body) {
28
+ const theirs = (typeof body?.detail === "string" && body.detail.trim()) ||
29
+ (typeof body?.detail?.message === "string" && body.detail.message.trim()) ||
30
+ (typeof body?.message === "string" && body.message.trim()) ||
31
+ "";
32
+ if (status === 401 || status === 403) {
33
+ // Restricted keys are the common case, not a corner: a key with the
34
+ // wrong scopes is REAL and still fails, so saying "copy a fresh one"
35
+ // sends people to regenerate a key that was never the problem.
36
+ return "ElevenLabs rejected that key. If it's a restricted key, give it the Voices and Text to Speech permissions — or paste an unrestricted one.";
37
+ }
38
+ if (status === 429)
39
+ return theirs || "ElevenLabs is rate-limiting this account — wait a moment and try again.";
40
+ if (status === 402)
41
+ return theirs || "ElevenLabs says this account is out of credit.";
42
+ return theirs ? `${what} failed: ${theirs}` : `${what} failed (${status})`;
43
+ }
44
+ /** Check a key before we store it: a rejected credential must fail at the
45
+ * paste, not hours later in another panel with nothing to act on.
46
+ *
47
+ * Checked against /voices, NOT /user. ElevenLabs keys carry per-endpoint
48
+ * scopes, and a key restricted to speech has no `user_read` — verifying
49
+ * there rejects perfectly good keys for a permission this feature never
50
+ * uses (found the hard way, with a real key). /voices is what the settings
51
+ * picker needs next, so it tests exactly the capability that matters. */
52
+ export async function verifyKey(key) {
53
+ try {
54
+ const res = await fetch(`${API}/voices`, {
55
+ headers: { "xi-api-key": key },
56
+ signal: AbortSignal.timeout(20_000),
57
+ });
58
+ if (res.ok)
59
+ return { ok: true };
60
+ return { ok: false, message: message(res.status, "checking that key", await safeJson(res)) };
61
+ }
62
+ catch {
63
+ return { ok: false, message: "Couldn't reach ElevenLabs to check that key — check your connection." };
64
+ }
65
+ }
66
+ export async function listVoices(key) {
67
+ const res = await fetch(`${API}/voices`, {
68
+ headers: { "xi-api-key": key },
69
+ signal: AbortSignal.timeout(20_000),
70
+ });
71
+ const body = await safeJson(res);
72
+ if (!res.ok)
73
+ throw new Error(message(res.status, "listing voices", body));
74
+ return (body?.voices ?? [])
75
+ .map((v) => ({
76
+ id: String(v.voice_id ?? ""),
77
+ label: String(v.name ?? "Voice"),
78
+ description: [v.labels?.accent, v.labels?.description].filter(Boolean).join(" · ") || undefined,
79
+ }))
80
+ .filter((v) => v.id);
81
+ }
82
+ export async function synthesize(text, voiceId, key) {
83
+ const res = await fetch(`${API}/text-to-speech/${encodeURIComponent(voiceId)}?output_format=${FORMAT}`, {
84
+ method: "POST",
85
+ headers: { "xi-api-key": key, "content-type": "application/json", accept: "audio/mpeg" },
86
+ body: JSON.stringify({ text, model_id: MODEL }),
87
+ signal: AbortSignal.timeout(60_000),
88
+ });
89
+ if (!res.ok)
90
+ throw new Error(message(res.status, "speaking", await safeJson(res)));
91
+ return { bytes: new Uint8Array(await res.arrayBuffer()), mime: "audio/mpeg" };
92
+ }
@@ -0,0 +1,79 @@
1
+ import * as elevenlabs from "./elevenlabs.js";
2
+ import * as systemVoices from "./system-voices.js";
3
+ export class NoVoiceConfigured extends Error {
4
+ // a plain field rather than a constructor parameter property: the harness
5
+ // runs under `node --experimental-strip-types`, which is strip-ONLY, so a
6
+ // parameter property is rejected at load time even though it typechecks
7
+ reason;
8
+ constructor(reason) {
9
+ super(reason === "key"
10
+ ? "Add an ElevenLabs key in Settings on the computer to turn on voice."
11
+ : "Pick a voice in the agent profile.");
12
+ this.reason = reason;
13
+ }
14
+ }
15
+ export function voiceProvider(cfg) {
16
+ return cfg.tts?.provider === "system" ? "system" : "elevenlabs";
17
+ }
18
+ /** The system provider needs no credential — it is only ever offered where
19
+ * the platform actually has it, so "configured" means "this engine can
20
+ * speak", not "a key is on file". */
21
+ export function providerConfigured(cfg) {
22
+ return voiceProvider(cfg) === "system" ? systemVoices.systemVoicesAvailable() : Boolean(cfg.tts?.key);
23
+ }
24
+ export function voiceConfigured(cfg) {
25
+ if (voiceProvider(cfg) === "system") {
26
+ return systemVoices.systemVoicesAvailable() && Boolean(cfg.tts?.voice);
27
+ }
28
+ return Boolean(cfg.tts?.key && cfg.tts?.voice);
29
+ }
30
+ /** A per-bot voice is a complete choice too; it should not be blocked just
31
+ * because the app-wide fallback has not been selected yet. */
32
+ export function voiceReady(cfg, voiceId) {
33
+ if (voiceProvider(cfg) === "system") {
34
+ return systemVoices.systemVoicesAvailable() && Boolean(voiceId || cfg.tts?.voice);
35
+ }
36
+ return Boolean(cfg.tts?.key && (voiceId || cfg.tts?.voice));
37
+ }
38
+ /** What the settings panel needs. Never includes the key — same write-only
39
+ * rule as every other credential. */
40
+ export function describeVoice(cfg) {
41
+ return {
42
+ configured: providerConfigured(cfg),
43
+ ready: voiceConfigured(cfg),
44
+ voice: cfg.tts?.voice ?? "",
45
+ provider: voiceProvider(cfg),
46
+ };
47
+ }
48
+ export function verifyKey(key) {
49
+ return elevenlabs.verifyKey(key);
50
+ }
51
+ export async function listVoices(cfg, run) {
52
+ if (voiceProvider(cfg) === "system")
53
+ return systemVoices.listSystemVoices(run);
54
+ const key = cfg.tts?.key;
55
+ if (!key)
56
+ return [];
57
+ return elevenlabs.listVoices(key);
58
+ }
59
+ /** Synthesize one utterance. Throws NoVoiceConfigured when there is nothing
60
+ * to speak with, which the route turns into a 409 the client can explain. */
61
+ export function speak(cfg, text, voiceId, run) {
62
+ if (voiceProvider(cfg) === "system") {
63
+ const voice = voiceId || cfg.tts?.voice;
64
+ // An injected runner is the cross-platform test seam for `/usr/bin/say`;
65
+ // production calls omit it and remain strictly Darwin-gated.
66
+ if (!systemVoices.systemVoicesAvailable() && !run)
67
+ throw new NoVoiceConfigured("key");
68
+ if (!voice)
69
+ throw new NoVoiceConfigured("voice");
70
+ return systemVoices.synthesizeSystem(text, voice, run);
71
+ }
72
+ const key = cfg.tts?.key;
73
+ if (!key)
74
+ throw new NoVoiceConfigured("key");
75
+ const voice = voiceId || cfg.tts?.voice;
76
+ if (!voice)
77
+ throw new NoVoiceConfigured("voice");
78
+ return elevenlabs.synthesize(text, voice, key);
79
+ }