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,628 @@
1
+ // Async peer handoff (delegate_bot).
2
+ //
3
+ // A bot that finishes one task can hand the NEXT task to a peer without
4
+ // blocking its own turn — the source bot's turn.completed fires after it
5
+ // settles, and the queued delegation runs then. The peer gets a fresh
6
+ // depth-1 turn (depth cap still blocks A→B→C chains, see index.ts).
7
+ //
8
+ // Visiblity rides on the same comms-visibility helpers ask_bot uses
9
+ // (channel mirror + 1:1 chips) so a delegated exchange looks like an
10
+ // exchanged one. The optional approval gate (A2) is checked at drain
11
+ // time, never at queue time, because the user might have just turned
12
+ // approvePeerComms on between queueing and draining.
13
+ import { readFileSync } from "node:fs";
14
+ import { join } from "node:path";
15
+ import { writeFileAtomic } from "./atomic.js";
16
+ import { getOrCreateChannel, mirrorExchange } from "./comms-visibility.js";
17
+ import { DATA_DIR } from "./config.js";
18
+ import { newId } from "./contracts.js";
19
+ import { requestPeerApproval } from "./peer-approval.js";
20
+ import { peerAllowed } from "./peer-roster.js";
21
+ import { sectionKey } from "./store.js";
22
+ /** Per source-thread queue. Persisted to delegations.json on every change
23
+ * and reloaded at boot: a handoff queued right before a restart runs after
24
+ * it. (Provider PERMISSIONS still die with the process — nobody can answer
25
+ * for an unattended bot — but queued work is not a permission; the target
26
+ * and approvePeerComms are re-checked at drain time as always.) */
27
+ const pendingDelegations = new Map();
28
+ const drainingThreads = new Set();
29
+ /** Threads whose drain was requested WHILE a drain was already running.
30
+ * Dropping such a request loses real work: the waiting-on retry fires the
31
+ * moment a busy target settles, and that can land mid-drain. */
32
+ const queuedRedrains = new Set();
33
+ const DELEGATIONS_FILE = join(DATA_DIR, "delegations.json");
34
+ const RECEIPTS_FILE = join(DATA_DIR, "delegation-receipts.json");
35
+ const MAX_RECEIPTS = 100;
36
+ const RECEIPT_MAX_AGE_MS = 48 * 60 * 60 * 1000;
37
+ const RESULT_MAX_CHARS = 4_000;
38
+ export const MAX_BUSY_ATTEMPTS = 3;
39
+ let receipts = [];
40
+ function saveReceipts() {
41
+ try {
42
+ writeFileAtomic(RECEIPTS_FILE, JSON.stringify(receipts, null, 2), { mode: 0o600 });
43
+ }
44
+ catch (error) {
45
+ console.error("delegations: could not persist receipts", error);
46
+ }
47
+ }
48
+ /** Record one terminal outcome. Newest first; pruned by count and age so the
49
+ * drawer can never grow without bound. */
50
+ export function recordDelegationReceipt(receipt) {
51
+ const now = Date.now();
52
+ const bounded = {
53
+ id: receipt.id,
54
+ sourceThreadId: receipt.sourceThreadId,
55
+ toBotId: receipt.toBotId,
56
+ toBotName: receipt.toBotName,
57
+ status: receipt.status,
58
+ finishedAt: receipt.finishedAt ?? now,
59
+ };
60
+ if (receipt.result !== undefined)
61
+ bounded.result = receipt.result.slice(0, RESULT_MAX_CHARS);
62
+ receipts = [bounded, ...receipts.filter((existing) => existing.id !== bounded.id)]
63
+ .filter((existing) => now - existing.finishedAt <= RECEIPT_MAX_AGE_MS)
64
+ .slice(0, MAX_RECEIPTS);
65
+ saveReceipts();
66
+ }
67
+ export function findDelegationReceipt(id) {
68
+ return receipts.find((receipt) => receipt.id === id) ?? null;
69
+ }
70
+ /** A still-queued task's routing info, or null once it dispatched/settled. */
71
+ export function pendingDelegationInfo(id) {
72
+ for (const [sourceThreadId, items] of pendingDelegations) {
73
+ const item = items.find((candidate) => candidate.id === id);
74
+ if (item)
75
+ return { sourceThreadId, toBotId: item.toBotId, attempts: item.attempts };
76
+ }
77
+ return null;
78
+ }
79
+ /** Source threads currently waiting for this busy bot — the set its idle
80
+ * transition re-drains. Fresh items are excluded: they run when their SOURCE
81
+ * turn settles, and draining them early would start the peer too soon. */
82
+ export function threadsWaitingOn(toBotId) {
83
+ return [...pendingDelegations.entries()]
84
+ .filter(([, items]) => items.some((item) => item.toBotId === toBotId && item.waitingOnBusy === true))
85
+ .map(([threadId]) => threadId);
86
+ }
87
+ /** Mark a target's observed busy period as finished and return the source
88
+ * threads that should be retried. This makes retries count distinct busy
89
+ * periods, not unrelated drain requests on the same source thread. */
90
+ export function releaseDelegationsWaitingOn(toBotId) {
91
+ const threads = threadsWaitingOn(toBotId);
92
+ if (!threads.length)
93
+ return threads;
94
+ for (const threadId of threads) {
95
+ for (const item of pendingDelegations.get(threadId) ?? []) {
96
+ if (item.toBotId === toBotId)
97
+ delete item.waitingOnBusy;
98
+ }
99
+ }
100
+ savePending();
101
+ return threads;
102
+ }
103
+ function savePending() {
104
+ try {
105
+ writeFileAtomic(DELEGATIONS_FILE, JSON.stringify(Object.fromEntries(pendingDelegations), null, 2), { mode: 0o600 });
106
+ }
107
+ catch (error) {
108
+ console.error("delegations: could not persist queue", error);
109
+ }
110
+ }
111
+ /** Load what a previous process left queued. Missing or corrupt → empty. */
112
+ export function _loadPending() {
113
+ pendingDelegations.clear();
114
+ try {
115
+ const raw = JSON.parse(readFileSync(DELEGATIONS_FILE, "utf8"));
116
+ for (const [threadId, list] of Object.entries(raw)) {
117
+ if (!Array.isArray(list))
118
+ continue;
119
+ const items = list.flatMap((value) => {
120
+ if (!value || typeof value !== "object")
121
+ return [];
122
+ const item = value;
123
+ if (typeof item.toBotId !== "string" ||
124
+ typeof item.message !== "string" ||
125
+ !Number.isFinite(item.depth))
126
+ return [];
127
+ const loaded = {
128
+ id: typeof item.id === "string" && item.id ? item.id : newId(),
129
+ sourceBotId: typeof item.sourceBotId === "string" && item.sourceBotId ? item.sourceBotId : "",
130
+ toBotId: item.toBotId,
131
+ message: item.message,
132
+ ...(typeof item.reason === "string" ? { reason: item.reason } : {}),
133
+ depth: Math.max(0, Math.trunc(item.depth)),
134
+ attempts: Number.isFinite(item.attempts) ? Math.max(0, Math.trunc(item.attempts)) : 0,
135
+ };
136
+ if (item.approvalAlreadyGranted === true)
137
+ loaded.approvalAlreadyGranted = true;
138
+ if (item.waitingOnBusy === true)
139
+ loaded.waitingOnBusy = true;
140
+ if (typeof item.originatingGroupId === "string" && item.originatingGroupId) {
141
+ loaded.originatingGroupId = item.originatingGroupId;
142
+ }
143
+ return [loaded];
144
+ });
145
+ if (items.length)
146
+ pendingDelegations.set(threadId, items);
147
+ }
148
+ }
149
+ catch {
150
+ /* fresh install, or unreadable — start empty */
151
+ }
152
+ receipts = [];
153
+ try {
154
+ const rawReceipts = JSON.parse(readFileSync(RECEIPTS_FILE, "utf8"));
155
+ if (Array.isArray(rawReceipts)) {
156
+ const now = Date.now();
157
+ const loaded = [];
158
+ for (const value of rawReceipts) {
159
+ if (!value || typeof value !== "object" || Array.isArray(value))
160
+ continue;
161
+ // SAFETY: the Partial view only names candidate fields; every one is
162
+ // narrowed below before a receipt is constructed from the narrowed
163
+ // locals, so nothing unvalidated survives into `receipts`.
164
+ const candidate = value;
165
+ const { id, sourceThreadId, toBotId, toBotName, status, result, finishedAt } = candidate;
166
+ if (typeof id !== "string" || !id)
167
+ continue;
168
+ if (typeof sourceThreadId !== "string" || typeof toBotId !== "string")
169
+ continue;
170
+ if (typeof toBotName !== "string" || typeof status !== "string")
171
+ continue;
172
+ if (!Number.isFinite(finishedAt) || now - finishedAt > RECEIPT_MAX_AGE_MS)
173
+ continue;
174
+ const receipt = { id, sourceThreadId, toBotId, toBotName, status, finishedAt: finishedAt };
175
+ if (typeof result === "string")
176
+ receipt.result = result;
177
+ loaded.push(receipt);
178
+ }
179
+ receipts = loaded.slice(0, MAX_RECEIPTS);
180
+ }
181
+ }
182
+ catch {
183
+ /* no receipts yet */
184
+ }
185
+ }
186
+ /** Source threads with something queued — what a boot drain iterates. */
187
+ export function pendingThreads() {
188
+ return [...pendingDelegations.keys()];
189
+ }
190
+ /** Read-only metadata for the local Team Map. Task prompts stay private;
191
+ * the UI only needs to know who handed work to whom and the optional label. */
192
+ export function pendingDelegationSnapshot() {
193
+ return [...pendingDelegations.entries()].flatMap(([sourceThreadId, items]) => items.map((item) => ({
194
+ sourceThreadId,
195
+ sourceBotId: item.sourceBotId,
196
+ toBotId: item.toBotId,
197
+ ...(item.reason ? { reason: item.reason } : {}),
198
+ })));
199
+ }
200
+ /** How many handoffs one turn may queue. Small on purpose: this is the only
201
+ * thing standing between a confused bot and a fan-out of real turns. */
202
+ const MAX_QUEUED_PER_THREAD = 4;
203
+ /** Validate and enqueue a delegation. Pushes a "Delegated to @B: reason"
204
+ * chip to the source thread so the user can see what was queued. */
205
+ export function queueDelegation(bus, from, item, maxDepth, sourceThreadId = from.threadId) {
206
+ if (item.toBotId === from.id)
207
+ return { result: "self" };
208
+ if (item.depth >= maxDepth)
209
+ return { result: "too_deep" };
210
+ const target = bus.store.bot(item.toBotId);
211
+ if (!target)
212
+ return { result: "no_target" };
213
+ const list = pendingDelegations.get(sourceThreadId) ?? [];
214
+ // Async handoff removes the backpressure that ask_bot got for free by
215
+ // making the caller wait. Without a cap, one turn can queue unboundedly
216
+ // and fan out into as many real turns on the next settle.
217
+ if (list.length >= MAX_QUEUED_PER_THREAD)
218
+ return { result: "too_many" };
219
+ // If the source thread is a shared group that contains both bots, keep it
220
+ // as the authoritative channel instead of routing into a pair DM later.
221
+ const originatingGroup = item.originatingGroupId
222
+ ? bus.store.group(item.originatingGroupId)
223
+ : (sourceThreadId ? bus.store.groupByThread(sourceThreadId) : undefined);
224
+ const groupId = originatingGroup &&
225
+ !originatingGroup.dm &&
226
+ originatingGroup.memberIds.includes(from.id) &&
227
+ originatingGroup.memberIds.includes(target.id)
228
+ ? originatingGroup.id
229
+ : undefined;
230
+ const id = newId();
231
+ list.push({ ...item, id, sourceBotId: from.id, attempts: 0, ...(groupId ? { originatingGroupId: groupId } : {}) });
232
+ pendingDelegations.set(sourceThreadId, list);
233
+ savePending();
234
+ const label = `Delegated to @${target.name}${item.reason ? `: ${item.reason}` : ""}`;
235
+ const sourceGroup = sourceThreadId ? bus.store.groupByThread(sourceThreadId) : undefined;
236
+ bus.store.appendMessage(sourceThreadId, {
237
+ role: "bot",
238
+ kind: "activity",
239
+ // settled at birth: queueing is the whole act. Left open, the chip
240
+ // would spin until the transcript is closed — the chat never patches it
241
+ tool: { name: label, ok: true },
242
+ ...(sourceGroup && !sourceGroup.dm
243
+ ? { from: { botId: from.id, name: from.name, color: from.color } }
244
+ : {}),
245
+ });
246
+ return { result: "ok", id };
247
+ }
248
+ /** Drain queued delegations for a source thread (called on its
249
+ * turn.completed). Each item is processed independently: a deny, a busy
250
+ * target, or an error in one does not stop the rest. The actual start
251
+ * of the target turn is delegated to `runTarget` so delegations.ts
252
+ * stays free of harness-level concerns (commsDepth is the only thing
253
+ * the caller needs). */
254
+ export function drainDelegations(bus, approvalBus, threadId, runTarget) {
255
+ if (drainingThreads.has(threadId)) {
256
+ queuedRedrains.add(threadId);
257
+ return;
258
+ }
259
+ const list = pendingDelegations.get(threadId);
260
+ if (!list?.length)
261
+ return;
262
+ const snapshot = [...list];
263
+ drainingThreads.add(threadId);
264
+ void (async () => {
265
+ for (const item of snapshot) {
266
+ // A shared channel's thread is not owned by any single bot, so each
267
+ // queued item carries its own source bot identity.
268
+ const from = bus.store.botByThread(threadId) ??
269
+ bus.store.bot(item.sourceBotId);
270
+ if (!from) {
271
+ recordDelegationReceipt({
272
+ id: item.id,
273
+ sourceThreadId: threadId,
274
+ toBotId: item.toBotId,
275
+ toBotName: bus.store.bot(item.toBotId)?.name ?? item.toBotId,
276
+ status: "dropped",
277
+ result: "the delegating bot no longer exists",
278
+ });
279
+ acknowledgeDelegation(threadId, item.id);
280
+ continue;
281
+ }
282
+ let outcome = "settled";
283
+ try {
284
+ outcome = await processOne(bus, approvalBus, from, threadId, item, runTarget);
285
+ }
286
+ catch (error) {
287
+ const why = error instanceof Error ? error.message : String(error);
288
+ recordDelegationReceipt({
289
+ id: item.id,
290
+ sourceThreadId: threadId,
291
+ toBotId: item.toBotId,
292
+ toBotName: bus.store.bot(item.toBotId)?.name ?? item.toBotId,
293
+ status: "error",
294
+ result: why.slice(0, 200),
295
+ });
296
+ try {
297
+ bus.store.appendMessage(threadId, {
298
+ role: "bot",
299
+ kind: "activity",
300
+ tool: { name: `error: delegation failed — ${why.slice(0, 120)}`, ok: false },
301
+ });
302
+ }
303
+ catch (reportError) {
304
+ console.error("delegation failed and could not be reported", reportError);
305
+ }
306
+ }
307
+ finally {
308
+ // A requeued item (busy target, retries left) stays for the drain
309
+ // that the target's own settling turn will trigger.
310
+ if (outcome !== "requeued")
311
+ acknowledgeDelegation(threadId, item.id);
312
+ }
313
+ }
314
+ })().finally(() => {
315
+ drainingThreads.delete(threadId);
316
+ // A later turn may have queued and settled while this thread was
317
+ // waiting for approval. Only items OUTSIDE our snapshot warrant a fresh
318
+ // drain — re-draining a just-requeued item would burn its bounded busy
319
+ // retries in milliseconds instead of once per target settle.
320
+ const redrainRequested = queuedRedrains.delete(threadId);
321
+ const snapshotIds = new Set(snapshot.map((item) => item.id));
322
+ const hasNewItems = pendingDelegations.get(threadId)?.some((item) => !snapshotIds.has(item.id)) ?? false;
323
+ if (redrainRequested || hasNewItems) {
324
+ drainDelegations(bus, approvalBus, threadId, runTarget);
325
+ }
326
+ });
327
+ }
328
+ /** Remove one terminal handoff only after approval/dispatch has settled. */
329
+ function acknowledgeDelegation(threadId, itemId) {
330
+ const current = pendingDelegations.get(threadId);
331
+ if (!current)
332
+ return;
333
+ const remaining = current.filter((item) => item.id !== itemId);
334
+ if (remaining.length)
335
+ pendingDelegations.set(threadId, remaining);
336
+ else
337
+ pendingDelegations.delete(threadId);
338
+ savePending();
339
+ }
340
+ /** Drop a thread's queued handoffs without running them, telling the user
341
+ * they were dropped. Used when the queueing turn failed or was interrupted. */
342
+ export function discardDelegations(bus, threadId) {
343
+ const list = pendingDelegations.get(threadId);
344
+ if (!list?.length)
345
+ return;
346
+ pendingDelegations.delete(threadId);
347
+ savePending();
348
+ for (const item of list) {
349
+ recordDelegationReceipt({
350
+ id: item.id,
351
+ sourceThreadId: threadId,
352
+ toBotId: item.toBotId,
353
+ toBotName: bus.store.bot(item.toBotId)?.name ?? item.toBotId,
354
+ status: "dropped",
355
+ result: "the delegating turn did not finish",
356
+ });
357
+ }
358
+ const from = bus.store.botByThread(threadId) ??
359
+ bus.store.bot(list.find((item) => bus.store.bot(item.sourceBotId))?.sourceBotId ?? list[0].sourceBotId);
360
+ if (!from)
361
+ return;
362
+ bus.store.appendMessage(threadId, {
363
+ role: "bot",
364
+ kind: "activity",
365
+ tool: { name: `${list.length} queued delegation${list.length > 1 ? "s" : ""} dropped — the turn did not finish`, ok: false },
366
+ });
367
+ }
368
+ async function processOne(bus, approvalBus, from, sourceThreadId, item, runTarget) {
369
+ let sender = from;
370
+ let target = bus.store.bot(item.toBotId);
371
+ if (!target) {
372
+ recordDelegationReceipt({
373
+ id: item.id,
374
+ sourceThreadId,
375
+ toBotId: item.toBotId,
376
+ toBotName: item.toBotId,
377
+ status: "error",
378
+ result: "no such bot",
379
+ });
380
+ bus.store.appendMessage(sourceThreadId, {
381
+ role: "bot",
382
+ kind: "activity",
383
+ tool: { name: `error: delegation to ${item.toBotId} failed — no such bot`, ok: false },
384
+ });
385
+ return "settled";
386
+ }
387
+ if (dropIfUnreachable(bus, sender, target, sourceThreadId, item)) {
388
+ return "settled";
389
+ }
390
+ if (target.busy) {
391
+ if (item.waitingOnBusy)
392
+ return "requeued";
393
+ item.attempts += 1;
394
+ item.waitingOnBusy = true;
395
+ if (item.attempts < MAX_BUSY_ATTEMPTS) {
396
+ savePending();
397
+ bus.store.appendMessage(sourceThreadId, {
398
+ role: "bot",
399
+ kind: "activity",
400
+ tool: { name: `Delegation to @${target.name} waiting — they're busy (retry ${item.attempts}/${MAX_BUSY_ATTEMPTS} when they finish)` },
401
+ });
402
+ return "requeued";
403
+ }
404
+ recordDelegationReceipt({
405
+ id: item.id,
406
+ sourceThreadId,
407
+ toBotId: target.id,
408
+ toBotName: target.name,
409
+ status: "busy_gave_up",
410
+ result: `@${target.name} stayed busy through ${MAX_BUSY_ATTEMPTS} retries`,
411
+ });
412
+ bus.store.appendMessage(sourceThreadId, {
413
+ role: "bot",
414
+ kind: "activity",
415
+ tool: { name: `Delegation to @${target.name} canceled — still busy after ${MAX_BUSY_ATTEMPTS} retries`, ok: false },
416
+ });
417
+ return "settled";
418
+ }
419
+ if (item.waitingOnBusy) {
420
+ delete item.waitingOnBusy;
421
+ savePending();
422
+ }
423
+ if (sender.approvePeerComms && !item.approvalAlreadyGranted) {
424
+ const verdict = await requestPeerApproval(approvalBus, sender, target, item.message, "delegate_bot", sourceThreadId);
425
+ if (verdict !== "allow") {
426
+ recordDelegationReceipt({
427
+ id: item.id,
428
+ sourceThreadId,
429
+ toBotId: target.id,
430
+ toBotName: target.name,
431
+ status: "denied",
432
+ result: "the user denied this handoff",
433
+ });
434
+ bus.store.appendMessage(sourceThreadId, {
435
+ role: "bot",
436
+ kind: "activity",
437
+ tool: { name: `Delegation to @${target.name} denied by user`, ok: false },
438
+ });
439
+ return "settled";
440
+ }
441
+ // The approval could have been sitting for up to 15 minutes. Everything
442
+ // checked above is a stale snapshot now: re-read both bots and re-check
443
+ // busy, or an allow can start a second turn on a bot that is mid-turn —
444
+ // and mirror a "Messaged @X" chip for an exchange that never happens.
445
+ const current = bus.store.bot(item.toBotId);
446
+ const currentSender = bus.store.bot(from.id);
447
+ if (!current || !currentSender || !sourceThreadBelongsToBot(bus.store, currentSender.id, sourceThreadId))
448
+ return "settled";
449
+ if (dropIfUnreachable(bus, currentSender, current, sourceThreadId, item)) {
450
+ return "settled";
451
+ }
452
+ if (current.busy) {
453
+ if (item.waitingOnBusy)
454
+ return "requeued";
455
+ item.attempts += 1;
456
+ item.waitingOnBusy = true;
457
+ if (item.attempts < MAX_BUSY_ATTEMPTS) {
458
+ savePending();
459
+ bus.store.appendMessage(sourceThreadId, {
460
+ role: "bot",
461
+ kind: "activity",
462
+ tool: { name: `Delegation to @${current.name} waiting — they're busy (retry ${item.attempts}/${MAX_BUSY_ATTEMPTS} when they finish)` },
463
+ });
464
+ return "requeued";
465
+ }
466
+ recordDelegationReceipt({
467
+ id: item.id,
468
+ sourceThreadId,
469
+ toBotId: current.id,
470
+ toBotName: current.name,
471
+ status: "busy_gave_up",
472
+ result: `@${current.name} stayed busy through ${MAX_BUSY_ATTEMPTS} retries`,
473
+ });
474
+ bus.store.appendMessage(sourceThreadId, {
475
+ role: "bot",
476
+ kind: "activity",
477
+ tool: { name: `Delegation to @${current.name} canceled — still busy after ${MAX_BUSY_ATTEMPTS} retries`, ok: false },
478
+ });
479
+ return "settled";
480
+ }
481
+ sender = currentSender;
482
+ target = current;
483
+ }
484
+ // Use the originating group as the channel when both bots are still
485
+ // members; otherwise the exchange falls back to the pair DM.
486
+ const originatingGroup = (item.originatingGroupId ? bus.store.group(item.originatingGroupId) : undefined) ??
487
+ (sourceThreadId ? bus.store.groupByThread(sourceThreadId) : undefined);
488
+ const channel = getOrCreateChannel(bus.store, sender, target, originatingGroup);
489
+ mirrorExchange(bus, sender, target, item.message, channel, sourceThreadId);
490
+ const reasonLine = item.reason ? `\n\n[Reason: ${item.reason}]` : "";
491
+ const prefixed = `[Delegated by @${sender.name}, another bot in this OpenMausBot workspace. Do the work and reply directly.]\n\n${item.message}${reasonLine}`;
492
+ await runTarget(item.toBotId, prefixed, item.depth + 1, sourceThreadId, channel, item.id, sender.id);
493
+ return "settled";
494
+ }
495
+ /** The source thread may be a bot's own task or a shared group where the
496
+ * bot is a member. This is the same check the API gate uses for group turns. */
497
+ function sourceThreadBelongsToBot(store, botId, threadId) {
498
+ if (store.taskByThread(botId, threadId))
499
+ return true;
500
+ const group = store.groupByThread(threadId);
501
+ return Boolean(group && group.memberIds.includes(botId));
502
+ }
503
+ /** Section membership and the sender's peer allow-list are execution
504
+ * boundaries, not just sidebar styling. A queued handoff may wait through a
505
+ * turn, a busy target, or human approval, so the permission granted when it
506
+ * was queued must be checked again at the final dispatch edge — the user may
507
+ * have moved either bot, or narrowed the sender's peers, in between. */
508
+ function dropIfUnreachable(bus, sender, target, sourceThreadId, item) {
509
+ const sectionsDiffer = sectionKey(sender.section) !== sectionKey(target.section);
510
+ if (!sectionsDiffer && peerAllowed(sender, target.id))
511
+ return false;
512
+ const reason = sectionsDiffer
513
+ ? "bots now belong to different sections"
514
+ : `@${target.name} is no longer an allowed peer`;
515
+ const result = sectionsDiffer
516
+ ? `@${sender.name} and @${target.name} now belong to different sections`
517
+ : `@${sender.name} is no longer allowed to contact @${target.name}`;
518
+ recordDelegationReceipt({
519
+ id: item.id,
520
+ sourceThreadId,
521
+ toBotId: target.id,
522
+ toBotName: target.name,
523
+ status: "dropped",
524
+ result,
525
+ });
526
+ bus.store.appendMessage(sourceThreadId, {
527
+ role: "bot",
528
+ kind: "activity",
529
+ tool: { name: `Delegation to @${target.name} canceled — ${reason}`, ok: false },
530
+ });
531
+ return true;
532
+ }
533
+ /** Test helper: how many items remain queued for a thread. */
534
+ export function _pendingCount(threadId) {
535
+ return pendingDelegations.get(threadId)?.length ?? 0;
536
+ }
537
+ /** Test helper: forget the in-memory queue (a simulated restart). */
538
+ export function _resetPending() {
539
+ pendingDelegations.clear();
540
+ drainingThreads.clear();
541
+ queuedRedrains.clear();
542
+ receipts = [];
543
+ }
544
+ // ── peer wake (delegated reply resumes the source bot) ────────────────
545
+ // A successful delegated reply is appended to the source thread, but that
546
+ // alone leaves the source idle — the user has to nudge it ("what did the
547
+ // bot say?"). The harness wakes the source with a control-plane revival
548
+ // prompt so it can fold the result in and answer. The prompt is pure and
549
+ // testable; the burst budget below keeps a re-delegating bot from
550
+ // ping-ponging forever.
551
+ /** The revival prompt the harness feeds a delegating bot when its peer
552
+ * replies. The peer's text is already in the thread; this tells the source
553
+ * to stop idling and answer the user with the outcome. */
554
+ export function buildDelegationRevivalPrompt(targetName) {
555
+ return [
556
+ "[A delegated task just completed]",
557
+ `The task you delegated to @${targetName} has finished, and their reply is now in this conversation.`,
558
+ "Pick the work back up: review the reply, then answer the user with the outcome — lead with the concrete result and say what happens next. Do not re-delegate the same task.",
559
+ ].join("\n\n");
560
+ }
561
+ /** Same wake for a failed delegated turn: the source must tell the user it
562
+ * did not finish and decide the next step, instead of leaving the failure
563
+ * as a silent chip nobody acts on. */
564
+ export function buildDelegationFailurePrompt(targetName, reason) {
565
+ return [
566
+ "[A delegated task failed]",
567
+ `The task you delegated to @${targetName} did not finish: ${reason}`,
568
+ "Take over: tell the user what failed in plain terms, then decide the next step — retry with a narrower task, do the work yourself, or propose an alternative. Do not re-delegate the exact same task unchanged.",
569
+ ].join("\n\n");
570
+ }
571
+ export const DELEGATION_WAKE_MAX_PER_WINDOW = 3;
572
+ export const DELEGATION_WAKE_WINDOW_MS = 5 * 60 * 1000;
573
+ /** Bounded auto-wake budget per source thread. A delegation completion
574
+ * wakes the source; if that source re-delegates and the new completion
575
+ * wakes it again, this cap stops an A→B→A→B ping-pong. The window is
576
+ * short, so a user actively driving the bot outpaces it. */
577
+ export class DelegationWakeBudget {
578
+ entries = new Map();
579
+ now;
580
+ constructor(now = Date.now) {
581
+ this.now = now;
582
+ }
583
+ tryAcquire(threadId) {
584
+ const now = this.now();
585
+ const entry = this.entries.get(threadId);
586
+ if (!entry || now - entry.windowStart >= DELEGATION_WAKE_WINDOW_MS) {
587
+ this.entries.set(threadId, { count: 1, windowStart: now });
588
+ return true;
589
+ }
590
+ if (entry.count >= DELEGATION_WAKE_MAX_PER_WINDOW)
591
+ return false;
592
+ entry.count += 1;
593
+ return true;
594
+ }
595
+ /** A genuine user turn clears the debt — the user is driving now. */
596
+ reset(threadId) {
597
+ this.entries.delete(threadId);
598
+ }
599
+ }
600
+ export function formatDelegationElapsed(elapsedMs) {
601
+ const totalSeconds = Math.max(0, Math.round(elapsedMs / 1_000));
602
+ if (totalSeconds < 90)
603
+ return `${totalSeconds}s`;
604
+ const minutes = Math.floor(totalSeconds / 60);
605
+ const seconds = totalSeconds % 60;
606
+ return seconds === 0 ? `${minutes}m` : `${minutes}m ${seconds}s`;
607
+ }
608
+ /** Recent, bounded activity from the peer's thread since the delegated
609
+ * turn started — newest last. Empty means the peer has produced nothing
610
+ * visible since dispatch, which reads as "maybe stuck" to the caller. */
611
+ export function summarizeDelegatedActivity(messages, startedAtMs, limit = 5) {
612
+ const lines = [];
613
+ for (const message of messages) {
614
+ if (message.at < startedAtMs)
615
+ continue;
616
+ if (message.kind === "activity") {
617
+ const name = (message.tool?.name ?? "").trim();
618
+ if (name)
619
+ lines.push(`tool: ${name}`);
620
+ continue;
621
+ }
622
+ if (message.kind === "text" && message.text?.trim()) {
623
+ const text = message.text.trim().replace(/\s+/g, " ");
624
+ lines.push(`text: ${text.slice(0, 140)}${text.length > 140 ? "…" : ""}`);
625
+ }
626
+ }
627
+ return lines.slice(-limit);
628
+ }