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,76 @@
1
+ import { z } from "zod";
2
+ import { BOT_AVATAR_CROPS, botAvatarCropSchema, botAvatarUrlSchema } from "../shared/bot-avatar.js";
3
+ import { BOT_PROFILE_LIMITS } from "../shared/bot-profile.js";
4
+ import { MASCOT_BODY_IDS, mascotBodySchema } from "../shared/mascot-bodies.js";
5
+ export const BOT_PROFILE_PATCH_FIELDS = [
6
+ "name",
7
+ "title",
8
+ "description",
9
+ "notifications",
10
+ "avatarUrl",
11
+ "avatarCrop",
12
+ "mascotBody",
13
+ "voice",
14
+ "speakReplies",
15
+ ];
16
+ const profilePatchSchema = z.object({
17
+ name: z
18
+ .string({ error: "name must be a string" })
19
+ .max(BOT_PROFILE_LIMITS.name, { error: "name must be at most 100 characters" })
20
+ .refine((value) => Boolean(value.trim()), { error: "name must not be empty" })
21
+ .optional(),
22
+ title: z
23
+ .string({ error: "title must be a string" })
24
+ .max(BOT_PROFILE_LIMITS.title, { error: "title must be at most 200 characters" })
25
+ .optional(),
26
+ description: z
27
+ .string({ error: "description must be a string" })
28
+ .max(BOT_PROFILE_LIMITS.description, { error: "description must be at most 4000 characters" })
29
+ .optional(),
30
+ notifications: z.boolean({ error: "notifications must be true or false" }).optional(),
31
+ avatarUrl: z
32
+ .union([botAvatarUrlSchema, z.literal(""), z.null()], {
33
+ error: "avatarUrl must be a stored PNG, JPEG, GIF, or WebP attachment",
34
+ })
35
+ .optional(),
36
+ avatarCrop: botAvatarCropSchema.optional(),
37
+ mascotBody: mascotBodySchema.optional(),
38
+ voice: z
39
+ .string({ error: "voice must be a string" })
40
+ .max(BOT_PROFILE_LIMITS.voice, { error: "voice must be at most 200 characters" })
41
+ .optional(),
42
+ speakReplies: z.boolean({ error: "speakReplies must be true or false" }).optional(),
43
+ });
44
+ /**
45
+ * The shared validation boundary for profile fields. The desktop's broad bot
46
+ * PATCH passes strict=false; paired clients use strict=true so a future bot
47
+ * field cannot silently become remotely writable.
48
+ *
49
+ * avatarUrl deliberately uses `undefined` as the normalized clear value.
50
+ * Store persistence already omits undefined fields, while wireBot sends null
51
+ * back to clients so Codable and object-spread clients both clear stale data.
52
+ */
53
+ export function parseBotProfilePatch(input, strict = false) {
54
+ const parsed = (strict ? profilePatchSchema.strict() : profilePatchSchema).safeParse(input);
55
+ if (!parsed.success) {
56
+ const unsupported = parsed.error.issues.find((issue) => issue.code === "unrecognized_keys");
57
+ if (unsupported?.code === "unrecognized_keys") {
58
+ return { ok: false, error: `unsupported profile field: ${unsupported.keys[0] ?? "unknown"}` };
59
+ }
60
+ const issue = parsed.error.issues[0];
61
+ if (issue?.path[0] === "avatarCrop") {
62
+ const options = `${BOT_AVATAR_CROPS.slice(0, -1).join(", ")}, or ${BOT_AVATAR_CROPS.at(-1)}`;
63
+ return { ok: false, error: `avatarCrop must be ${options}` };
64
+ }
65
+ if (issue?.path[0] === "mascotBody") {
66
+ const options = `${MASCOT_BODY_IDS.slice(0, -1).join(", ")}, or ${MASCOT_BODY_IDS.at(-1)}`;
67
+ return { ok: false, error: `mascotBody must be ${options}` };
68
+ }
69
+ return { ok: false, error: issue?.message ?? "invalid profile patch" };
70
+ }
71
+ const { avatarUrl, ...fields } = parsed.data;
72
+ const patch = fields;
73
+ if (avatarUrl !== undefined)
74
+ patch.avatarUrl = avatarUrl || undefined;
75
+ return { ok: true, patch };
76
+ }
@@ -0,0 +1,463 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { linkSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { writeFileAtomic } from "./atomic.js";
5
+ import { DATA_DIR } from "./config.js";
6
+ const FILE = join(DATA_DIR, "box-create-requests.json");
7
+ const LOCK_FILE = join(DATA_DIR, "box-create-requests.lock");
8
+ const KEY_RETENTION_MS = 24 * 60 * 60 * 1_000;
9
+ const MAX_REQUESTS = 4_096;
10
+ const LOCK_WAIT_MS = 2_000;
11
+ const LOCK_RETRY_MS = 20;
12
+ const MAX_REAPER_GENERATIONS = 128;
13
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
14
+ const BOT_ID = /^[A-Za-z0-9_-]{1,120}$/;
15
+ const BOX_ID = /^bx_[23456789abcdefghjkmnpqrstuvwxyz]{8}$/;
16
+ const lockWait = new Int32Array(new SharedArrayBuffer(4));
17
+ function isRequest(value) {
18
+ if (!value || typeof value !== "object" || Array.isArray(value))
19
+ return false;
20
+ const request = value;
21
+ return (typeof request.botId === "string"
22
+ && BOT_ID.test(request.botId)
23
+ && typeof request.requestBody === "string"
24
+ && request.requestBody.length > 0
25
+ && request.requestBody.length <= 1_024
26
+ && typeof request.idempotencyKey === "string"
27
+ && UUID.test(request.idempotencyKey)
28
+ && typeof request.createdAt === "number"
29
+ && Number.isFinite(request.createdAt)
30
+ && request.createdAt > 0
31
+ && (request.boxId === undefined || (typeof request.boxId === "string" && BOX_ID.test(request.boxId)))
32
+ && (request.resolved === undefined || (request.resolved === true && typeof request.boxId === "string")));
33
+ }
34
+ function recoveryStateError(detail, cause) {
35
+ return Object.assign(new Error(`Cloud computer creation is paused because its recovery state is ${detail}. `
36
+ + "Check ascii.dev for an unnamed Box before repairing OpenMausBot's local state."), { status: 503, cause });
37
+ }
38
+ function loadFresh() {
39
+ let raw;
40
+ try {
41
+ raw = JSON.parse(readFileSync(FILE, "utf8"));
42
+ }
43
+ catch (error) {
44
+ if (error?.code === "ENOENT")
45
+ return [];
46
+ throw recoveryStateError("unreadable", error);
47
+ }
48
+ const file = raw;
49
+ if (!file
50
+ || typeof file !== "object"
51
+ || Array.isArray(file)
52
+ || file.version !== 1
53
+ || !Array.isArray(file.requests)
54
+ || file.requests.length > MAX_REQUESTS
55
+ || !file.requests.every(isRequest)) {
56
+ throw recoveryStateError("invalid");
57
+ }
58
+ const identities = new Set();
59
+ const keys = new Set();
60
+ const botsWithKnownBoxes = new Set();
61
+ for (const request of file.requests) {
62
+ const identity = `${request.botId}\0${request.requestBody}`;
63
+ if (identities.has(identity) || keys.has(request.idempotencyKey))
64
+ throw recoveryStateError("invalid");
65
+ if (request.boxId && botsWithKnownBoxes.has(request.botId))
66
+ throw recoveryStateError("invalid");
67
+ identities.add(identity);
68
+ keys.add(request.idempotencyKey);
69
+ if (request.boxId)
70
+ botsWithKnownBoxes.add(request.botId);
71
+ }
72
+ return file.requests.map((request) => ({ ...request }));
73
+ }
74
+ function save(next) {
75
+ mkdirSync(DATA_DIR, { recursive: true, mode: 0o700 });
76
+ try {
77
+ writeFileAtomic(FILE, `${JSON.stringify({ version: 1, requests: next }, null, 2)}\n`, { mode: 0o600 });
78
+ }
79
+ catch (error) {
80
+ throw recoveryStateError("unavailable", error);
81
+ }
82
+ }
83
+ function isLockOwner(value) {
84
+ if (!value || typeof value !== "object" || Array.isArray(value))
85
+ return false;
86
+ const owner = value;
87
+ return owner.version === 1
88
+ && Number.isInteger(owner.pid)
89
+ && Number(owner.pid) > 0
90
+ && Number(owner.pid) <= 0x7fffffff
91
+ && typeof owner.token === "string"
92
+ && UUID.test(owner.token)
93
+ && typeof owner.createdAt === "number"
94
+ && Number.isFinite(owner.createdAt)
95
+ && owner.createdAt > 0;
96
+ }
97
+ function readLockOwner() {
98
+ let raw;
99
+ try {
100
+ raw = readFileSync(LOCK_FILE, "utf8");
101
+ }
102
+ catch (error) {
103
+ if (error?.code === "ENOENT")
104
+ return null;
105
+ throw recoveryStateError("lock is unreadable", error);
106
+ }
107
+ let owner;
108
+ try {
109
+ owner = JSON.parse(raw);
110
+ }
111
+ catch (error) {
112
+ throw recoveryStateError("lock is invalid", error);
113
+ }
114
+ if (!isLockOwner(owner))
115
+ throw recoveryStateError("lock is invalid");
116
+ return owner;
117
+ }
118
+ function readReaperOwner(path, targetToken) {
119
+ let raw;
120
+ try {
121
+ raw = readFileSync(path, "utf8");
122
+ }
123
+ catch (error) {
124
+ if (error?.code === "ENOENT")
125
+ return null;
126
+ throw recoveryStateError("stale-lock recovery record is unreadable", error);
127
+ }
128
+ // Versions before the successor chain wrote only the elected reaper's PID.
129
+ // Treat that immutable record as generation zero so an interrupted upgrade
130
+ // remains recoverable without deleting another contender's authority.
131
+ if (/^[1-9][0-9]*\n?$/.test(raw)) {
132
+ const pid = Number(raw.trim());
133
+ if (Number.isInteger(pid) && pid <= 0x7fffffff)
134
+ return { legacy: true, pid };
135
+ }
136
+ let owner;
137
+ try {
138
+ owner = JSON.parse(raw);
139
+ }
140
+ catch (error) {
141
+ throw recoveryStateError("stale-lock recovery record is invalid", error);
142
+ }
143
+ if (!isLockOwner(owner) || !("targetToken" in owner) || owner.targetToken !== targetToken) {
144
+ throw recoveryStateError("stale-lock recovery record is invalid");
145
+ }
146
+ return owner;
147
+ }
148
+ function processIsAlive(pid) {
149
+ try {
150
+ process.kill(pid, 0);
151
+ return true;
152
+ }
153
+ catch (error) {
154
+ const code = error?.code;
155
+ if (code === "ESRCH")
156
+ return false;
157
+ // EPERM proves a process owns the pid even though this account cannot
158
+ // signal it. Every other answer is ambiguous and must keep the lock.
159
+ if (code === "EPERM")
160
+ return true;
161
+ throw recoveryStateError("lock owner could not be verified", error);
162
+ }
163
+ }
164
+ function unlinkCandidate(path) {
165
+ try {
166
+ unlinkSync(path);
167
+ }
168
+ catch (error) {
169
+ if (error?.code !== "ENOENT") {
170
+ throw recoveryStateError("lock cleanup failed", error);
171
+ }
172
+ }
173
+ }
174
+ function publishReaper(path, owner) {
175
+ const candidate = `${path}.candidate-${owner.pid}-${owner.token}`;
176
+ try {
177
+ writeFileSync(candidate, `${JSON.stringify(owner)}\n`, { flag: "wx", mode: 0o600, flush: true });
178
+ }
179
+ catch (error) {
180
+ throw recoveryStateError("stale-lock recovery candidate is unavailable", error);
181
+ }
182
+ try {
183
+ try {
184
+ linkSync(candidate, path);
185
+ return true;
186
+ }
187
+ catch (error) {
188
+ if (error?.code === "EEXIST")
189
+ return false;
190
+ throw recoveryStateError("stale-lock recovery is unavailable", error);
191
+ }
192
+ }
193
+ finally {
194
+ unlinkCandidate(candidate);
195
+ }
196
+ }
197
+ function successorReaperPath(targetToken, reaperIdentity) {
198
+ const digest = createHash("sha256").update(reaperIdentity).digest("hex").slice(0, 32);
199
+ return `${LOCK_FILE}.reap-${targetToken}-${digest}`;
200
+ }
201
+ /** Elect exactly one live process to retire this immutable lock owner. A
202
+ * reaper can itself crash, so each dead reaper deterministically names the
203
+ * next election. Election records are never removed: no contender can delete
204
+ * a successor's authority between checking it and publishing its own. */
205
+ function claimReaperAuthority(expected) {
206
+ let reaperPath = `${LOCK_FILE}.reap-${expected.token}`;
207
+ for (let generation = 0; generation < MAX_REAPER_GENERATIONS; generation += 1) {
208
+ const candidate = {
209
+ version: 1,
210
+ pid: process.pid,
211
+ token: randomUUID(),
212
+ createdAt: Date.now(),
213
+ targetToken: expected.token,
214
+ };
215
+ if (publishReaper(reaperPath, candidate))
216
+ return true;
217
+ const current = readReaperOwner(reaperPath, expected.token);
218
+ if (!current)
219
+ continue;
220
+ if (processIsAlive(current.pid))
221
+ return false;
222
+ const identity = "legacy" in current ? `legacy:${current.pid}` : current.token;
223
+ reaperPath = successorReaperPath(expected.token, identity);
224
+ }
225
+ throw recoveryStateError("stale lock could not be recovered after repeated interrupted attempts");
226
+ }
227
+ function reapDeadLock(expected) {
228
+ if (!claimReaperAuthority(expected))
229
+ return false;
230
+ const current = readLockOwner();
231
+ if (!current || current.token !== expected.token)
232
+ return true;
233
+ if (processIsAlive(current.pid))
234
+ return false;
235
+ try {
236
+ unlinkSync(LOCK_FILE);
237
+ }
238
+ catch (error) {
239
+ if (error?.code !== "ENOENT") {
240
+ throw recoveryStateError("stale lock could not be retired", error);
241
+ }
242
+ }
243
+ return true;
244
+ }
245
+ function acquireJournalLock() {
246
+ try {
247
+ mkdirSync(DATA_DIR, { recursive: true, mode: 0o700 });
248
+ }
249
+ catch (error) {
250
+ throw recoveryStateError("lock directory is unavailable", error);
251
+ }
252
+ const owner = {
253
+ version: 1,
254
+ pid: process.pid,
255
+ token: randomUUID(),
256
+ createdAt: Date.now(),
257
+ };
258
+ // The fully-written candidate exists before link(2) publishes it at the
259
+ // fixed lock path. Unlike open-then-write, contenders can never observe an
260
+ // ownerless lock after a crash between those two operations.
261
+ const candidate = `${LOCK_FILE}.candidate-${owner.pid}-${owner.token}`;
262
+ try {
263
+ writeFileSync(candidate, `${JSON.stringify(owner)}\n`, { flag: "wx", mode: 0o600, flush: true });
264
+ }
265
+ catch (error) {
266
+ throw recoveryStateError("lock candidate is unavailable", error);
267
+ }
268
+ const deadline = performance.now() + LOCK_WAIT_MS;
269
+ try {
270
+ for (;;) {
271
+ try {
272
+ linkSync(candidate, LOCK_FILE);
273
+ return owner;
274
+ }
275
+ catch (error) {
276
+ if (error?.code !== "EEXIST") {
277
+ throw recoveryStateError("lock could not be acquired", error);
278
+ }
279
+ }
280
+ const current = readLockOwner();
281
+ const reaped = current !== null && !processIsAlive(current.pid) && reapDeadLock(current);
282
+ // Every retry path is bounded. In particular, an adversarially changing
283
+ // lock can disappear between link(EEXIST) and read, or replace each
284
+ // successfully reaped owner before the next link attempt.
285
+ if (performance.now() >= deadline) {
286
+ throw recoveryStateError("locked by another OpenMausBot process");
287
+ }
288
+ if (reaped)
289
+ continue;
290
+ Atomics.wait(lockWait, 0, 0, LOCK_RETRY_MS);
291
+ }
292
+ }
293
+ finally {
294
+ unlinkCandidate(candidate);
295
+ }
296
+ }
297
+ function releaseJournalLock(owner) {
298
+ const current = readLockOwner();
299
+ if (!current || current.token !== owner.token || current.pid !== owner.pid) {
300
+ throw recoveryStateError("lock ownership changed unexpectedly");
301
+ }
302
+ try {
303
+ unlinkSync(LOCK_FILE);
304
+ }
305
+ catch (error) {
306
+ throw recoveryStateError("lock could not be released", error);
307
+ }
308
+ }
309
+ function withJournalLock(operation) {
310
+ const owner = acquireJournalLock();
311
+ try {
312
+ return operation(loadFresh());
313
+ }
314
+ finally {
315
+ releaseJournalLock(owner);
316
+ }
317
+ }
318
+ /** Record the exact provider request before it leaves the process. A known
319
+ * Box wins over a changed body: once a provider resource exists, recovering
320
+ * and naming it is safer than issuing any second create request. */
321
+ export function beginBoxCreate(botId, requestBody) {
322
+ if (!BOT_ID.test(botId))
323
+ throw new Error("invalid bot id for cloud computer creation");
324
+ if (!requestBody || requestBody.length > 1_024)
325
+ throw new Error("invalid cloud computer create request");
326
+ return withJournalLock((requests) => {
327
+ const known = requests.find((request) => request.botId === botId && request.boxId);
328
+ if (known)
329
+ return { request: { ...known }, startedNow: false };
330
+ const now = Date.now();
331
+ const pending = requests.find((request) => request.botId === botId);
332
+ if (pending) {
333
+ if (pending.requestBody !== requestBody) {
334
+ throw recoveryStateError("waiting for an earlier cloud computer request to be reconciled");
335
+ }
336
+ if (now - pending.createdAt >= KEY_RETENTION_MS) {
337
+ // Once the provider forgets the idempotency key, retrying it (or using
338
+ // a new key) may create a second billable Box. Absence cannot be
339
+ // inferred from a lost response, so stop for manual reconciliation.
340
+ throw recoveryStateError("older than ascii.dev's 24-hour retry window");
341
+ }
342
+ return { request: { ...pending }, startedNow: false };
343
+ }
344
+ const request = {
345
+ botId,
346
+ requestBody,
347
+ idempotencyKey: randomUUID(),
348
+ createdAt: now,
349
+ };
350
+ if (requests.length >= MAX_REQUESTS)
351
+ throw recoveryStateError("full");
352
+ save([...requests, request]);
353
+ return { request: { ...request }, startedNow: true };
354
+ });
355
+ }
356
+ /** Persist the returned identity before the caller attempts to rename it. */
357
+ export function rememberCreatedBox(request, boxId) {
358
+ if (!BOX_ID.test(boxId))
359
+ throw new Error("ascii.dev returned an invalid cloud computer id");
360
+ return withJournalLock((requests) => {
361
+ const current = requests.find((candidate) => (candidate.botId === request.botId
362
+ && candidate.requestBody === request.requestBody
363
+ && candidate.idempotencyKey === request.idempotencyKey));
364
+ if (!current || (current.boxId !== undefined && current.boxId !== boxId)) {
365
+ throw recoveryStateError("out of date");
366
+ }
367
+ const completed = { ...current, boxId };
368
+ // There can be an older rejected-TTL request for this bot. Once a Box is
369
+ // known, it is the only recovery authority we need to retain.
370
+ save([...requests.filter((candidate) => candidate.botId !== request.botId), completed]);
371
+ return { ...completed };
372
+ });
373
+ }
374
+ /** Mark the recovery record safe only after the deterministic provider rename
375
+ * succeeds. Keeping the resolved Box ID still lets a later retry recover from
376
+ * an eventually-consistent account listing without blocking bot deletion. */
377
+ export function resolveBoxCreate(request) {
378
+ return withJournalLock((requests) => {
379
+ const current = requests.find((candidate) => (candidate.botId === request.botId
380
+ && candidate.requestBody === request.requestBody
381
+ && candidate.idempotencyKey === request.idempotencyKey
382
+ && candidate.boxId === request.boxId));
383
+ if (!current?.boxId)
384
+ throw recoveryStateError("out of date");
385
+ const resolved = { ...current, resolved: true };
386
+ save(requests.map((candidate) => candidate.idempotencyKey === current.idempotencyKey ? resolved : candidate));
387
+ return { ...resolved };
388
+ });
389
+ }
390
+ /** Read-only deletion guard. Both a key-only request with an ambiguous
391
+ * provider outcome and a known-but-not-yet-named Box must keep its bot owner. */
392
+ export function hasUnresolvedBoxCreate(botId) {
393
+ if (!BOT_ID.test(botId))
394
+ throw new Error("invalid bot id for cloud computer creation");
395
+ return withJournalLock((requests) => (requests.some((request) => request.botId === botId && request.resolved !== true)));
396
+ }
397
+ /** Sanitized local recovery authority for configuration guards. The fresh,
398
+ * lock-protected read can prove a remembered provider id even while the
399
+ * account-wide LIST endpoint is eventually consistent. Provider request
400
+ * bodies and idempotency keys never cross this boundary. */
401
+ export function boxCreateRecoverySnapshot() {
402
+ return withJournalLock((requests) => requests.map((request) => ({
403
+ botId: request.botId,
404
+ ...(request.boxId ? { boxId: request.boxId } : {}),
405
+ resolved: request.resolved === true,
406
+ })));
407
+ }
408
+ /** Persist ownership discovered from a pre-journal deterministic Box name.
409
+ * The provider listing proves which live bot owns the exact immutable id, but
410
+ * it must never steal an identity remembered for another bot. It supersedes
411
+ * stale attempts for the same bot, is idempotent, and fails closed on a true
412
+ * cross-bot conflict. */
413
+ export function adoptResolvedBox(botId, boxId) {
414
+ if (!BOT_ID.test(botId))
415
+ throw new Error("invalid bot id for cloud computer ownership");
416
+ if (!BOX_ID.test(boxId))
417
+ throw new Error("invalid cloud computer id for ownership");
418
+ withJournalLock((requests) => {
419
+ const sameBox = requests.find((request) => request.boxId === boxId);
420
+ if (sameBox && sameBox.botId !== botId) {
421
+ throw recoveryStateError("conflicted with another bot's remembered cloud computer");
422
+ }
423
+ const adopted = sameBox
424
+ ? { ...sameBox, resolved: true }
425
+ : {
426
+ botId,
427
+ requestBody: JSON.stringify({ adopted: "legacy-name", boxId }),
428
+ idempotencyKey: randomUUID(),
429
+ createdAt: Date.now(),
430
+ boxId,
431
+ resolved: true,
432
+ };
433
+ const retained = requests.filter((request) => request.botId !== botId);
434
+ if (retained.length >= MAX_REQUESTS)
435
+ throw recoveryStateError("full");
436
+ if (requests.filter((request) => request.botId === botId).length === 1
437
+ && sameBox?.resolved === true
438
+ && sameBox.botId === botId)
439
+ return;
440
+ // A successfully listed deterministic legacy name resolves any older
441
+ // key-only/remembered attempt for this bot. Keeping those stale rows would
442
+ // leave deletion permanently blocked after the adopted Box is removed.
443
+ save([...retained, adopted]);
444
+ });
445
+ }
446
+ /** Retire only the durable identity for a Box the provider has confirmed was
447
+ * deleted. Callers must never use this for a failed or ambiguous deletion. */
448
+ export function retireDeletedBoxCreate(boxId) {
449
+ if (!BOX_ID.test(boxId))
450
+ throw new Error("invalid deleted cloud computer id");
451
+ withJournalLock((requests) => {
452
+ const next = requests.filter((request) => request.boxId !== boxId);
453
+ if (next.length !== requests.length)
454
+ save(next);
455
+ });
456
+ }
457
+ export function discardBoxCreate(request) {
458
+ withJournalLock((requests) => {
459
+ const next = requests.filter((candidate) => candidate.idempotencyKey !== request.idempotencyKey);
460
+ if (next.length !== requests.length)
461
+ save(next);
462
+ });
463
+ }