@withbuddi/buddi 0.1.0-pre.37 → 0.1.0-pre.38

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 (703) hide show
  1. package/extension/background.js +130 -12
  2. package/extension/manifest.json +2 -2
  3. package/node_modules/@buddi/cli/dist/.tsbuildinfo +1 -1
  4. package/node_modules/@buddi/cli/dist/access-cmd.d.ts +10 -0
  5. package/node_modules/@buddi/cli/dist/access-cmd.d.ts.map +1 -0
  6. package/node_modules/@buddi/cli/dist/access-cmd.js +160 -0
  7. package/node_modules/@buddi/cli/dist/access-cmd.js.map +1 -0
  8. package/node_modules/@buddi/cli/dist/args.d.ts +10 -0
  9. package/node_modules/@buddi/cli/dist/args.d.ts.map +1 -1
  10. package/node_modules/@buddi/cli/dist/args.js +29 -1
  11. package/node_modules/@buddi/cli/dist/args.js.map +1 -1
  12. package/node_modules/@buddi/cli/dist/commands.d.ts.map +1 -1
  13. package/node_modules/@buddi/cli/dist/commands.js +28 -2
  14. package/node_modules/@buddi/cli/dist/commands.js.map +1 -1
  15. package/node_modules/@buddi/cli/dist/doctor-probes.d.ts.map +1 -1
  16. package/node_modules/@buddi/cli/dist/doctor-probes.js +54 -29
  17. package/node_modules/@buddi/cli/dist/doctor-probes.js.map +1 -1
  18. package/node_modules/@buddi/cli/dist/doctor.d.ts +36 -12
  19. package/node_modules/@buddi/cli/dist/doctor.d.ts.map +1 -1
  20. package/node_modules/@buddi/cli/dist/doctor.js +32 -9
  21. package/node_modules/@buddi/cli/dist/doctor.js.map +1 -1
  22. package/node_modules/@buddi/cli/dist/main.d.ts +2 -0
  23. package/node_modules/@buddi/cli/dist/main.d.ts.map +1 -1
  24. package/node_modules/@buddi/cli/dist/main.js +18 -1
  25. package/node_modules/@buddi/cli/dist/main.js.map +1 -1
  26. package/node_modules/@buddi/core/dist/.tsbuildinfo +1 -1
  27. package/node_modules/@buddi/core/dist/agents/catalog.d.ts +2 -0
  28. package/node_modules/@buddi/core/dist/agents/catalog.d.ts.map +1 -1
  29. package/node_modules/@buddi/core/dist/agents/catalog.js +1 -0
  30. package/node_modules/@buddi/core/dist/agents/catalog.js.map +1 -1
  31. package/node_modules/@buddi/core/dist/agents/edit.d.ts +2 -0
  32. package/node_modules/@buddi/core/dist/agents/edit.d.ts.map +1 -1
  33. package/node_modules/@buddi/core/dist/agents/edit.js +3 -1
  34. package/node_modules/@buddi/core/dist/agents/edit.js.map +1 -1
  35. package/node_modules/@buddi/core/dist/agents/frontmatter.d.ts +11 -0
  36. package/node_modules/@buddi/core/dist/agents/frontmatter.d.ts.map +1 -1
  37. package/node_modules/@buddi/core/dist/agents/frontmatter.js +7 -0
  38. package/node_modules/@buddi/core/dist/agents/frontmatter.js.map +1 -1
  39. package/node_modules/@buddi/core/dist/index.d.ts +1 -0
  40. package/node_modules/@buddi/core/dist/index.d.ts.map +1 -1
  41. package/node_modules/@buddi/core/dist/index.js +1 -0
  42. package/node_modules/@buddi/core/dist/index.js.map +1 -1
  43. package/node_modules/@buddi/core/dist/plugin/index.d.ts +3 -0
  44. package/node_modules/@buddi/core/dist/plugin/index.d.ts.map +1 -1
  45. package/node_modules/@buddi/core/dist/plugin/index.js +3 -0
  46. package/node_modules/@buddi/core/dist/plugin/index.js.map +1 -1
  47. package/node_modules/@buddi/core/dist/plugin/version.d.ts +1 -1
  48. package/node_modules/@buddi/core/dist/plugin/version.js +1 -1
  49. package/node_modules/@buddi/core/dist/questions/store.d.ts +12 -0
  50. package/node_modules/@buddi/core/dist/questions/store.d.ts.map +1 -1
  51. package/node_modules/@buddi/core/dist/questions/store.js +11 -1
  52. package/node_modules/@buddi/core/dist/questions/store.js.map +1 -1
  53. package/node_modules/@buddi/core/dist/questions/types.d.ts +8 -0
  54. package/node_modules/@buddi/core/dist/questions/types.d.ts.map +1 -1
  55. package/node_modules/@buddi/core/dist/questions/types.js +15 -0
  56. package/node_modules/@buddi/core/dist/questions/types.js.map +1 -1
  57. package/node_modules/@buddi/core/dist/queue/jobs.d.ts +8 -0
  58. package/node_modules/@buddi/core/dist/queue/jobs.d.ts.map +1 -1
  59. package/node_modules/@buddi/core/dist/queue/jobs.js +9 -3
  60. package/node_modules/@buddi/core/dist/queue/jobs.js.map +1 -1
  61. package/node_modules/@buddi/core/dist/queue/worker.d.ts +2 -0
  62. package/node_modules/@buddi/core/dist/queue/worker.d.ts.map +1 -1
  63. package/node_modules/@buddi/core/dist/queue/worker.js +2 -1
  64. package/node_modules/@buddi/core/dist/queue/worker.js.map +1 -1
  65. package/node_modules/@buddi/core/dist/registry.d.ts +7 -1
  66. package/node_modules/@buddi/core/dist/registry.d.ts.map +1 -1
  67. package/node_modules/@buddi/core/dist/registry.js +73 -11
  68. package/node_modules/@buddi/core/dist/registry.js.map +1 -1
  69. package/node_modules/@buddi/core/dist/routes.d.ts +153 -0
  70. package/node_modules/@buddi/core/dist/routes.d.ts.map +1 -0
  71. package/node_modules/@buddi/core/dist/routes.js +47 -0
  72. package/node_modules/@buddi/core/dist/routes.js.map +1 -0
  73. package/node_modules/@buddi/core/dist/scheduler/missions.d.ts +5 -3
  74. package/node_modules/@buddi/core/dist/scheduler/missions.d.ts.map +1 -1
  75. package/node_modules/@buddi/core/dist/scheduler/missions.js +9 -7
  76. package/node_modules/@buddi/core/dist/scheduler/missions.js.map +1 -1
  77. package/node_modules/@buddi/core/dist/scheduler/types.d.ts +7 -0
  78. package/node_modules/@buddi/core/dist/scheduler/types.d.ts.map +1 -1
  79. package/node_modules/@buddi/core/dist/scheduler/types.js +1 -0
  80. package/node_modules/@buddi/core/dist/scheduler/types.js.map +1 -1
  81. package/node_modules/@buddi/core/dist/tools.d.ts +59 -2
  82. package/node_modules/@buddi/core/dist/tools.d.ts.map +1 -1
  83. package/node_modules/@buddi/core/dist/tools.js.map +1 -1
  84. package/node_modules/@buddi/core/migrations/075_access_providers.sql +43 -0
  85. package/node_modules/@buddi/core/migrations/076_mission_browser.sql +7 -0
  86. package/node_modules/@buddi/gateway/dist/.tsbuildinfo +1 -1
  87. package/node_modules/@buddi/gateway/dist/agents/canvas.d.ts +12 -12
  88. package/node_modules/@buddi/gateway/dist/agents/catalogue-package.d.ts +38 -20
  89. package/node_modules/@buddi/gateway/dist/agents/catalogue-package.d.ts.map +1 -1
  90. package/node_modules/@buddi/gateway/dist/agents/catalogue-package.js +6 -0
  91. package/node_modules/@buddi/gateway/dist/agents/catalogue-package.js.map +1 -1
  92. package/node_modules/@buddi/gateway/dist/agents/delegation.d.ts +10 -0
  93. package/node_modules/@buddi/gateway/dist/agents/delegation.d.ts.map +1 -1
  94. package/node_modules/@buddi/gateway/dist/agents/delegation.js +1 -0
  95. package/node_modules/@buddi/gateway/dist/agents/delegation.js.map +1 -1
  96. package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.d.ts +7 -1
  97. package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.d.ts.map +1 -1
  98. package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.js +15 -6
  99. package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.js.map +1 -1
  100. package/node_modules/@buddi/gateway/dist/bootstrap.d.ts.map +1 -1
  101. package/node_modules/@buddi/gateway/dist/bootstrap.js +8 -0
  102. package/node_modules/@buddi/gateway/dist/bootstrap.js.map +1 -1
  103. package/node_modules/@buddi/gateway/dist/browser-host.d.ts +30 -1
  104. package/node_modules/@buddi/gateway/dist/browser-host.d.ts.map +1 -1
  105. package/node_modules/@buddi/gateway/dist/browser-host.js +56 -1
  106. package/node_modules/@buddi/gateway/dist/browser-host.js.map +1 -1
  107. package/node_modules/@buddi/gateway/dist/chat/session.d.ts.map +1 -1
  108. package/node_modules/@buddi/gateway/dist/chat/session.js +9 -5
  109. package/node_modules/@buddi/gateway/dist/chat/session.js.map +1 -1
  110. package/node_modules/@buddi/gateway/dist/index.d.ts +2 -1
  111. package/node_modules/@buddi/gateway/dist/index.d.ts.map +1 -1
  112. package/node_modules/@buddi/gateway/dist/index.js +2 -1
  113. package/node_modules/@buddi/gateway/dist/index.js.map +1 -1
  114. package/node_modules/@buddi/gateway/dist/missions/execute.d.ts +34 -1
  115. package/node_modules/@buddi/gateway/dist/missions/execute.d.ts.map +1 -1
  116. package/node_modules/@buddi/gateway/dist/missions/execute.js +92 -8
  117. package/node_modules/@buddi/gateway/dist/missions/execute.js.map +1 -1
  118. package/node_modules/@buddi/gateway/dist/missions/parked.d.ts +133 -0
  119. package/node_modules/@buddi/gateway/dist/missions/parked.d.ts.map +1 -0
  120. package/node_modules/@buddi/gateway/dist/missions/parked.js +249 -0
  121. package/node_modules/@buddi/gateway/dist/missions/parked.js.map +1 -0
  122. package/node_modules/@buddi/gateway/dist/serve.d.ts +7 -0
  123. package/node_modules/@buddi/gateway/dist/serve.d.ts.map +1 -1
  124. package/node_modules/@buddi/gateway/dist/serve.js +49 -9
  125. package/node_modules/@buddi/gateway/dist/serve.js.map +1 -1
  126. package/node_modules/@buddi/gateway/dist/surfaces/browser-cards.d.ts +18 -0
  127. package/node_modules/@buddi/gateway/dist/surfaces/browser-cards.d.ts.map +1 -0
  128. package/node_modules/@buddi/gateway/dist/surfaces/browser-cards.js +42 -0
  129. package/node_modules/@buddi/gateway/dist/surfaces/browser-cards.js.map +1 -0
  130. package/node_modules/@buddi/gateway/dist/surfaces/browser-continuation.js +1 -1
  131. package/node_modules/@buddi/gateway/dist/surfaces/browser-continuation.js.map +1 -1
  132. package/node_modules/@buddi/gateway/dist/surfaces/owner-request.d.ts +6 -0
  133. package/node_modules/@buddi/gateway/dist/surfaces/owner-request.d.ts.map +1 -1
  134. package/node_modules/@buddi/gateway/dist/surfaces/owner-request.js +7 -1
  135. package/node_modules/@buddi/gateway/dist/surfaces/owner-request.js.map +1 -1
  136. package/node_modules/@buddi/gateway/dist/system-context.d.ts.map +1 -1
  137. package/node_modules/@buddi/gateway/dist/system-context.js +6 -7
  138. package/node_modules/@buddi/gateway/dist/system-context.js.map +1 -1
  139. package/node_modules/@buddi/gateway/dist/telegram/browser-view.d.ts +17 -17
  140. package/node_modules/@buddi/gateway/dist/telegram/browser-view.d.ts.map +1 -1
  141. package/node_modules/@buddi/gateway/dist/telegram/browser-view.js +33 -37
  142. package/node_modules/@buddi/gateway/dist/telegram/browser-view.js.map +1 -1
  143. package/node_modules/@buddi/gateway/dist/telegram/channel.d.ts.map +1 -1
  144. package/node_modules/@buddi/gateway/dist/telegram/channel.js +17 -1
  145. package/node_modules/@buddi/gateway/dist/telegram/channel.js.map +1 -1
  146. package/node_modules/@buddi/gateway/dist/telegram/main.d.ts.map +1 -1
  147. package/node_modules/@buddi/gateway/dist/telegram/main.js +11 -3
  148. package/node_modules/@buddi/gateway/dist/telegram/main.js.map +1 -1
  149. package/node_modules/@buddi/gateway/dist/telegram/surface.d.ts.map +1 -1
  150. package/node_modules/@buddi/gateway/dist/telegram/surface.js +10 -0
  151. package/node_modules/@buddi/gateway/dist/telegram/surface.js.map +1 -1
  152. package/node_modules/@buddi/gateway/dist/tips/facts.d.ts +8 -0
  153. package/node_modules/@buddi/gateway/dist/tips/facts.d.ts.map +1 -1
  154. package/node_modules/@buddi/gateway/dist/tips/facts.js +8 -2
  155. package/node_modules/@buddi/gateway/dist/tips/facts.js.map +1 -1
  156. package/node_modules/@buddi/gateway/dist/tips/rules.d.ts +2 -0
  157. package/node_modules/@buddi/gateway/dist/tips/rules.d.ts.map +1 -1
  158. package/node_modules/@buddi/gateway/dist/tips/rules.js +15 -0
  159. package/node_modules/@buddi/gateway/dist/tips/rules.js.map +1 -1
  160. package/node_modules/@buddi/gateway/dist/web/access/arrival.d.ts +24 -0
  161. package/node_modules/@buddi/gateway/dist/web/access/arrival.d.ts.map +1 -0
  162. package/node_modules/@buddi/gateway/dist/web/access/arrival.js +18 -0
  163. package/node_modules/@buddi/gateway/dist/web/access/arrival.js.map +1 -0
  164. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-api.d.ts +124 -0
  165. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-api.d.ts.map +1 -0
  166. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-api.js +206 -0
  167. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-api.js.map +1 -0
  168. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.d.ts +163 -0
  169. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.d.ts.map +1 -0
  170. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.js +438 -0
  171. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.js.map +1 -0
  172. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-token.d.ts +31 -0
  173. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-token.d.ts.map +1 -0
  174. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-token.js +74 -0
  175. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-token.js.map +1 -0
  176. package/node_modules/@buddi/gateway/dist/web/access/cloudflare.d.ts +145 -0
  177. package/node_modules/@buddi/gateway/dist/web/access/cloudflare.d.ts.map +1 -0
  178. package/node_modules/@buddi/gateway/dist/web/access/cloudflare.js +474 -0
  179. package/node_modules/@buddi/gateway/dist/web/access/cloudflare.js.map +1 -0
  180. package/node_modules/@buddi/gateway/dist/web/access/index.d.ts +9 -0
  181. package/node_modules/@buddi/gateway/dist/web/access/index.d.ts.map +1 -0
  182. package/node_modules/@buddi/gateway/dist/web/access/index.js +9 -0
  183. package/node_modules/@buddi/gateway/dist/web/access/index.js.map +1 -0
  184. package/node_modules/@buddi/gateway/dist/web/access/ingress.d.ts +30 -0
  185. package/node_modules/@buddi/gateway/dist/web/access/ingress.d.ts.map +1 -0
  186. package/node_modules/@buddi/gateway/dist/web/access/ingress.js +76 -0
  187. package/node_modules/@buddi/gateway/dist/web/access/ingress.js.map +1 -0
  188. package/node_modules/@buddi/gateway/dist/web/access/provider.d.ts +173 -0
  189. package/node_modules/@buddi/gateway/dist/web/access/provider.d.ts.map +1 -0
  190. package/node_modules/@buddi/gateway/dist/web/access/provider.js +11 -0
  191. package/node_modules/@buddi/gateway/dist/web/access/provider.js.map +1 -0
  192. package/node_modules/@buddi/gateway/dist/web/access/registry.d.ts +33 -0
  193. package/node_modules/@buddi/gateway/dist/web/access/registry.d.ts.map +1 -0
  194. package/node_modules/@buddi/gateway/dist/web/access/registry.js +32 -0
  195. package/node_modules/@buddi/gateway/dist/web/access/registry.js.map +1 -0
  196. package/node_modules/@buddi/gateway/dist/web/{tailscale.d.ts → access/tailscale.d.ts} +27 -0
  197. package/node_modules/@buddi/gateway/dist/web/access/tailscale.d.ts.map +1 -0
  198. package/node_modules/@buddi/gateway/dist/web/{tailscale.js → access/tailscale.js} +118 -3
  199. package/node_modules/@buddi/gateway/dist/web/access/tailscale.js.map +1 -0
  200. package/node_modules/@buddi/gateway/dist/web/agents.d.ts +2 -0
  201. package/node_modules/@buddi/gateway/dist/web/agents.d.ts.map +1 -1
  202. package/node_modules/@buddi/gateway/dist/web/agents.js +19 -1
  203. package/node_modules/@buddi/gateway/dist/web/agents.js.map +1 -1
  204. package/node_modules/@buddi/gateway/dist/web/api-routes.d.ts +4 -3
  205. package/node_modules/@buddi/gateway/dist/web/api-routes.d.ts.map +1 -1
  206. package/node_modules/@buddi/gateway/dist/web/api-routes.js +96 -17
  207. package/node_modules/@buddi/gateway/dist/web/api-routes.js.map +1 -1
  208. package/node_modules/@buddi/gateway/dist/web/attention.d.ts.map +1 -1
  209. package/node_modules/@buddi/gateway/dist/web/attention.js +11 -3
  210. package/node_modules/@buddi/gateway/dist/web/attention.js.map +1 -1
  211. package/node_modules/@buddi/gateway/dist/web/chat.d.ts +23 -0
  212. package/node_modules/@buddi/gateway/dist/web/chat.d.ts.map +1 -1
  213. package/node_modules/@buddi/gateway/dist/web/chat.js +62 -2
  214. package/node_modules/@buddi/gateway/dist/web/chat.js.map +1 -1
  215. package/node_modules/@buddi/gateway/dist/web/client-key.d.ts +3 -0
  216. package/node_modules/@buddi/gateway/dist/web/client-key.d.ts.map +1 -1
  217. package/node_modules/@buddi/gateway/dist/web/client-key.js +8 -1
  218. package/node_modules/@buddi/gateway/dist/web/client-key.js.map +1 -1
  219. package/node_modules/@buddi/gateway/dist/web/extension.d.ts +9 -1
  220. package/node_modules/@buddi/gateway/dist/web/extension.d.ts.map +1 -1
  221. package/node_modules/@buddi/gateway/dist/web/extension.js +61 -1
  222. package/node_modules/@buddi/gateway/dist/web/extension.js.map +1 -1
  223. package/node_modules/@buddi/gateway/dist/web/http.d.ts +7 -0
  224. package/node_modules/@buddi/gateway/dist/web/http.d.ts.map +1 -1
  225. package/node_modules/@buddi/gateway/dist/web/http.js +15 -1
  226. package/node_modules/@buddi/gateway/dist/web/http.js.map +1 -1
  227. package/node_modules/@buddi/gateway/dist/web/index.d.ts +1 -1
  228. package/node_modules/@buddi/gateway/dist/web/index.d.ts.map +1 -1
  229. package/node_modules/@buddi/gateway/dist/web/index.js +1 -1
  230. package/node_modules/@buddi/gateway/dist/web/index.js.map +1 -1
  231. package/node_modules/@buddi/gateway/dist/web/onboarding.js +1 -1
  232. package/node_modules/@buddi/gateway/dist/web/onboarding.js.map +1 -1
  233. package/node_modules/@buddi/gateway/dist/web/server.d.ts +38 -2
  234. package/node_modules/@buddi/gateway/dist/web/server.d.ts.map +1 -1
  235. package/node_modules/@buddi/gateway/dist/web/server.js +576 -145
  236. package/node_modules/@buddi/gateway/dist/web/server.js.map +1 -1
  237. package/node_modules/@buddi/gateway/dist/web/sessions.d.ts +24 -14
  238. package/node_modules/@buddi/gateway/dist/web/sessions.d.ts.map +1 -1
  239. package/node_modules/@buddi/gateway/dist/web/sessions.js +42 -14
  240. package/node_modules/@buddi/gateway/dist/web/sessions.js.map +1 -1
  241. package/node_modules/@buddi/gateway/dist/web/signed-out.d.ts +10 -0
  242. package/node_modules/@buddi/gateway/dist/web/signed-out.d.ts.map +1 -1
  243. package/node_modules/@buddi/gateway/dist/web/signed-out.js +47 -0
  244. package/node_modules/@buddi/gateway/dist/web/signed-out.js.map +1 -1
  245. package/node_modules/@buddi/install/dist/.tsbuildinfo +1 -1
  246. package/node_modules/@buddi/runtime/dist/.tsbuildinfo +1 -1
  247. package/node_modules/@buddi/runtime/dist/delegate.d.ts +8 -0
  248. package/node_modules/@buddi/runtime/dist/delegate.d.ts.map +1 -1
  249. package/node_modules/@buddi/runtime/dist/delegate.js +19 -1
  250. package/node_modules/@buddi/runtime/dist/delegate.js.map +1 -1
  251. package/node_modules/@buddi/runtime/dist/loop.d.ts +2 -0
  252. package/node_modules/@buddi/runtime/dist/loop.d.ts.map +1 -1
  253. package/node_modules/@buddi/runtime/dist/loop.js +18 -4
  254. package/node_modules/@buddi/runtime/dist/loop.js.map +1 -1
  255. package/node_modules/@buddi/tool-artifacts/dist/.tsbuildinfo +1 -1
  256. package/node_modules/@buddi/tool-browser/dist/.tsbuildinfo +1 -1
  257. package/node_modules/@buddi/tool-browser/dist/availability.d.ts +2 -2
  258. package/node_modules/@buddi/tool-browser/dist/availability.d.ts.map +1 -1
  259. package/node_modules/@buddi/tool-browser/dist/availability.js +2 -2
  260. package/node_modules/@buddi/tool-browser/dist/availability.js.map +1 -1
  261. package/node_modules/@buddi/tool-browser/dist/controller.d.ts +76 -58
  262. package/node_modules/@buddi/tool-browser/dist/controller.d.ts.map +1 -1
  263. package/node_modules/@buddi/tool-browser/dist/controller.js +751 -219
  264. package/node_modules/@buddi/tool-browser/dist/controller.js.map +1 -1
  265. package/node_modules/@buddi/tool-browser/dist/extension.d.ts +12 -0
  266. package/node_modules/@buddi/tool-browser/dist/extension.d.ts.map +1 -1
  267. package/node_modules/@buddi/tool-browser/dist/extension.js +8 -0
  268. package/node_modules/@buddi/tool-browser/dist/extension.js.map +1 -1
  269. package/node_modules/@buddi/tool-browser/dist/index.d.ts +13 -5
  270. package/node_modules/@buddi/tool-browser/dist/index.d.ts.map +1 -1
  271. package/node_modules/@buddi/tool-browser/dist/index.js +29 -12
  272. package/node_modules/@buddi/tool-browser/dist/index.js.map +1 -1
  273. package/node_modules/@buddi/tool-browser/dist/manager.d.ts +39 -21
  274. package/node_modules/@buddi/tool-browser/dist/manager.d.ts.map +1 -1
  275. package/node_modules/@buddi/tool-browser/dist/manager.js +229 -136
  276. package/node_modules/@buddi/tool-browser/dist/manager.js.map +1 -1
  277. package/node_modules/@buddi/tool-browser/dist/routes.d.ts +130 -0
  278. package/node_modules/@buddi/tool-browser/dist/routes.d.ts.map +1 -0
  279. package/node_modules/@buddi/tool-browser/dist/routes.js +283 -0
  280. package/node_modules/@buddi/tool-browser/dist/routes.js.map +1 -0
  281. package/node_modules/@buddi/tool-browser/dist/service.d.ts +157 -114
  282. package/node_modules/@buddi/tool-browser/dist/service.d.ts.map +1 -1
  283. package/node_modules/@buddi/tool-browser/dist/service.js +379 -390
  284. package/node_modules/@buddi/tool-browser/dist/service.js.map +1 -1
  285. package/node_modules/@buddi/tool-browser/dist/settings.d.ts +88 -0
  286. package/node_modules/@buddi/tool-browser/dist/settings.d.ts.map +1 -0
  287. package/node_modules/@buddi/tool-browser/dist/settings.js +86 -0
  288. package/node_modules/@buddi/tool-browser/dist/settings.js.map +1 -0
  289. package/node_modules/@buddi/tool-browser/dist/telemetry.d.ts +203 -0
  290. package/node_modules/@buddi/tool-browser/dist/telemetry.d.ts.map +1 -0
  291. package/node_modules/@buddi/tool-browser/dist/telemetry.js +142 -0
  292. package/node_modules/@buddi/tool-browser/dist/telemetry.js.map +1 -0
  293. package/node_modules/@buddi/tool-browser/dist/types.d.ts +14 -3
  294. package/node_modules/@buddi/tool-browser/dist/types.d.ts.map +1 -1
  295. package/node_modules/@buddi/tool-browser/dist/types.js +9 -9
  296. package/node_modules/@buddi/tool-browser/dist/types.js.map +1 -1
  297. package/node_modules/@buddi/tool-email/dist/.tsbuildinfo +1 -1
  298. package/node_modules/@buddi/tool-host/dist/.tsbuildinfo +1 -1
  299. package/node_modules/@buddi/tool-mcp/dist/.tsbuildinfo +1 -1
  300. package/node_modules/@buddi/tool-memory/dist/.tsbuildinfo +1 -1
  301. package/node_modules/@buddi/tool-web/dist/.tsbuildinfo +1 -1
  302. package/node_modules/imapflow/CHANGELOG.md +15 -0
  303. package/node_modules/imapflow/dist/cjs/package-info.d.ts +1 -1
  304. package/node_modules/imapflow/dist/cjs/package-info.js +1 -1
  305. package/node_modules/imapflow/dist/cjs/search-compiler.js +21 -31
  306. package/node_modules/imapflow/dist/esm/package-info.d.ts +1 -1
  307. package/node_modules/imapflow/dist/esm/package-info.js +1 -1
  308. package/node_modules/imapflow/dist/esm/search-compiler.js +21 -31
  309. package/node_modules/imapflow/package.json +2 -2
  310. package/node_modules/pino/CONTRIBUTING.md +1 -5
  311. package/node_modules/pino/LICENSE +1 -1
  312. package/node_modules/pino/README.md +1 -1
  313. package/node_modules/pino/SECURITY.md +2 -18
  314. package/node_modules/pino/browser.js +8 -68
  315. package/node_modules/pino/docs/api.md +4 -75
  316. package/node_modules/pino/docs/asynchronous.md +3 -18
  317. package/node_modules/pino/docs/browser.md +0 -63
  318. package/node_modules/pino/docs/child-loggers.md +1 -22
  319. package/node_modules/pino/docs/ecosystem.md +0 -1
  320. package/node_modules/pino/docs/help.md +3 -11
  321. package/node_modules/pino/docs/lts.md +0 -29
  322. package/node_modules/pino/docs/pretty.md +0 -3
  323. package/node_modules/pino/docs/redaction.md +8 -3
  324. package/node_modules/pino/docs/transports.md +0 -71
  325. package/node_modules/pino/docs/web.md +14 -11
  326. package/node_modules/pino/eslint.config.js +7 -15
  327. package/node_modules/pino/lib/caller.js +0 -10
  328. package/node_modules/pino/lib/meta.js +1 -1
  329. package/node_modules/pino/lib/multistream.js +7 -15
  330. package/node_modules/pino/lib/redaction.js +3 -8
  331. package/node_modules/pino/lib/symbols.js +1 -3
  332. package/node_modules/pino/lib/tools.js +2 -2
  333. package/node_modules/pino/lib/transport.js +1 -14
  334. package/node_modules/pino/lib/worker.js +1 -4
  335. package/node_modules/pino/package.json +22 -14
  336. package/node_modules/pino/pino.d.ts +736 -709
  337. package/node_modules/pino/pino.js +2 -27
  338. package/node_modules/pino/test/basic.test.js +0 -66
  339. package/node_modules/pino/test/escaping.test.js +0 -17
  340. package/node_modules/pino/test/fixtures/ts/transpile.cjs +3 -3
  341. package/node_modules/pino/test/helper.js +2 -6
  342. package/node_modules/pino/test/multistream.test.js +0 -64
  343. package/node_modules/pino/test/redact.test.js +0 -30
  344. package/node_modules/pino/test/transport/core.test.js +0 -85
  345. package/node_modules/pino/test/transport/sync-false.test.js +0 -12
  346. package/node_modules/pino/test/transport/uses-pino-config.test.js +4 -4
  347. package/node_modules/pino/test/types/pino-import.test-d.cts +30 -0
  348. package/node_modules/pino/test/types/pino-multistream.test-d.ts +28 -0
  349. package/node_modules/pino/test/types/pino-top-export.test-d.ts +34 -0
  350. package/node_modules/pino/test/types/{pino-transport.tst.ts → pino-transport.test-d.ts} +70 -85
  351. package/node_modules/pino/test/types/pino-type-only.test-d.ts +75 -0
  352. package/node_modules/pino/test/types/{pino.tst.ts → pino.test-d.ts} +137 -135
  353. package/node_modules/pino/test/types/pino.ts +7 -14
  354. package/node_modules/pino/tsconfig.json +6 -6
  355. package/node_modules/real-require/README.md +6 -6
  356. package/node_modules/real-require/package.json +21 -10
  357. package/node_modules/real-require/src/index.js +2 -2
  358. package/node_modules/thread-stream/node_modules/real-require/LICENSE.md +21 -0
  359. package/node_modules/thread-stream/node_modules/real-require/README.md +51 -0
  360. package/node_modules/thread-stream/node_modules/real-require/package.json +38 -0
  361. package/node_modules/thread-stream/node_modules/real-require/src/index.js +14 -0
  362. package/package.json +2 -2
  363. package/packages/cli/dist/.tsbuildinfo +1 -1
  364. package/packages/cli/dist/access-cmd.d.ts +10 -0
  365. package/packages/cli/dist/access-cmd.d.ts.map +1 -0
  366. package/packages/cli/dist/access-cmd.js +160 -0
  367. package/packages/cli/dist/access-cmd.js.map +1 -0
  368. package/packages/cli/dist/args.d.ts +10 -0
  369. package/packages/cli/dist/args.d.ts.map +1 -1
  370. package/packages/cli/dist/args.js +29 -1
  371. package/packages/cli/dist/args.js.map +1 -1
  372. package/packages/cli/dist/commands.d.ts.map +1 -1
  373. package/packages/cli/dist/commands.js +28 -2
  374. package/packages/cli/dist/commands.js.map +1 -1
  375. package/packages/cli/dist/doctor-probes.d.ts.map +1 -1
  376. package/packages/cli/dist/doctor-probes.js +54 -29
  377. package/packages/cli/dist/doctor-probes.js.map +1 -1
  378. package/packages/cli/dist/doctor.d.ts +36 -12
  379. package/packages/cli/dist/doctor.d.ts.map +1 -1
  380. package/packages/cli/dist/doctor.js +32 -9
  381. package/packages/cli/dist/doctor.js.map +1 -1
  382. package/packages/cli/dist/main.d.ts +2 -0
  383. package/packages/cli/dist/main.d.ts.map +1 -1
  384. package/packages/cli/dist/main.js +18 -1
  385. package/packages/cli/dist/main.js.map +1 -1
  386. package/packages/core/dist/.tsbuildinfo +1 -1
  387. package/packages/core/dist/agents/catalog.d.ts +2 -0
  388. package/packages/core/dist/agents/catalog.d.ts.map +1 -1
  389. package/packages/core/dist/agents/catalog.js +1 -0
  390. package/packages/core/dist/agents/catalog.js.map +1 -1
  391. package/packages/core/dist/agents/edit.d.ts +2 -0
  392. package/packages/core/dist/agents/edit.d.ts.map +1 -1
  393. package/packages/core/dist/agents/edit.js +3 -1
  394. package/packages/core/dist/agents/edit.js.map +1 -1
  395. package/packages/core/dist/agents/frontmatter.d.ts +11 -0
  396. package/packages/core/dist/agents/frontmatter.d.ts.map +1 -1
  397. package/packages/core/dist/agents/frontmatter.js +7 -0
  398. package/packages/core/dist/agents/frontmatter.js.map +1 -1
  399. package/packages/core/dist/index.d.ts +1 -0
  400. package/packages/core/dist/index.d.ts.map +1 -1
  401. package/packages/core/dist/index.js +1 -0
  402. package/packages/core/dist/index.js.map +1 -1
  403. package/packages/core/dist/plugin/index.d.ts +3 -0
  404. package/packages/core/dist/plugin/index.d.ts.map +1 -1
  405. package/packages/core/dist/plugin/index.js +3 -0
  406. package/packages/core/dist/plugin/index.js.map +1 -1
  407. package/packages/core/dist/plugin/version.d.ts +1 -1
  408. package/packages/core/dist/plugin/version.js +1 -1
  409. package/packages/core/dist/questions/store.d.ts +12 -0
  410. package/packages/core/dist/questions/store.d.ts.map +1 -1
  411. package/packages/core/dist/questions/store.js +11 -1
  412. package/packages/core/dist/questions/store.js.map +1 -1
  413. package/packages/core/dist/questions/types.d.ts +8 -0
  414. package/packages/core/dist/questions/types.d.ts.map +1 -1
  415. package/packages/core/dist/questions/types.js +15 -0
  416. package/packages/core/dist/questions/types.js.map +1 -1
  417. package/packages/core/dist/queue/jobs.d.ts +8 -0
  418. package/packages/core/dist/queue/jobs.d.ts.map +1 -1
  419. package/packages/core/dist/queue/jobs.js +9 -3
  420. package/packages/core/dist/queue/jobs.js.map +1 -1
  421. package/packages/core/dist/queue/worker.d.ts +2 -0
  422. package/packages/core/dist/queue/worker.d.ts.map +1 -1
  423. package/packages/core/dist/queue/worker.js +2 -1
  424. package/packages/core/dist/queue/worker.js.map +1 -1
  425. package/packages/core/dist/registry.d.ts +7 -1
  426. package/packages/core/dist/registry.d.ts.map +1 -1
  427. package/packages/core/dist/registry.js +73 -11
  428. package/packages/core/dist/registry.js.map +1 -1
  429. package/packages/core/dist/routes.d.ts +153 -0
  430. package/packages/core/dist/routes.d.ts.map +1 -0
  431. package/packages/core/dist/routes.js +47 -0
  432. package/packages/core/dist/routes.js.map +1 -0
  433. package/packages/core/dist/scheduler/missions.d.ts +5 -3
  434. package/packages/core/dist/scheduler/missions.d.ts.map +1 -1
  435. package/packages/core/dist/scheduler/missions.js +9 -7
  436. package/packages/core/dist/scheduler/missions.js.map +1 -1
  437. package/packages/core/dist/scheduler/types.d.ts +7 -0
  438. package/packages/core/dist/scheduler/types.d.ts.map +1 -1
  439. package/packages/core/dist/scheduler/types.js +1 -0
  440. package/packages/core/dist/scheduler/types.js.map +1 -1
  441. package/packages/core/dist/tools.d.ts +59 -2
  442. package/packages/core/dist/tools.d.ts.map +1 -1
  443. package/packages/core/dist/tools.js.map +1 -1
  444. package/packages/core/migrations/075_access_providers.sql +43 -0
  445. package/packages/core/migrations/076_mission_browser.sql +7 -0
  446. package/packages/gateway/dist/.tsbuildinfo +1 -1
  447. package/packages/gateway/dist/agents/canvas.d.ts +12 -12
  448. package/packages/gateway/dist/agents/catalogue-package.d.ts +38 -20
  449. package/packages/gateway/dist/agents/catalogue-package.d.ts.map +1 -1
  450. package/packages/gateway/dist/agents/catalogue-package.js +6 -0
  451. package/packages/gateway/dist/agents/catalogue-package.js.map +1 -1
  452. package/packages/gateway/dist/agents/delegation.d.ts +10 -0
  453. package/packages/gateway/dist/agents/delegation.d.ts.map +1 -1
  454. package/packages/gateway/dist/agents/delegation.js +1 -0
  455. package/packages/gateway/dist/agents/delegation.js.map +1 -1
  456. package/packages/gateway/dist/agents/platform-catalogue.d.ts +7 -1
  457. package/packages/gateway/dist/agents/platform-catalogue.d.ts.map +1 -1
  458. package/packages/gateway/dist/agents/platform-catalogue.js +15 -6
  459. package/packages/gateway/dist/agents/platform-catalogue.js.map +1 -1
  460. package/packages/gateway/dist/bootstrap.d.ts.map +1 -1
  461. package/packages/gateway/dist/bootstrap.js +8 -0
  462. package/packages/gateway/dist/bootstrap.js.map +1 -1
  463. package/packages/gateway/dist/browser-host.d.ts +30 -1
  464. package/packages/gateway/dist/browser-host.d.ts.map +1 -1
  465. package/packages/gateway/dist/browser-host.js +56 -1
  466. package/packages/gateway/dist/browser-host.js.map +1 -1
  467. package/packages/gateway/dist/chat/session.d.ts.map +1 -1
  468. package/packages/gateway/dist/chat/session.js +9 -5
  469. package/packages/gateway/dist/chat/session.js.map +1 -1
  470. package/packages/gateway/dist/index.d.ts +2 -1
  471. package/packages/gateway/dist/index.d.ts.map +1 -1
  472. package/packages/gateway/dist/index.js +2 -1
  473. package/packages/gateway/dist/index.js.map +1 -1
  474. package/packages/gateway/dist/missions/execute.d.ts +34 -1
  475. package/packages/gateway/dist/missions/execute.d.ts.map +1 -1
  476. package/packages/gateway/dist/missions/execute.js +92 -8
  477. package/packages/gateway/dist/missions/execute.js.map +1 -1
  478. package/packages/gateway/dist/missions/parked.d.ts +133 -0
  479. package/packages/gateway/dist/missions/parked.d.ts.map +1 -0
  480. package/packages/gateway/dist/missions/parked.js +249 -0
  481. package/packages/gateway/dist/missions/parked.js.map +1 -0
  482. package/packages/gateway/dist/serve.d.ts +7 -0
  483. package/packages/gateway/dist/serve.d.ts.map +1 -1
  484. package/packages/gateway/dist/serve.js +49 -9
  485. package/packages/gateway/dist/serve.js.map +1 -1
  486. package/packages/gateway/dist/surfaces/browser-cards.d.ts +18 -0
  487. package/packages/gateway/dist/surfaces/browser-cards.d.ts.map +1 -0
  488. package/packages/gateway/dist/surfaces/browser-cards.js +42 -0
  489. package/packages/gateway/dist/surfaces/browser-cards.js.map +1 -0
  490. package/packages/gateway/dist/surfaces/browser-continuation.js +1 -1
  491. package/packages/gateway/dist/surfaces/browser-continuation.js.map +1 -1
  492. package/packages/gateway/dist/surfaces/owner-request.d.ts +6 -0
  493. package/packages/gateway/dist/surfaces/owner-request.d.ts.map +1 -1
  494. package/packages/gateway/dist/surfaces/owner-request.js +7 -1
  495. package/packages/gateway/dist/surfaces/owner-request.js.map +1 -1
  496. package/packages/gateway/dist/system-context.d.ts.map +1 -1
  497. package/packages/gateway/dist/system-context.js +6 -7
  498. package/packages/gateway/dist/system-context.js.map +1 -1
  499. package/packages/gateway/dist/telegram/browser-view.d.ts +17 -17
  500. package/packages/gateway/dist/telegram/browser-view.d.ts.map +1 -1
  501. package/packages/gateway/dist/telegram/browser-view.js +33 -37
  502. package/packages/gateway/dist/telegram/browser-view.js.map +1 -1
  503. package/packages/gateway/dist/telegram/channel.d.ts.map +1 -1
  504. package/packages/gateway/dist/telegram/channel.js +17 -1
  505. package/packages/gateway/dist/telegram/channel.js.map +1 -1
  506. package/packages/gateway/dist/telegram/main.d.ts.map +1 -1
  507. package/packages/gateway/dist/telegram/main.js +11 -3
  508. package/packages/gateway/dist/telegram/main.js.map +1 -1
  509. package/packages/gateway/dist/telegram/surface.d.ts.map +1 -1
  510. package/packages/gateway/dist/telegram/surface.js +10 -0
  511. package/packages/gateway/dist/telegram/surface.js.map +1 -1
  512. package/packages/gateway/dist/tips/facts.d.ts +8 -0
  513. package/packages/gateway/dist/tips/facts.d.ts.map +1 -1
  514. package/packages/gateway/dist/tips/facts.js +8 -2
  515. package/packages/gateway/dist/tips/facts.js.map +1 -1
  516. package/packages/gateway/dist/tips/rules.d.ts +2 -0
  517. package/packages/gateway/dist/tips/rules.d.ts.map +1 -1
  518. package/packages/gateway/dist/tips/rules.js +15 -0
  519. package/packages/gateway/dist/tips/rules.js.map +1 -1
  520. package/packages/gateway/dist/web/access/arrival.d.ts +24 -0
  521. package/packages/gateway/dist/web/access/arrival.d.ts.map +1 -0
  522. package/packages/gateway/dist/web/access/arrival.js +18 -0
  523. package/packages/gateway/dist/web/access/arrival.js.map +1 -0
  524. package/packages/gateway/dist/web/access/cloudflare-api.d.ts +124 -0
  525. package/packages/gateway/dist/web/access/cloudflare-api.d.ts.map +1 -0
  526. package/packages/gateway/dist/web/access/cloudflare-api.js +206 -0
  527. package/packages/gateway/dist/web/access/cloudflare-api.js.map +1 -0
  528. package/packages/gateway/dist/web/access/cloudflare-setup.d.ts +163 -0
  529. package/packages/gateway/dist/web/access/cloudflare-setup.d.ts.map +1 -0
  530. package/packages/gateway/dist/web/access/cloudflare-setup.js +438 -0
  531. package/packages/gateway/dist/web/access/cloudflare-setup.js.map +1 -0
  532. package/packages/gateway/dist/web/access/cloudflare-token.d.ts +31 -0
  533. package/packages/gateway/dist/web/access/cloudflare-token.d.ts.map +1 -0
  534. package/packages/gateway/dist/web/access/cloudflare-token.js +74 -0
  535. package/packages/gateway/dist/web/access/cloudflare-token.js.map +1 -0
  536. package/packages/gateway/dist/web/access/cloudflare.d.ts +145 -0
  537. package/packages/gateway/dist/web/access/cloudflare.d.ts.map +1 -0
  538. package/packages/gateway/dist/web/access/cloudflare.js +474 -0
  539. package/packages/gateway/dist/web/access/cloudflare.js.map +1 -0
  540. package/packages/gateway/dist/web/access/index.d.ts +9 -0
  541. package/packages/gateway/dist/web/access/index.d.ts.map +1 -0
  542. package/packages/gateway/dist/web/access/index.js +9 -0
  543. package/packages/gateway/dist/web/access/index.js.map +1 -0
  544. package/packages/gateway/dist/web/access/ingress.d.ts +30 -0
  545. package/packages/gateway/dist/web/access/ingress.d.ts.map +1 -0
  546. package/packages/gateway/dist/web/access/ingress.js +76 -0
  547. package/packages/gateway/dist/web/access/ingress.js.map +1 -0
  548. package/packages/gateway/dist/web/access/provider.d.ts +173 -0
  549. package/packages/gateway/dist/web/access/provider.d.ts.map +1 -0
  550. package/packages/gateway/dist/web/access/provider.js +11 -0
  551. package/packages/gateway/dist/web/access/provider.js.map +1 -0
  552. package/packages/gateway/dist/web/access/registry.d.ts +33 -0
  553. package/packages/gateway/dist/web/access/registry.d.ts.map +1 -0
  554. package/packages/gateway/dist/web/access/registry.js +32 -0
  555. package/packages/gateway/dist/web/access/registry.js.map +1 -0
  556. package/packages/gateway/dist/web/{tailscale.d.ts → access/tailscale.d.ts} +27 -0
  557. package/packages/gateway/dist/web/access/tailscale.d.ts.map +1 -0
  558. package/packages/gateway/dist/web/{tailscale.js → access/tailscale.js} +118 -3
  559. package/packages/gateway/dist/web/access/tailscale.js.map +1 -0
  560. package/packages/gateway/dist/web/agents.d.ts +2 -0
  561. package/packages/gateway/dist/web/agents.d.ts.map +1 -1
  562. package/packages/gateway/dist/web/agents.js +19 -1
  563. package/packages/gateway/dist/web/agents.js.map +1 -1
  564. package/packages/gateway/dist/web/api-routes.d.ts +4 -3
  565. package/packages/gateway/dist/web/api-routes.d.ts.map +1 -1
  566. package/packages/gateway/dist/web/api-routes.js +96 -17
  567. package/packages/gateway/dist/web/api-routes.js.map +1 -1
  568. package/packages/gateway/dist/web/attention.d.ts.map +1 -1
  569. package/packages/gateway/dist/web/attention.js +11 -3
  570. package/packages/gateway/dist/web/attention.js.map +1 -1
  571. package/packages/gateway/dist/web/chat.d.ts +23 -0
  572. package/packages/gateway/dist/web/chat.d.ts.map +1 -1
  573. package/packages/gateway/dist/web/chat.js +62 -2
  574. package/packages/gateway/dist/web/chat.js.map +1 -1
  575. package/packages/gateway/dist/web/client-key.d.ts +3 -0
  576. package/packages/gateway/dist/web/client-key.d.ts.map +1 -1
  577. package/packages/gateway/dist/web/client-key.js +8 -1
  578. package/packages/gateway/dist/web/client-key.js.map +1 -1
  579. package/packages/gateway/dist/web/extension.d.ts +9 -1
  580. package/packages/gateway/dist/web/extension.d.ts.map +1 -1
  581. package/packages/gateway/dist/web/extension.js +61 -1
  582. package/packages/gateway/dist/web/extension.js.map +1 -1
  583. package/packages/gateway/dist/web/http.d.ts +7 -0
  584. package/packages/gateway/dist/web/http.d.ts.map +1 -1
  585. package/packages/gateway/dist/web/http.js +15 -1
  586. package/packages/gateway/dist/web/http.js.map +1 -1
  587. package/packages/gateway/dist/web/index.d.ts +1 -1
  588. package/packages/gateway/dist/web/index.d.ts.map +1 -1
  589. package/packages/gateway/dist/web/index.js +1 -1
  590. package/packages/gateway/dist/web/index.js.map +1 -1
  591. package/packages/gateway/dist/web/onboarding.js +1 -1
  592. package/packages/gateway/dist/web/onboarding.js.map +1 -1
  593. package/packages/gateway/dist/web/server.d.ts +38 -2
  594. package/packages/gateway/dist/web/server.d.ts.map +1 -1
  595. package/packages/gateway/dist/web/server.js +576 -145
  596. package/packages/gateway/dist/web/server.js.map +1 -1
  597. package/packages/gateway/dist/web/sessions.d.ts +24 -14
  598. package/packages/gateway/dist/web/sessions.d.ts.map +1 -1
  599. package/packages/gateway/dist/web/sessions.js +42 -14
  600. package/packages/gateway/dist/web/sessions.js.map +1 -1
  601. package/packages/gateway/dist/web/signed-out.d.ts +10 -0
  602. package/packages/gateway/dist/web/signed-out.d.ts.map +1 -1
  603. package/packages/gateway/dist/web/signed-out.js +47 -0
  604. package/packages/gateway/dist/web/signed-out.js.map +1 -1
  605. package/packages/install/dist/.tsbuildinfo +1 -1
  606. package/packages/runtime/dist/.tsbuildinfo +1 -1
  607. package/packages/runtime/dist/delegate.d.ts +8 -0
  608. package/packages/runtime/dist/delegate.d.ts.map +1 -1
  609. package/packages/runtime/dist/delegate.js +19 -1
  610. package/packages/runtime/dist/delegate.js.map +1 -1
  611. package/packages/runtime/dist/loop.d.ts +2 -0
  612. package/packages/runtime/dist/loop.d.ts.map +1 -1
  613. package/packages/runtime/dist/loop.js +18 -4
  614. package/packages/runtime/dist/loop.js.map +1 -1
  615. package/packages/tools/artifacts/dist/.tsbuildinfo +1 -1
  616. package/packages/tools/browser/dist/.tsbuildinfo +1 -1
  617. package/packages/tools/browser/dist/availability.d.ts +2 -2
  618. package/packages/tools/browser/dist/availability.d.ts.map +1 -1
  619. package/packages/tools/browser/dist/availability.js +2 -2
  620. package/packages/tools/browser/dist/availability.js.map +1 -1
  621. package/packages/tools/browser/dist/controller.d.ts +76 -58
  622. package/packages/tools/browser/dist/controller.d.ts.map +1 -1
  623. package/packages/tools/browser/dist/controller.js +751 -219
  624. package/packages/tools/browser/dist/controller.js.map +1 -1
  625. package/packages/tools/browser/dist/extension.d.ts +12 -0
  626. package/packages/tools/browser/dist/extension.d.ts.map +1 -1
  627. package/packages/tools/browser/dist/extension.js +8 -0
  628. package/packages/tools/browser/dist/extension.js.map +1 -1
  629. package/packages/tools/browser/dist/index.d.ts +13 -5
  630. package/packages/tools/browser/dist/index.d.ts.map +1 -1
  631. package/packages/tools/browser/dist/index.js +29 -12
  632. package/packages/tools/browser/dist/index.js.map +1 -1
  633. package/packages/tools/browser/dist/manager.d.ts +39 -21
  634. package/packages/tools/browser/dist/manager.d.ts.map +1 -1
  635. package/packages/tools/browser/dist/manager.js +229 -136
  636. package/packages/tools/browser/dist/manager.js.map +1 -1
  637. package/packages/tools/browser/dist/routes.d.ts +130 -0
  638. package/packages/tools/browser/dist/routes.d.ts.map +1 -0
  639. package/packages/tools/browser/dist/routes.js +283 -0
  640. package/packages/tools/browser/dist/routes.js.map +1 -0
  641. package/packages/tools/browser/dist/service.d.ts +157 -114
  642. package/packages/tools/browser/dist/service.d.ts.map +1 -1
  643. package/packages/tools/browser/dist/service.js +379 -390
  644. package/packages/tools/browser/dist/service.js.map +1 -1
  645. package/packages/tools/browser/dist/settings.d.ts +88 -0
  646. package/packages/tools/browser/dist/settings.d.ts.map +1 -0
  647. package/packages/tools/browser/dist/settings.js +86 -0
  648. package/packages/tools/browser/dist/settings.js.map +1 -0
  649. package/packages/tools/browser/dist/telemetry.d.ts +203 -0
  650. package/packages/tools/browser/dist/telemetry.d.ts.map +1 -0
  651. package/packages/tools/browser/dist/telemetry.js +142 -0
  652. package/packages/tools/browser/dist/telemetry.js.map +1 -0
  653. package/packages/tools/browser/dist/types.d.ts +14 -3
  654. package/packages/tools/browser/dist/types.d.ts.map +1 -1
  655. package/packages/tools/browser/dist/types.js +9 -9
  656. package/packages/tools/browser/dist/types.js.map +1 -1
  657. package/packages/tools/email/dist/.tsbuildinfo +1 -1
  658. package/packages/tools/host/dist/.tsbuildinfo +1 -1
  659. package/packages/tools/mcp/dist/.tsbuildinfo +1 -1
  660. package/packages/tools/memory/dist/.tsbuildinfo +1 -1
  661. package/packages/tools/web/dist/.tsbuildinfo +1 -1
  662. package/packages/web/dist/assets/index-Bac-CdD-.css +1 -0
  663. package/packages/web/dist/assets/index-DI8bp_D7.js +146 -0
  664. package/packages/web/dist/assets/{lottie_light-CKJ88Yuk.js → lottie_light-CuiSMqnl.js} +1 -1
  665. package/packages/web/dist/build.json +1 -1
  666. package/packages/web/dist/index.html +2 -2
  667. package/packages/web/dist/precache.json +4 -4
  668. package/node_modules/@buddi/gateway/dist/web/apps.d.ts +0 -18
  669. package/node_modules/@buddi/gateway/dist/web/apps.d.ts.map +0 -1
  670. package/node_modules/@buddi/gateway/dist/web/apps.js +0 -84
  671. package/node_modules/@buddi/gateway/dist/web/apps.js.map +0 -1
  672. package/node_modules/@buddi/gateway/dist/web/tailscale.d.ts.map +0 -1
  673. package/node_modules/@buddi/gateway/dist/web/tailscale.js.map +0 -1
  674. package/node_modules/@buddi/tool-browser/dist/computer.d.ts +0 -153
  675. package/node_modules/@buddi/tool-browser/dist/computer.d.ts.map +0 -1
  676. package/node_modules/@buddi/tool-browser/dist/computer.js +0 -392
  677. package/node_modules/@buddi/tool-browser/dist/computer.js.map +0 -1
  678. package/node_modules/@buddi/tool-browser/dist/native/buddi-computer +0 -0
  679. package/node_modules/pino/test/browser-bindings.test.js +0 -114
  680. package/node_modules/pino/test/browser-redaction.test.js +0 -264
  681. package/node_modules/pino/test/browser-set-bindings.test.js +0 -99
  682. package/node_modules/pino/test/caller.test.js +0 -20
  683. package/node_modules/pino/test/fixtures/caller-loop.js +0 -6
  684. package/node_modules/pino/test/smoke.js +0 -59
  685. package/node_modules/pino/test/types/pino-import.tst.cts +0 -30
  686. package/node_modules/pino/test/types/pino-import.tst.js +0 -73
  687. package/node_modules/pino/test/types/pino-multistream.tst.ts +0 -49
  688. package/node_modules/pino/test/types/pino-top-export.tst.ts +0 -32
  689. package/node_modules/pino/test/types/pino-type-only.tst.ts +0 -77
  690. package/node_modules/pino/test/types/tsconfig.json +0 -10
  691. package/packages/gateway/dist/web/apps.d.ts +0 -18
  692. package/packages/gateway/dist/web/apps.d.ts.map +0 -1
  693. package/packages/gateway/dist/web/apps.js +0 -84
  694. package/packages/gateway/dist/web/apps.js.map +0 -1
  695. package/packages/gateway/dist/web/tailscale.d.ts.map +0 -1
  696. package/packages/gateway/dist/web/tailscale.js.map +0 -1
  697. package/packages/tools/browser/dist/computer.d.ts +0 -153
  698. package/packages/tools/browser/dist/computer.d.ts.map +0 -1
  699. package/packages/tools/browser/dist/computer.js +0 -392
  700. package/packages/tools/browser/dist/computer.js.map +0 -1
  701. package/packages/tools/browser/dist/native/buddi-computer +0 -0
  702. package/packages/web/dist/assets/index-CN1AXMI1.css +0 -1
  703. package/packages/web/dist/assets/index-CQRE9LJX.js +0 -145
@@ -1,3 +1,4 @@
1
+ import { existsSync, statSync } from 'node:fs';
1
2
  import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
2
3
  import path from 'node:path';
3
4
  import { randomUUID } from 'node:crypto';
@@ -5,88 +6,199 @@ import { ToolRefusal } from '@buddi/core/plugin';
5
6
  import { BrowserManager } from './manager.js';
6
7
  import { PlaywrightHost } from './host.js';
7
8
  import { PlaywrightDriver } from './driver.js';
8
- import { COMPUTER_HELPER_MISSING, ComputerDriver, computerHelperPresent, NativeComputerBridge, resolveApp, settingsSchema, spotlightApps } from './computer.js';
9
9
  import { ExtensionDriver, NOT_CONNECTED } from './extension.js';
10
+ import { browserStoppedMessage } from './service.js';
10
11
  import { BrowserPreconditionError } from './types.js';
11
12
  import { detectBrowser, HEADLESS_NOTE, installBrowser, InstallProgressReader, missingLibrariesMessage, needsHeadless, noSandboxMessage, NO_BROWSER_STATUS, probeLaunch } from './availability.js';
13
+ import { applySettingsChange, migrateSettings, PIN_VALUES, settingsSchema } from './settings.js';
14
+ import { agoText, cardAnswer, ownerClock, chooseRoute, detectWall, ownerCard, RouteProviderDriver, routeNote, siteListed, siteOf } from './routes.js';
15
+ import { BrowserTelemetry, missionMark, readTelemetry, summarize } from './telemetry.js';
16
+ import { canonicalOrigin, fieldBoundTo } from './secrets.js';
12
17
  const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
13
18
  /** The one control an app card carries: how long the yes lasts. */
14
19
  const REMEMBER = { key: 'remember', label: 'Allow', options: ['Once', 'Always'], default: 'Once' };
15
20
  function isAppEnvelope(value) {
16
21
  return typeof value === 'object' && value !== null && typeof value.allowApp === 'string';
17
22
  }
18
- /** Owner-only mode switch. No automatic fallback and no model-selected driver. */
23
+ /** What the agent is told when an app job has no route: the one fix, never a mode. */
24
+ /** What a mission is told when it asks for the owner's Chrome (docs/browser.md, "Missions"). */
25
+ export const UNATTENDED_CHROME = "A mission looks only in buddi's own browser, never the owner's Chrome: nobody is there to watch it. Use the own browser, or report what needs the owner's sign-in.";
26
+ /** What a mission is told when it asks for an app. */
27
+ export const UNATTENDED_APPS = "A mission looks only in buddi's own browser; the owner's apps need the owner. Report what you could not do instead.";
28
+ export const APPS_UNAVAILABLE = 'Your apps are not available to agents right now. The owner can turn them on, or repair them, in Settings → Where agents may look.';
29
+ /** What the agent is told when no plugin provides the apps route. */
30
+ export const APPS_NOT_INSTALLED = 'Agents cannot work in apps here: that needs the Computer plugin (macOS), which the owner installs from Settings → Plugins.';
31
+ const asApp = (target) => ({ bundleId: target.id, name: target.name });
32
+ const ROUTES = ['own', 'chrome', 'apps'];
33
+ /**
34
+ * Where agents may look, and the runtime that picks for them
35
+ * (docs/browser.md).
36
+ *
37
+ * Three routes, one manager each: buddi's own browser (headless, shown in the
38
+ * Canvas), the owner's Chrome (background tabs through the extension) and the
39
+ * owner's apps (a route a plugin provides: the Computer plugin). The
40
+ * settings are permissions; per task the runtime chooses, falls back
41
+ * silently when a route cannot serve, and says one line when the route was
42
+ * not its own browser. The owner is asked on four occasions only, by card.
43
+ */
19
44
  export class HostController {
20
45
  dir;
21
46
  options;
22
- #manager;
23
47
  #settings = settingsSchema.parse({});
24
- #permissions;
25
48
  #enabled = false;
26
- #changing = false;
27
- #requests = new Map();
28
49
  #extension;
50
+ #providers;
29
51
  #problem;
30
52
  #install;
31
- /** Apps the owner allowed Once, by conversation. Memory only: the ledger answers again after a restart. */
32
53
  #once = new Map();
33
- /** The conversation whose `browser.act` is running, for the driver's app check. */
34
- #acting;
54
+ /** The apps each conversation was let into (listed or allowed by card), for the Telegram picture check. */
55
+ #opened = new Map();
56
+ #names = new Map();
57
+ #managers;
58
+ #ownOptions;
59
+ #host;
60
+ #stop;
61
+ #pins = new Map();
62
+ #learned = new Set();
63
+ /** The route each conversation's page is on: `[owner, agent, conversation]`. */
64
+ #current = new Map();
65
+ /** Notes already said, so the chat line comes once per site and route. */
66
+ #noted = new Set();
67
+ /** Stop cards shown, by conversation, so a Resume tap is understood. */
68
+ #stopCards = new Map();
69
+ /** Cards already handed to a surface, so one moment is one card. */
70
+ #asked = new WeakSet();
71
+ /** Who hears that the owner gave a page back (the gateway continues the run that waited on it). */
72
+ #giveBack = new Set();
73
+ telemetry;
35
74
  constructor(dir, options = {}) {
36
75
  this.dir = dir;
37
76
  this.options = options;
38
77
  this.#extension = options.extensionBridge;
39
- this.#manager = this.#create();
78
+ this.telemetry = new BrowserTelemetry(path.join(dir, 'telemetry.jsonl'), options.service?.now);
79
+ const self = this;
80
+ const hostOptions = {
81
+ profileDir: path.join(this.dir, 'profile'), channel: this.options.channel, allowedHosts: this.options.allowedHosts,
82
+ ...(this.options.lookup ? { lookup: this.options.lookup } : {}),
83
+ detect: () => this.#detect(), report: (problem) => { this.#problem = problem; },
84
+ };
85
+ // Read at launch, so Show the window applies to the next launch without a restart.
86
+ Object.defineProperty(hostOptions, 'headless', { enumerable: true, get: () => self.#headless });
87
+ this.#host = new PlaywrightHost(hostOptions);
88
+ const base = { ...options.service, telemetry: this.telemetry, requestTakeover: (sessionId) => { void this.control('takeover', sessionId).catch(() => undefined); } };
89
+ this.#ownOptions = { ...base, route: 'own', maxSessions: options.limits?.own ?? this.#settings.maxOwnPages, closeHost: () => this.#host.close(),
90
+ ...(options.idleEvictMs !== undefined ? { idleEvictMs: options.idleEvictMs } : {}), ...(options.queueTimeoutMs !== undefined ? { queueTimeoutMs: options.queueTimeoutMs } : {}) };
91
+ this.#managers = {
92
+ own: new BrowserManager(() => this.options.drivers?.own?.() ?? new PlaywrightDriver(this.#host.options, this.#host), this.#ownOptions),
93
+ chrome: new BrowserManager(() => this.options.drivers?.chrome?.() ?? new ExtensionDriver(this.#bridge(), this.options.allowedHosts), { ...base, route: 'chrome', siteLocks: true, maxSessions: options.limits?.chrome ?? 8,
94
+ ...(options.idleEvictMs !== undefined ? { idleEvictMs: options.idleEvictMs } : {}), ...(options.queueTimeoutMs !== undefined ? { queueTimeoutMs: options.queueTimeoutMs } : {}) }),
95
+ apps: new BrowserManager(() => this.#appsDriver(), { ...base, route: 'apps', allowOpen: true, maxSessions: options.limits?.apps ?? 1,
96
+ ...(options.idleEvictMs !== undefined ? { idleEvictMs: options.idleEvictMs } : {}), ...(options.queueTimeoutMs !== undefined ? { queueTimeoutMs: options.queueTimeoutMs } : {}) }),
97
+ };
40
98
  }
41
- /**
42
- * The gateway hands its WebSocket endpoint over once it exists.
43
- *
44
- * Late rather than through the constructor because `hostBrowser` is a
45
- * singleton per data dir and the module that reads its manifest builds it
46
- * before the gateway has a server to attach a socket to. Only the composition
47
- * root calls this, and only before `enable`.
48
- */
99
+ /** The gateway hands its WebSocket endpoint over once it exists. */
49
100
  useExtension(bridge) { this.#extension = bridge; }
50
- #create() {
51
- if (this.options.manager)
52
- return this.options.manager(this.#settings);
53
- if (this.#settings.mode === 'extension') {
54
- // Never silently fall back to another browser: with no endpoint wired,
55
- // the mode the owner chose simply says it is not connected.
56
- const offline = { connected: () => false, send: () => Promise.reject(new Error(NOT_CONNECTED)), close: () => { } };
57
- return new BrowserManager(() => new ExtensionDriver(this.#extension?.() ?? offline, this.options.allowedHosts), { controlFile: path.join(this.dir, 'control.json') });
58
- }
59
- if (this.#settings.mode === 'computer')
60
- return new BrowserManager(() => new ComputerDriver(this.#settings, this.options.bridge?.(), this.options.allowedHosts, (appId) => this.#allowed(appId, this.#acting), (appId) => this.#nameOf(appId)), {
61
- controlFile: path.join(this.dir, 'control.json'), maxSessions: 1, allowOpen: true,
62
- });
63
- const host = new PlaywrightHost({ profileDir: path.join(this.dir, 'profile'), channel: this.options.channel, allowedHosts: this.options.allowedHosts, ...(this.options.lookup ? { lookup: this.options.lookup } : {}),
64
- headless: this.#headless, detect: () => this.#detect(), report: (problem) => { this.#problem = problem; } });
65
- return new BrowserManager(() => new PlaywrightDriver(host.options, host), { controlFile: path.join(this.dir, 'control.json'), closeHost: () => host.close() });
66
- }
67
- get #headless() { return needsHeadless(this.options.platform ?? process.platform, this.options.env ?? process.env); }
101
+ /** The routes plugins provide (core's registry), read on every choice. */
102
+ useRouteProviders(providers) { this.#providers = providers; }
103
+ /** The agents' pins from their `agent.md`. */
104
+ useAgentPins(pin) { this.options.agentPin = pin; }
105
+ #bridge() {
106
+ const offline = { connected: () => false, send: () => Promise.reject(new Error(NOT_CONNECTED)), close: () => { } };
107
+ return this.#extension?.() ?? offline;
108
+ }
109
+ get #env() { return this.options.env ?? process.env; }
110
+ /** Headless unless the owner asked to see the window (or BUDDI_BROWSER_HEADED=1); always headless with no display. */
111
+ get #headless() {
112
+ if (needsHeadless(this.options.platform ?? process.platform, this.#env))
113
+ return true;
114
+ return !(this.#settings.showWindow || this.#env.BUDDI_BROWSER_HEADED === '1');
115
+ }
68
116
  #detect() { return (this.options.detect ?? detectBrowser)(); }
69
- /** The agents' own browser, said for the owner and the model alike. */
70
117
  #engine() {
71
118
  const found = this.#detect();
72
119
  const headless = this.#headless;
73
120
  const problem = found.engine === 'none' ? undefined : this.#problem;
121
+ const forced = needsHeadless(this.options.platform ?? process.platform, this.#env);
74
122
  const message = found.engine === 'none' ? NO_BROWSER_STATUS
75
123
  : problem === 'missing-libraries' ? missingLibrariesMessage()
76
124
  : problem === 'no-sandbox' ? noSandboxMessage()
77
- : headless ? HEADLESS_NOTE : undefined;
125
+ : forced ? HEADLESS_NOTE : undefined;
78
126
  return { engine: found.engine, headless, ...(problem ? { problem } : {}), ...(message ? { message } : {}), ...(this.#install ? { install: { ...this.#install } } : {}) };
79
127
  }
80
- /**
81
- * Playwright's Chromium, downloaded where `PLAYWRIGHT_BROWSERS_PATH` points (the data directory's `browser/engines` in a packaged install). Started here and
82
- * followed through the status: an install takes a minute or more, far
83
- * longer than a request should wait.
84
- */
128
+ /* ---------------- the apps route ---------------- */
129
+ /** The plugin that provides the apps route on this platform, when one is installed. */
130
+ #pluginApps() {
131
+ const platform = this.options.platform ?? process.platform;
132
+ return this.#providers?.().find((provider) => provider.kind === 'apps' && (!provider.platforms || provider.platforms.includes(platform)));
133
+ }
134
+ #appsDriver() {
135
+ const test = this.options.drivers?.apps;
136
+ if (test)
137
+ return test();
138
+ const plugin = this.#pluginApps();
139
+ if (!plugin)
140
+ throw new BrowserPreconditionError(APPS_NOT_INSTALLED);
141
+ return new RouteProviderDriver(plugin, randomUUID());
142
+ }
143
+ /* ---------------- routes and their health ---------------- */
144
+ #chromeConnected() { try {
145
+ return this.#bridge().connected();
146
+ }
147
+ catch {
148
+ return false;
149
+ } }
150
+ #chromePaired() { try {
151
+ return this.#bridge().paired?.() ?? this.#chromeConnected();
152
+ }
153
+ catch {
154
+ return false;
155
+ } }
156
+ routes() {
157
+ const engine = this.#engine();
158
+ const ownOk = engine.engine !== 'none' && !engine.problem;
159
+ const own = { kind: 'own', allowed: true, available: ownOk || this.options.drivers?.own !== undefined, provider: 'core',
160
+ ...(engine.message ? { message: engine.message } : {}),
161
+ ...(engine.engine === 'none' ? { repair: 'install' } : engine.problem === 'no-sandbox' ? { repair: 'sandbox' } : engine.problem ? { repair: 'install' } : {}) };
162
+ const connected = this.#chromeConnected();
163
+ const paired = this.#chromePaired();
164
+ const chrome = { kind: 'chrome', allowed: this.#settings.yourChrome, available: this.#settings.yourChrome && connected, provider: 'core', paired, connected,
165
+ ...(!paired ? { message: 'Add buddi to Chrome and pair it to let agents use your Chrome.', repair: 'pair' }
166
+ : !connected ? { message: 'Your Chrome is paired but not connected right now: open Chrome.' } : {}) };
167
+ const plugin = this.#pluginApps();
168
+ let health;
169
+ if (this.options.drivers?.apps)
170
+ health = { ok: true };
171
+ else if (plugin) {
172
+ try {
173
+ const answered = plugin.health();
174
+ health = answered instanceof Promise ? this.#lastPluginHealth : answered;
175
+ if (answered instanceof Promise)
176
+ void answered.then((value) => { this.#lastPluginHealth = value; }, () => undefined);
177
+ }
178
+ catch (error) {
179
+ health = { ok: false, message: error instanceof Error ? error.message : String(error) };
180
+ }
181
+ }
182
+ else
183
+ health = { ok: false, message: APPS_NOT_INSTALLED, repair: 'install' };
184
+ const installed = plugin !== undefined || this.options.drivers?.apps !== undefined;
185
+ const apps = { kind: 'apps', allowed: installed && this.#settings.yourApps !== 'off', available: installed && this.#settings.yourApps !== 'off' && health.ok,
186
+ provider: plugin?.plugin ?? (this.options.drivers?.apps ? 'test' : ''), installed, mode: this.#settings.yourApps,
187
+ ...(plugin ? { label: plugin.label } : {}),
188
+ ...(health.message ? { message: health.message } : {}), ...(health.repair ? { repair: health.repair } : {}) };
189
+ return [own, chrome, apps];
190
+ }
191
+ #lastPluginHealth = { ok: true };
192
+ #usable() {
193
+ const list = this.routes();
194
+ const allowed = Object.fromEntries(list.map((route) => [route.kind, route.allowed]));
195
+ const available = Object.fromEntries(list.map((route) => [route.kind, route.available]));
196
+ return { allowed, available };
197
+ }
198
+ /* ---------------- install and launch ---------------- */
85
199
  installBrowser() {
86
200
  if (this.#install?.state === 'running')
87
201
  return this.status();
88
- // The installer's lines are read into numbers here and go no further: the
89
- // page draws a bar and says it in buddi's words, never the installer's.
90
202
  const reader = new InstallProgressReader();
91
203
  const install = { state: 'running', progress: reader.progress };
92
204
  this.#install = install;
@@ -106,16 +218,8 @@ export class HostController {
106
218
  });
107
219
  return this.status();
108
220
  }
109
- /**
110
- * Launch the agents' browser once and close it, headed or headless as this
111
- * machine dictates. Only the agents' own browser has a binary to start; the
112
- * other modes answer ok, since there is nothing of buddi's to launch.
113
- * A missing-libraries or no-sandbox failure is remembered as the status's problem, as a
114
- * failed launch from a real session would be.
115
- */
221
+ /** Launch the agents' own browser once and close it: does it start on this machine? */
116
222
  async checkLaunch() {
117
- if (this.#settings.mode !== 'playwright')
118
- return { ok: true };
119
223
  const check = await probeLaunch({
120
224
  headless: this.#headless,
121
225
  detect: () => this.#detect(),
@@ -128,67 +232,162 @@ export class HostController {
128
232
  this.#problem = check.problem;
129
233
  return check;
130
234
  }
131
- get #macOS() { return (this.options.platform ?? process.platform) === 'darwin'; }
235
+ /* ---------------- lifecycle and persistence ---------------- */
236
+ async #readJson(name) {
237
+ try {
238
+ return JSON.parse(await readFile(path.join(this.dir, name), 'utf8'));
239
+ }
240
+ catch (error) {
241
+ if (error.code === 'ENOENT')
242
+ return undefined;
243
+ throw error;
244
+ }
245
+ }
246
+ async #writeJson(name, value) {
247
+ await mkdir(this.dir, { recursive: true, mode: 0o700 });
248
+ const file = path.join(this.dir, name);
249
+ const temp = `${file}.${randomUUID()}.tmp`;
250
+ await writeFile(temp, JSON.stringify(value), { mode: 0o600 });
251
+ await rename(temp, file);
252
+ }
132
253
  async enable() {
133
254
  if (this.#enabled)
134
255
  return;
135
- try {
136
- const stored = settingsSchema.parse(JSON.parse(await readFile(path.join(this.dir, 'settings.json'), 'utf8')));
137
- // Computer control is macOS-only: elsewhere a stored choice of it runs, and reads, as the agents' own browser.
138
- // The file keeps what the owner chose.
139
- this.#settings = stored.mode === 'computer' && !this.#macOS ? { ...stored, mode: 'playwright' } : stored;
256
+ const raw = await this.#readJson('settings.json');
257
+ if (raw !== undefined) {
258
+ const { settings, migrated } = migrateSettings(raw, { paired: this.#chromePaired() });
259
+ this.#settings = settings;
260
+ if (migrated) {
261
+ // The first shape is kept once; a v2 file only loses the apps list the Computer plugin keeps now.
262
+ const v2 = raw?.version === 2;
263
+ await this.#writeJson(v2 ? 'settings.apps.json' : 'settings.v1.json', raw).catch(() => undefined);
264
+ await this.#writeJson('settings.json', settings);
265
+ }
140
266
  }
141
- catch (error) {
142
- if (error.code !== 'ENOENT')
143
- throw error;
267
+ this.#ownOptions.maxSessions = this.options.limits?.own ?? this.#settings.maxOwnPages;
268
+ const control = await this.#readJson('control.json');
269
+ if (control?.stopped) {
270
+ // A Stop from before expiries: it held from when it was written, for the default hour.
271
+ let at = typeof control.at === 'number' ? control.at : undefined;
272
+ if (at === undefined) {
273
+ try {
274
+ at = statSync(path.join(this.dir, 'control.json')).mtimeMs;
275
+ }
276
+ catch {
277
+ at = this.#now();
278
+ }
279
+ }
280
+ const until = control.until === null ? undefined : typeof control.until === 'number' ? control.until : at + 60 * 60_000;
281
+ this.#stop = { at, ...(until !== undefined ? { until } : {}) };
144
282
  }
145
- this.#manager = this.#create();
146
- await this.#manager.enable();
283
+ const pins = await this.#readJson('pins.json');
284
+ for (const [conversation, pin] of Object.entries(pins ?? {}))
285
+ if (PIN_VALUES.includes(pin))
286
+ this.#pins.set(conversation, pin);
287
+ const learned = await this.#readJson('sign-in-sites.json');
288
+ for (const site of Array.isArray(learned) ? learned.slice(-500) : [])
289
+ if (typeof site === 'string')
290
+ this.#learned.add(site);
291
+ await Promise.all(ROUTES.map((route) => this.#managers[route].enable()));
147
292
  this.#enabled = true;
148
293
  }
294
+ #now() { return this.options.service?.now?.() ?? Date.now(); }
295
+ /** The global Stop, if it still holds; an expired one is cleared here. */
296
+ #activeStop() {
297
+ if (this.#stop?.until !== undefined && this.#now() >= this.#stop.until) {
298
+ this.#stop = undefined;
299
+ this.#later(this.#writeJson('control.json', { stopped: false }));
300
+ }
301
+ return this.#stop;
302
+ }
303
+ /* ---------------- status ---------------- */
304
+ #key(ownerId, agentId, conversationId) { return JSON.stringify([ownerId, agentId, conversationId]); }
305
+ #pageOf(scope) {
306
+ for (const route of ROUTES) {
307
+ const manager = this.#managers[route];
308
+ if (manager.child(scope))
309
+ return { route, manager };
310
+ }
311
+ return undefined;
312
+ }
149
313
  status(scope) {
150
- const status = this.#manager.status(scope);
151
- // On macOS, whether "Use my apps" can run at all: an install without the helper says so on that card.
152
- const helper = this.#macOS ? { helper: (this.options.helperPresent ?? computerHelperPresent)() ? { present: true } : { present: false, message: COMPUTER_HELPER_MISSING } } : {};
153
- const metadata = { mode: this.#settings.mode, settings: { ...this.#settings, allowedApps: [...this.#settings.allowedApps] }, permissions: this.#permissions, ...helper,
154
- ...(this.#settings.mode === 'playwright' ? { browser: this.#engine() } : {}) };
314
+ const found = scope ? this.#pageOf(scope) : undefined;
315
+ let status;
316
+ if (scope)
317
+ status = found ? found.manager.status(scope) : { state: this.#enabled ? 'idle' : 'unavailable', enabled: this.#enabled, busy: false, hasScreenshot: false };
318
+ else {
319
+ const sessions = ROUTES.flatMap((route) => this.#managers[route].status().sessions ?? []);
320
+ const latest = sessions.at(-1) ?? { state: this.#enabled ? 'idle' : 'unavailable', enabled: this.#enabled, busy: false, hasScreenshot: false };
321
+ status = { ...latest, busy: sessions.some((session) => session.busy), sessions };
322
+ }
323
+ const stop = this.#activeStop();
324
+ if (stop && !status.session)
325
+ status = { ...status, state: 'stopped' };
326
+ const metadata = {
327
+ settings: { ...this.#settings, signInSites: [...this.#settings.signInSites] },
328
+ // The sites buddi added itself when it met their sign-in page: one list with the owner's in Settings.
329
+ learnedSignInSites: [...this.#learned].filter((site) => !this.#settings.signInSites.includes(site)).sort(),
330
+ browser: this.#engine(), routes: this.routes(),
331
+ ...(stop ? { stop: { at: new Date(stop.at).toISOString(), ...(stop.until !== undefined ? { until: new Date(stop.until).toISOString() } : {}) } } : {}),
332
+ ...(scope?.conversationId && this.#pins.has(scope.conversationId) ? { pin: this.#pins.get(scope.conversationId) } : {}),
333
+ };
155
334
  const once = (entry) => {
156
335
  const allowed = entry.session ? this.#once.get(entry.session.conversationId) : undefined;
157
- return allowed?.size && entry.session ? { ...entry, session: { ...entry.session, allowedOnce: [...allowed] } } : entry;
336
+ const opened = entry.session ? this.#opened.get(entry.session.conversationId) : undefined;
337
+ const withMode = { ...entry, mode: entry.mode ?? 'playwright' };
338
+ if (!withMode.session || (!allowed?.size && !opened?.size))
339
+ return withMode;
340
+ return { ...withMode, session: { ...withMode.session, ...(allowed?.size ? { allowedOnce: [...allowed] } : {}), ...(opened?.size ? { allowedApps: [...opened] } : {}) } };
158
341
  };
159
342
  return once({ ...status, ...metadata, ...(status.sessions ? { sessions: status.sessions.map((session) => once({ ...session, ...metadata })) } : {}) });
160
343
  }
161
- /** On the owner's list, or allowed Once in this conversation. */
162
- #allowed(appId, conversationId) {
163
- return this.#settings.allowedApps.includes(appId) || (conversationId !== undefined && this.#once.get(conversationId)?.has(appId) === true);
344
+ /** `buddi doctor browser`: the last week of stops, cards and routes. */
345
+ telemetrySummary(days = 7) {
346
+ const file = this.telemetry.file;
347
+ const events = file && existsSync(file) ? readTelemetry(file) : this.telemetry.events;
348
+ return summarize(events, this.#now(), days);
164
349
  }
165
- /** Display names already looked up, by bundle id, for the agent's sentences. */
166
- #names = new Map();
167
- #remember(app) { if (app.name !== app.bundleId)
168
- this.#names.set(app.bundleId, app.name); return app; }
169
- /** An app's display name, from an earlier lookup or Spotlight. Undefined when not found. */
170
- async #nameOf(appId) {
171
- const known = this.#names.get(appId);
172
- if (known)
173
- return known;
350
+ /* ---------------- apps: names, cards, Once / Always ---------------- */
351
+ /**
352
+ * May this conversation open the app without a card? `ask` asks every
353
+ * time; `on` opens what the plugin lists. A Once yes counts either way.
354
+ */
355
+ async #allowed(appId, conversationId) {
356
+ const once = conversationId !== undefined && this.#once.get(conversationId)?.has(appId) === true;
357
+ if (once)
358
+ return true;
359
+ if (this.#settings.yourApps !== 'on')
360
+ return false;
361
+ const reach = this.#pluginApps()?.reach;
362
+ if (!reach)
363
+ return this.options.drivers?.apps !== undefined || this.#pluginApps() !== undefined;
174
364
  try {
175
- return this.#remember(await resolveApp({ bundleId: appId }, this.options.resolveApp ?? spotlightApps)).name;
365
+ return (await reach.listed(appId)) === true;
176
366
  }
177
367
  catch {
178
- return undefined;
368
+ return false;
179
369
  }
180
370
  }
181
- /** The app an `open` names, as found on this Mac. An allowed bundle id needs no lookup. */
371
+ #remember(app) { if (app.name !== app.bundleId)
372
+ this.#names.set(app.bundleId, app.name); return app; }
182
373
  async #resolve(command, conversationId) {
183
- const resolver = this.options.resolveApp ?? spotlightApps;
184
- if (command.app !== undefined)
185
- return this.#remember(await resolveApp({ name: command.app }, resolver));
186
- const appId = command.appId;
187
- if (this.#allowed(appId, conversationId))
188
- return { bundleId: appId, name: this.#names.get(appId) ?? appId };
189
- return this.#remember(await resolveApp({ bundleId: appId }, resolver));
190
- }
191
- /** `#resolve`, with its refusal said as the tool's own sentence. */
374
+ const reach = this.#pluginApps()?.reach;
375
+ if (command.app === undefined && await this.#allowed(command.appId, conversationId))
376
+ return { bundleId: command.appId, name: this.#names.get(command.appId) ?? command.appId };
377
+ if (!reach) {
378
+ if (command.app !== undefined)
379
+ throw new BrowserPreconditionError(`The apps route cannot look up ${command.app} by name. Ask with its id.`);
380
+ return { bundleId: command.appId, name: command.appId };
381
+ }
382
+ try {
383
+ return this.#remember(asApp(await reach.resolve(command.app !== undefined ? { name: command.app } : { id: command.appId })));
384
+ }
385
+ catch (error) {
386
+ if (error.precondition === true && !(error instanceof BrowserPreconditionError))
387
+ throw new BrowserPreconditionError(error.message);
388
+ throw error;
389
+ }
390
+ }
192
391
  async #resolveOrRefuse(command, conversationId) {
193
392
  try {
194
393
  return await this.#resolve(command, conversationId);
@@ -197,20 +396,33 @@ export class HostController {
197
396
  throw error instanceof BrowserPreconditionError ? new ToolRefusal(error.message) : error;
198
397
  }
199
398
  }
200
- /**
201
- * Session for everything but an `open`, in computer mode, of an app the
202
- * owner has not allowed: that one is gated, so the owner gets a card.
203
- *
204
- * Asked once per app and conversation, from core's own ledger: a yes Once
205
- * lets it through (remembered here, too, for the screen guards), a no is
206
- * refused without a second card, and a card still waiting is not doubled.
207
- */
399
+ /** What the plugin does with an app not on its list: a card, or a refusal. */
400
+ async #unlisted() {
401
+ const reach = this.#pluginApps()?.reach;
402
+ if (!reach || this.#settings.yourApps === 'ask')
403
+ return 'ask';
404
+ try {
405
+ return (await reach.unlisted()) === 'refuse' ? 'refuse' : 'ask';
406
+ }
407
+ catch {
408
+ return 'ask';
409
+ }
410
+ }
411
+ /** Session for everything but an `open` of an app the owner has not allowed: that one asks with a card. */
208
412
  async tierFor(command, ctx) {
209
- if (command.action !== 'open' || this.#settings.mode !== 'computer')
413
+ if (command.action !== 'open' || this.#settings.yourApps === 'off')
414
+ return { tier: 'session' };
415
+ // No app card for a mission: nobody is there to answer it, and apps are never its route.
416
+ if (!ctx.ownerRequest)
417
+ throw new ToolRefusal(UNATTENDED_APPS);
418
+ // No plugin provides apps: no card either; the call itself says what to install.
419
+ if (!this.#pluginApps() && !this.options.drivers?.apps)
210
420
  return { tier: 'session' };
211
421
  const app = await this.#resolveOrRefuse(command, ctx.conversationId);
212
- if (this.#allowed(app.bundleId, ctx.conversationId))
422
+ if (await this.#allowed(app.bundleId, ctx.conversationId))
213
423
  return { tier: 'session' };
424
+ if (await this.#unlisted() === 'refuse')
425
+ throw new ToolRefusal(`${app.name} is not on the owner's list of apps, and the owner said not to open others. They can add it in Settings → Computer.`);
214
426
  const conversationId = ctx.conversationId;
215
427
  if (conversationId && UUID.test(conversationId) && ctx.buddi?.approvals.decisionsInConversation) {
216
428
  const cards = (await ctx.buddi.approvals.decisionsInConversation('browser.act', conversationId))
@@ -228,15 +440,14 @@ export class HostController {
228
440
  return { tier: 'gated' };
229
441
  }
230
442
  async describe(command, ctx) {
231
- // Always looked up, never read from an allowance: the executor describes
232
- // again before it runs, and the card must say the same both times.
233
443
  const app = await this.#resolveOrRefuse(command, undefined);
234
444
  const agent = ctx.agentId ?? 'An agent';
235
445
  const envelope = { tool: 'browser.act', allowApp: app.bundleId, name: app.name };
446
+ const always = this.#settings.yourApps === 'on' && this.#pluginApps()?.reach?.remember !== undefined;
236
447
  return {
237
448
  envelope,
238
449
  preview: `Use ${app.name} on your computer?\n${agent} wants to open ${app.name} (${app.bundleId}). While it works, buddi sees that window's screen and sends it to the model, as with the apps you allowed already.`,
239
- choices: [{ ...REMEMBER, options: [...REMEMBER.options] }],
450
+ choices: [{ ...REMEMBER, options: always ? [...REMEMBER.options] : ['Once'] }],
240
451
  };
241
452
  }
242
453
  #allowOnce(conversationId, appId) {
@@ -244,31 +455,31 @@ export class HostController {
244
455
  apps.add(appId);
245
456
  this.#once.set(conversationId, apps);
246
457
  }
247
- /**
248
- * The owner said yes on the card. Once: this conversation. Always: the
249
- * owner's list, written the way Settings writes it — without restarting
250
- * the driver, since the agent's session is usually live. A full list falls
251
- * back to Once and says so.
252
- */
253
458
  async #grant(command, ctx) {
254
- if (this.#settings.mode !== 'computer')
255
- throw new BrowserPreconditionError('Computer control is no longer on, so there is no app to allow. Ask the owner.');
459
+ if (this.#settings.yourApps === 'off' || !this.#pluginApps())
460
+ throw new BrowserPreconditionError('Your apps are off, so there is no app to allow. Ask the owner.');
256
461
  if (!ctx.conversationId)
257
462
  throw new Error('An app is allowed for a conversation, and this call has none.');
258
463
  const app = await this.#resolve(command, undefined);
259
464
  let remember = ctx.choices?.remember === 'Always' ? 'Always' : 'Once';
260
465
  let note = '';
261
- if (remember === 'Always' && !this.#settings.allowedApps.includes(app.bundleId)) {
262
- if (this.#settings.allowedApps.length >= 32) {
466
+ const reach = this.#pluginApps()?.reach;
467
+ if (remember === 'Always') {
468
+ let kept = false;
469
+ try {
470
+ kept = reach?.remember ? await reach.remember({ id: app.bundleId, name: app.name }) : false;
471
+ }
472
+ catch {
473
+ kept = false;
474
+ }
475
+ if (!kept) {
263
476
  remember = 'Once';
264
- note = ' The list of apps is full (32), so it is allowed for this conversation only.';
477
+ note = ' The list of apps could not take it (it may be full), so it is allowed for this conversation only.';
265
478
  }
266
- else
267
- await this.#writeSettings({ ...this.#settings, allowedApps: [...this.#settings.allowedApps, app.bundleId] });
268
479
  }
269
480
  if (remember === 'Once')
270
481
  this.#allowOnce(ctx.conversationId, app.bundleId);
271
- const how = remember === 'Always' ? 'Always: it is now on the list in Settings' : 'Once: for this conversation';
482
+ const how = remember === 'Always' ? 'Always: it is now on the list in Settings → Computer' : 'Once: for this conversation';
272
483
  return {
273
484
  allowed: { appId: app.bundleId, name: app.name, remember },
274
485
  message: `Allowed ${app.name} (${how}).${note}`,
@@ -277,143 +488,464 @@ export class HostController {
277
488
  }
278
489
  async #writeSettings(next) {
279
490
  const parsed = settingsSchema.parse(next);
280
- await mkdir(this.dir, { recursive: true, mode: 0o700 });
281
- const file = path.join(this.dir, 'settings.json');
282
- const temp = `${file}.${randomUUID()}.tmp`;
283
- await writeFile(temp, JSON.stringify(parsed), { mode: 0o600 });
284
- await rename(temp, file);
491
+ await this.#writeJson('settings.json', parsed);
285
492
  this.#settings = parsed;
493
+ this.#ownOptions.maxSessions = this.options.limits?.own ?? parsed.maxOwnPages;
494
+ }
495
+ /* ---------------- pages ---------------- */
496
+ screenshot(sessionId) {
497
+ if (sessionId)
498
+ return this.#pageOf({ sessionId })?.manager.screenshot(sessionId);
499
+ const latest = this.status().session?.id;
500
+ return latest ? this.#pageOf({ sessionId: latest })?.manager.screenshot(latest) : undefined;
286
501
  }
287
- screenshot(sessionId) { return this.#manager.screenshot(sessionId); }
288
502
  hand(scope) {
289
- if (this.#changing)
290
- return { supported: true, message: 'Control settings are changing. Wait before driving.' };
291
- return this.#manager.hand(scope);
503
+ const found = scope ? this.#pageOf(scope) : undefined;
504
+ if (!found)
505
+ return { supported: true, message: 'That page changed. Refresh before driving it.' };
506
+ return found.manager.hand(scope);
292
507
  }
293
508
  rollover(input) {
294
- if (this.#changing)
295
- throw new Error('Control settings are changing. Wait before continuing.');
296
- const moved = this.#manager.rollover(input);
509
+ let moved = false;
510
+ for (const route of ROUTES)
511
+ moved = this.#managers[route].rollover(input) || moved;
512
+ const oldKey = this.#key(input.ownerId, input.agentId, input.previousConversationId);
513
+ const current = this.#current.get(oldKey);
514
+ if (moved && current) {
515
+ this.#current.delete(oldKey);
516
+ this.#current.set(this.#key(input.ownerId, input.agentId, input.conversationId), current);
517
+ }
297
518
  const once = this.#once.get(input.previousConversationId);
298
519
  if (moved && once) {
299
520
  this.#once.delete(input.previousConversationId);
300
521
  this.#once.set(input.conversationId, once);
301
522
  }
523
+ const opened = this.#opened.get(input.previousConversationId);
524
+ if (moved && opened) {
525
+ this.#opened.delete(input.previousConversationId);
526
+ this.#opened.set(input.conversationId, opened);
527
+ }
528
+ const pin = this.#pins.get(input.previousConversationId);
529
+ if (pin) {
530
+ this.#pins.set(input.conversationId, pin);
531
+ this.#later(this.#savePins());
532
+ }
302
533
  return moved;
303
534
  }
535
+ /** The owner's own sign-in list, plus the sites buddi met a login wall on. */
536
+ #signInSite(site) {
537
+ return siteListed(site, this.#settings.signInSites) || siteListed(site, this.#learned);
538
+ }
539
+ #learn(site) {
540
+ if (!site || this.#learned.has(site))
541
+ return;
542
+ this.#learned.add(site);
543
+ this.#later(this.#saveLearned());
544
+ }
545
+ #learnedWrite = Promise.resolve();
546
+ /** One write at a time, each of the list as it is then: a late write never brings back a forgotten site. */
547
+ #saveLearned() {
548
+ const next = this.#learnedWrite.catch(() => undefined).then(() => this.#writeJson('sign-in-sites.json', [...this.#learned].slice(-500)));
549
+ this.#learnedWrite = next;
550
+ return next;
551
+ }
552
+ async #storedLogin(ctx, url) {
553
+ const origin = canonicalOrigin(url);
554
+ if (!origin || !ctx.buddi?.secrets)
555
+ return false;
556
+ try {
557
+ return (await ctx.buddi.secrets.list()).some((secret) => fieldBoundTo(secret.bindings, origin));
558
+ }
559
+ catch {
560
+ return false;
561
+ }
562
+ }
563
+ #pinFor(ctx) {
564
+ return {
565
+ conversation: ctx.conversationId ? this.#pins.get(ctx.conversationId) : undefined,
566
+ agent: ctx.agentId ? this.options.agentPin?.(ctx.agentId) : undefined,
567
+ global: this.#settings.defaultRoute,
568
+ };
569
+ }
570
+ /** Hand a card to the surface once, as a question with choices. */
571
+ #ask(ctx, card) {
572
+ if (this.#asked.has(card))
573
+ return;
574
+ this.#asked.add(card);
575
+ try {
576
+ ctx.ask?.({ question: card.question, options: card.options.map((option) => ({ label: option.label, ...(option.hint ? { hint: option.hint } : {}), ...(option.recommended ? { recommended: true } : {}) })), allowOther: false });
577
+ }
578
+ catch { /* a surface's drawing never decides a run */ }
579
+ }
580
+ /** How long a mission run waits on a card for the owner, in milliseconds (settings `missionWaitMinutes`). */
581
+ missionWaitMs() {
582
+ return this.#settings.missionWaitMinutes * 60_000;
583
+ }
304
584
  async execute(command, ctx) {
305
- if (this.#changing)
306
- throw new Error('Computer/browser settings are changing. Wait for the owner.');
307
- for (const [id, record] of this.#requests)
308
- if (record.expiresAt <= Date.now())
309
- this.#requests.delete(id);
310
- if (ctx.ownerRequest) {
311
- if (this.#requests.get(ctx.ownerRequest.id)?.revoked)
312
- throw new Error('Control settings changed. A new owner request is required.');
313
- this.#requests.set(ctx.ownerRequest.id, { expiresAt: ctx.ownerRequest.expiresAt, revoked: false });
314
- }
315
- if (this.#settings.mode !== 'computer' && (command.action === 'open' || command.target?.x !== undefined))
316
- throw new Error('Native apps and coordinate targets require Computer mode. Only the owner can change modes.');
585
+ ctx.signal?.throwIfAborted();
586
+ if (!this.#enabled)
587
+ throw new Error('Browser driving is available through buddi serve.');
588
+ if (!ctx.agentId || !ctx.conversationId || !ctx.buddi)
589
+ throw new Error('A browser action belongs to an agent and a conversation.');
590
+ const unattended = !ctx.ownerRequest;
591
+ // The owner's Stop: one card with Resume, never a Settings trip.
592
+ const stop = this.#activeStop();
593
+ if (stop && command.action !== 'close') {
594
+ this.telemetry.stop('owner-stop', { route: 'own', agent: ctx.agentId, ...missionMark(ctx), ...(ctx.surface?.id ? { surface: ctx.surface.id } : {}) });
595
+ // The core context carries the owner's zone; the plugin type does not name it.
596
+ const clock = (at) => ownerClock(at, ctx.timezone);
597
+ const wanted = command.action === 'navigate' ? siteOf(command.url) : undefined;
598
+ const card = ownerCard('stopped', { since: clock(stop.at), stoppedAgo: agoText(this.#now() - stop.at), ...(stop.until !== undefined ? { until: clock(stop.until) } : {}), ...(wanted ? { site: wanted } : {}) });
599
+ this.#stopCards.set(ctx.conversationId, card);
600
+ // The owner's own Stop is not a moment to park a mission on: it says so and ends.
601
+ if (!unattended)
602
+ this.#ask(ctx, card);
603
+ return { completed: false, dispatched: false, needsOwner: card, message: `${browserStoppedMessage(ctx.surface)} Say that in one sentence and stop.` };
604
+ }
317
605
  // The owner's yes on an app card, run by core's executor: record it; the agent opens next.
318
606
  if (ctx.actionId !== undefined && command.action === 'open')
319
607
  return this.#grant(command, ctx);
608
+ if (unattended && command.action === 'open') {
609
+ this.telemetry.stop('apps-unavailable', { route: 'apps', agent: ctx.agentId, ...missionMark(ctx) });
610
+ throw new ToolRefusal(UNATTENDED_APPS);
611
+ }
612
+ const key = this.#key(ctx.buddi.owner.id, ctx.agentId, ctx.conversationId);
613
+ if (command.action === 'close') {
614
+ for (const route of ROUTES)
615
+ await this.#managers[route].execute(command, ctx);
616
+ this.#current.delete(key);
617
+ return { closed: true };
618
+ }
619
+ if (command.target?.x !== undefined && this.#current.get(key) !== 'apps') {
620
+ throw new BrowserPreconditionError('Coordinates are for an app window. On a web page, use a ref from the page.');
621
+ }
320
622
  let run = command;
623
+ let appName;
321
624
  if (command.action === 'open') {
625
+ if (!this.#pluginApps() && !this.options.drivers?.apps) {
626
+ this.telemetry.stop('apps-unavailable', { route: 'apps', agent: ctx.agentId });
627
+ throw new Error(APPS_NOT_INSTALLED);
628
+ }
629
+ if (this.#settings.yourApps === 'off') {
630
+ this.telemetry.stop('apps-unavailable', { route: 'apps', agent: ctx.agentId, ...missionMark(ctx) });
631
+ throw new Error(APPS_UNAVAILABLE);
632
+ }
322
633
  const app = await this.#resolve(command, ctx.conversationId);
323
- if (!this.#allowed(app.bundleId, ctx.conversationId))
634
+ if (!await this.#allowed(app.bundleId, ctx.conversationId))
324
635
  throw new BrowserPreconditionError(`${app.name} is not allowed yet. Ask to open it again so the owner gets a card.`);
325
636
  run = { ...command, appId: app.bundleId, app: undefined };
637
+ appName = app.name;
638
+ const opened = this.#opened.get(ctx.conversationId) ?? new Set();
639
+ opened.add(app.bundleId);
640
+ this.#opened.set(ctx.conversationId, opened);
326
641
  }
327
- this.#acting = ctx.conversationId;
328
- try {
329
- return await this.#manager.execute(run, ctx);
642
+ // A mission browses in buddi's own browser only: asked for the owner's Chrome, it is told so plainly (no pin changes that).
643
+ if (unattended && command.prefer === 'yours') {
644
+ this.telemetry.stop('route-unavailable', { route: 'chrome', agent: ctx.agentId, ...missionMark(ctx) });
645
+ throw new ToolRefusal(UNATTENDED_CHROME);
646
+ }
647
+ let route = this.#current.get(key);
648
+ let choice = { route, reason: 'continuing' };
649
+ const site = siteOf(command.url);
650
+ if (!route || command.action === 'navigate' || command.action === 'open') {
651
+ const { allowed, available } = this.#usable();
652
+ choice = chooseRoute({ command: run, prefer: command.prefer, pins: this.#pinFor(ctx), allowed, available, signInSite: this.#signInSite(site), unattended });
653
+ // A task already in the owner's Chrome stays there for its next page (a checkout on
654
+ // another domain keeps his sign-in), unless something asked for another route.
655
+ if (route === 'chrome' && command.action === 'navigate' && choice.route === 'own' && choice.reason === 'default' && allowed.chrome && available.chrome) {
656
+ choice = { route: 'chrome', reason: 'continuing' };
657
+ }
658
+ if (!choice.route) {
659
+ this.telemetry.stop('apps-unavailable', { route: 'apps', agent: ctx.agentId, ...missionMark(ctx) });
660
+ throw new Error(unattended ? UNATTENDED_APPS : APPS_UNAVAILABLE);
661
+ }
662
+ if (choice.fallbackFrom)
663
+ this.telemetry.stop('route-unavailable', { route: choice.route, agent: ctx.agentId, ...missionMark(ctx), ...(site ? { host: site } : {}) });
664
+ if (route && route !== choice.route)
665
+ await this.#managers[route].release(ctx.conversationId, ctx.agentId);
666
+ if (route !== choice.route)
667
+ this.telemetry.record({ type: 'browser.route', chosen: choice.route, reason: choice.reason, ...(choice.fallbackFrom ? { fallbackFrom: choice.fallbackFrom } : {}), agent: ctx.agentId, ...missionMark(ctx), ...(site ? { host: site } : {}) });
668
+ route = choice.route;
669
+ this.#current.set(key, route);
330
670
  }
331
- finally {
332
- if (this.#acting === ctx.conversationId)
333
- this.#acting = undefined;
671
+ let result;
672
+ {
673
+ try {
674
+ result = await this.#managers[route].execute(run, ctx);
675
+ }
676
+ catch (error) {
677
+ // The owner's Chrome went away: the same page in buddi's own browser, silently.
678
+ if (route !== 'chrome' || !(error instanceof Error) || !error.message.includes(NOT_CONNECTED.slice(0, 30)))
679
+ throw error;
680
+ this.telemetry.stop('not-connected', { route: 'chrome', agent: ctx.agentId, ...missionMark(ctx), ...(site ? { host: site } : {}) });
681
+ const last = this.#managers.chrome.child({ agentId: ctx.agentId, conversationId: ctx.conversationId })?.lastUrl;
682
+ await this.#managers.chrome.release(ctx.conversationId, ctx.agentId);
683
+ route = 'own';
684
+ this.#current.set(key, route);
685
+ choice = { route, reason: 'chrome-unavailable', fallbackFrom: 'chrome' };
686
+ const url = run.action === 'navigate' ? run.url : last;
687
+ if (!url)
688
+ throw error;
689
+ result = await this.#managers.own.execute({ action: 'navigate', url }, ctx);
690
+ }
691
+ ({ result, route, choice } = await this.#walls(result, route, choice, ctx, unattended));
334
692
  }
693
+ return this.#annotate(result, route, choice, ctx, appName);
335
694
  }
336
695
  /**
337
- * The gates `execute` runs before anything reaches a manager, secret uses
338
- * included: settings are not changing mid-flight, and a request the owner
339
- * revoked while changing them is not one a secret can ride.
696
+ * A login wall or a human check on the page just returned. In buddi's own
697
+ * browser a sign-in moves to the owner's Chrome when it is allowed and
698
+ * connected (the site is remembered as one that needs his sign-in); a
699
+ * stored login is pointed at; otherwise one Sign in card. A captcha is a
700
+ * Human check card wherever it appears.
340
701
  */
341
- #secret(run, ctx) {
342
- if (this.#changing)
343
- throw new Error('Computer/browser settings are changing. Wait for the owner.');
344
- for (const [id, record] of this.#requests)
345
- if (record.expiresAt <= Date.now())
346
- this.#requests.delete(id);
347
- if (ctx.ownerRequest) {
348
- if (this.#requests.get(ctx.ownerRequest.id)?.revoked)
349
- throw new Error('Control settings changed. A new owner request is required.');
350
- this.#requests.set(ctx.ownerRequest.id, { expiresAt: ctx.ownerRequest.expiresAt, revoked: false });
351
- }
352
- return run(this.#manager);
702
+ async #walls(result, route, choice, ctx, unattended) {
703
+ const observation = result;
704
+ if (!observation?.observation || observation.needsOwner)
705
+ return { result, route, choice };
706
+ const wall = detectWall(observation.observation);
707
+ if (!wall)
708
+ return { result, route, choice };
709
+ const scope = { agentId: ctx.agentId, conversationId: ctx.conversationId };
710
+ const child = this.#managers[route].child(scope);
711
+ if (!child)
712
+ return { result, route, choice };
713
+ const url = observation.observation.url;
714
+ const site = siteOf(url);
715
+ if (wall === 'human') {
716
+ this.telemetry.stop('human-check', { route, agent: ctx.agentId, ...missionMark(ctx), ...(site ? { host: site } : {}) });
717
+ const card = child.park('human');
718
+ return { result: { ...observation, completed: false, needsOwner: card, message: `${site ?? 'This page'} asks for a human. Say so in one sentence and stop; the card asks the owner to take over.` }, route, choice };
719
+ }
720
+ this.#learn(site);
721
+ const { allowed, available } = this.#usable();
722
+ const chromeUsable = allowed.chrome && available.chrome && !unattended;
723
+ // A pin to another route (the conversation's, the agent's, the default) holds here too:
724
+ // the move to the owner's Chrome is then his choice on the card, never automatic.
725
+ const pins = this.#pinFor(ctx);
726
+ const pin = [pins.conversation, pins.agent, pins.global].find((value) => value !== undefined && value !== 'auto');
727
+ if (route === 'own' && chromeUsable && (pin === undefined || pin === 'chrome')) {
728
+ // The owner is signed in there: the same address, in a background tab of his Chrome.
729
+ await this.#managers.own.release(ctx.conversationId, ctx.agentId);
730
+ const key = this.#key(ctx.buddi.owner.id, ctx.agentId, ctx.conversationId);
731
+ this.#current.set(key, 'chrome');
732
+ this.telemetry.record({ type: 'browser.route', chosen: 'chrome', reason: 'sign-in-fallback', fallbackFrom: 'own', agent: ctx.agentId, ...missionMark(ctx), ...(site ? { host: site } : {}) });
733
+ const moved = await this.#managers.chrome.execute({ action: 'navigate', url }, ctx);
734
+ return this.#walls(moved, 'chrome', { route: 'chrome', reason: 'sign-in-fallback', fallbackFrom: 'own' }, ctx, unattended);
735
+ }
736
+ if (await this.#storedLogin(ctx, url)) {
737
+ return { result: { ...observation, message: `${observation.message ?? ''} This is a sign-in page and the owner keeps a login for it: secret.list, then secret.fill (a TOTP secret answers a code).`.trim() }, route, choice };
738
+ }
739
+ // A mission's sign-in is one of the four moments too: the card parks the run until the owner answers (Take over, or a saved login).
740
+ this.telemetry.stop('sign-in', { route, agent: ctx.agentId, ...missionMark(ctx), ...(site ? { host: site } : {}) });
741
+ const card = child.park(wall === 'code' ? 'code' : 'sign-in', { chrome: route === 'chrome' ? 'none' : chromeUsable ? 'usable' : allowed.chrome && !available.chrome ? 'offline' : 'none', storedLogin: false });
742
+ return { result: { ...observation, completed: false, needsOwner: card, message: `${card.title}. Say that in one sentence and stop; the card has Take over. You continue when the owner gives the page back.` }, route, choice };
743
+ }
744
+ #annotate(result, route, choice, ctx, appName) {
745
+ if (!result || typeof result !== 'object')
746
+ return result;
747
+ const value = result;
748
+ const site = siteOf(value.observation?.url) ?? undefined;
749
+ let note;
750
+ const reason = choice.reason;
751
+ if (route !== 'own' || choice.fallbackFrom) {
752
+ const candidate = routeNote(route, reason, site, appName);
753
+ const said = `${ctx.conversationId}|${route}|${site ?? appName ?? ''}`;
754
+ if (candidate && !this.#noted.has(said) && reason !== 'continuing') {
755
+ this.#noted.add(said);
756
+ note = candidate;
757
+ }
758
+ }
759
+ if (value.needsOwner)
760
+ this.#ask(ctx, value.needsOwner);
761
+ return { ...value, route, ...(note ? { routeNote: note } : {}) };
762
+ }
763
+ /** The secret tools act on the page the conversation is already on, whichever route it is. */
764
+ async #secretRoute(ctx) {
765
+ if (!this.#enabled)
766
+ throw new Error('Browser driving is available through buddi serve.');
767
+ if (this.#activeStop())
768
+ throw new Error(browserStoppedMessage(ctx.surface));
769
+ const found = ctx.agentId && ctx.conversationId ? this.#pageOf({ agentId: ctx.agentId, conversationId: ctx.conversationId }) : undefined;
770
+ return found?.manager ?? this.#managers.own;
353
771
  }
354
772
  async secretFill(input, ctx) {
355
- return this.#secret((manager) => manager.secretFill(input, ctx), ctx);
773
+ const manager = await this.#secretRoute(ctx);
774
+ const result = await manager.secretFill(input, ctx);
775
+ const card = result?.needsOwner;
776
+ if (card)
777
+ this.#ask(ctx, card);
778
+ return result;
356
779
  }
357
780
  async secretType(input, ctx) {
358
- return this.#secret((manager) => manager.secretType(input, ctx), ctx);
781
+ const manager = await this.#secretRoute(ctx);
782
+ const result = await manager.secretType(input, ctx);
783
+ const card = result?.needsOwner;
784
+ if (card)
785
+ this.#ask(ctx, card);
786
+ return result;
359
787
  }
360
- async control(action, sessionId) {
361
- if (this.#changing)
362
- throw new Error('Wait for the settings change to finish.');
363
- await this.#manager.control(action, sessionId);
364
- return this.status();
788
+ /**
789
+ * The owner spoke or tapped in a conversation. Every page there gets a
790
+ * fresh budget and its card is answered: Look / Take over hands the page
791
+ * over, Use my Chrome pins the conversation to it, Resume lifts the Stop.
792
+ */
793
+ async touch(input) {
794
+ const text = input.text ?? '';
795
+ let answered;
796
+ const stopCard = this.#stopCards.get(input.conversationId);
797
+ if (stopCard) {
798
+ const answer = cardAnswer(stopCard, text);
799
+ if (answer)
800
+ this.#stopCards.delete(input.conversationId);
801
+ if (answer === 'resume') {
802
+ await this.control('resume');
803
+ answered = 'resume';
804
+ }
805
+ }
806
+ for (const route of ROUTES) {
807
+ for (const { child, card } of this.#managers[route].renew(input.conversationId, input.agentId)) {
808
+ if (!card)
809
+ continue;
810
+ const answer = cardAnswer(card, text);
811
+ if (answer === 'takeover') {
812
+ const id = child.status().session?.id;
813
+ if (id) {
814
+ await this.control('takeover', id).catch(() => undefined);
815
+ answered = 'takeover';
816
+ }
817
+ }
818
+ else if (answer === 'chrome') {
819
+ this.#pins.set(input.conversationId, 'chrome');
820
+ this.#later(this.#savePins());
821
+ const session = child.status().session;
822
+ const last = child.lastUrl;
823
+ if (session && route !== 'chrome') {
824
+ await this.#managers[route].release(input.conversationId, session.agentId);
825
+ for (const [key] of this.#current)
826
+ if (key.endsWith(JSON.stringify(input.conversationId) + ']'))
827
+ this.#current.delete(key);
828
+ if (last)
829
+ this.#managers.chrome.remember(session.agentId, input.conversationId, last);
830
+ }
831
+ answered = 'chrome';
832
+ }
833
+ else if (answer)
834
+ answered = answer;
835
+ }
836
+ }
837
+ return answered ? { answered } : {};
365
838
  }
366
- async configure(input) {
367
- const next = settingsSchema.parse(input);
368
- if (next.mode === 'computer' && !this.#macOS)
369
- throw new Error('Computer control is macOS-only. Choose another mode.');
839
+ /** Writes nobody waits for, finished before shutdown so a closing process loses none. */
840
+ #pending = new Set();
841
+ #later(work) {
842
+ const tracked = work.catch(() => undefined).finally(() => { this.#pending.delete(tracked); });
843
+ this.#pending.add(tracked);
844
+ }
845
+ async #savePins() { await this.#writeJson('pins.json', Object.fromEntries(this.#pins)).catch(() => undefined); }
846
+ /** Pin a conversation to a route (`/use browser:chrome`), or clear it with `auto`. */
847
+ async pin(conversationId, pin) {
848
+ if (!PIN_VALUES.includes(pin))
849
+ throw new Error(`A pin is one of ${PIN_VALUES.join(', ')}.`);
850
+ if (pin === 'auto')
851
+ this.#pins.delete(conversationId);
852
+ else
853
+ this.#pins.set(conversationId, pin);
854
+ await this.#savePins();
855
+ return this.status({ conversationId });
856
+ }
857
+ async control(action, sessionId, options = {}) {
370
858
  if (!this.#enabled)
371
- throw new Error('Host control is unavailable. Start buddi serve.');
372
- if (this.#changing)
373
- throw new Error('Settings are already changing.');
374
- const current = this.#manager.status();
375
- if (current.busy || current.sessions?.length)
376
- throw new Error('Release all active sessions before changing control settings.');
377
- this.#changing = true;
378
- try {
379
- await mkdir(this.dir, { recursive: true, mode: 0o700 });
380
- const file = path.join(this.dir, 'settings.json');
381
- const temp = `${file}.${randomUUID()}.tmp`;
382
- await writeFile(temp, JSON.stringify(next), { mode: 0o600 });
383
- await rename(temp, file);
384
- for (const record of this.#requests.values())
385
- record.revoked = true;
386
- await this.#manager.shutdown();
387
- this.#settings = next;
388
- this.#manager = this.#create();
389
- await this.#manager.enable();
859
+ throw new Error('The host browser service is unavailable.');
860
+ if (!sessionId && action === 'stop') {
861
+ // Stop agents' browsing: every page closes, and it expires (an hour by default) unless "until I say".
862
+ const minutes = options.forever ? 0 : this.#settings.stopExpiryMinutes;
863
+ const at = this.#now();
864
+ this.#stop = { at, ...(minutes > 0 ? { until: at + minutes * 60_000 } : {}) };
865
+ await this.#writeJson('control.json', { stopped: true, at, until: this.#stop.until ?? null });
866
+ await Promise.all(ROUTES.map((route) => this.#managers[route].control('stop')));
867
+ this.#current.clear();
390
868
  return this.status();
391
869
  }
392
- finally {
393
- this.#changing = false;
870
+ if (!sessionId && action === 'resume') {
871
+ this.#stop = undefined;
872
+ this.#stopCards.clear();
873
+ await this.#writeJson('control.json', { stopped: false });
874
+ return this.status();
394
875
  }
395
- }
396
- async checkPermissions(prompt = false) {
397
- if (this.#changing || this.#manager.status().busy || this.#manager.status().sessions?.length)
398
- throw new Error('Release computer/browser sessions before checking permissions.');
399
- this.#changing = true;
400
- try {
401
- if (!this.#macOS)
402
- this.#permissions = { supported: false, accessibility: false, screenRecording: false, message: 'Computer mode requires macOS 14+. Browser automation remains an explicit alternative.' };
403
- // No helper on disk: a fact the "Use my apps" card already shows, not a failure to shout about.
404
- else if (!this.options.bridge && !(this.options.helperPresent ?? computerHelperPresent)())
405
- this.#permissions = { supported: false, accessibility: false, screenRecording: false, message: COMPUTER_HELPER_MISSING };
406
- else {
407
- const bridge = this.options.bridge?.() ?? new NativeComputerBridge();
408
- const result = await bridge.run({ operation: 'permissions', prompt });
409
- this.#permissions = { supported: result.supported === true, accessibility: result.accessibility === true, screenRecording: result.screenRecording === true };
876
+ if (!sessionId) {
877
+ const pages = ROUTES.flatMap((route) => this.#managers[route].pages());
878
+ if (pages.length === 0 && action === 'release')
879
+ return this.status();
880
+ throw new Error('Select a page before using this control.');
881
+ }
882
+ const found = this.#pageOf({ sessionId });
883
+ if (!found)
884
+ throw new Error('That page changed. Refresh before controlling it.');
885
+ if (action === 'takeover') {
886
+ // One page in the owner's hands at a time.
887
+ const held = ROUTES.flatMap((route) => this.#managers[route].pages()).find((page) => page.status().state === 'paused' && page.status().session?.id !== sessionId);
888
+ if (held)
889
+ throw new Error('You already have a page in your hands. Give it back first.');
890
+ }
891
+ const before = found.manager.status({ sessionId });
892
+ await found.manager.control(action, sessionId);
893
+ // Given back: the run that waited on the owner carries on (a parked mission, a held conversation).
894
+ if (action === 'resume' && before.state === 'paused' && before.session) {
895
+ const info = { sessionId, agentId: before.session.agentId, conversationId: before.session.conversationId };
896
+ for (const listener of this.#giveBack) {
897
+ try {
898
+ listener(info);
899
+ }
900
+ catch { /* a listener never fails the give-back */ }
410
901
  }
411
- return this.status();
412
902
  }
413
- finally {
414
- this.#changing = false;
903
+ // The page asked about, not whichever page changed last.
904
+ return this.status({ sessionId });
905
+ }
906
+ /** Hear every give-back of a page the owner held. Returns the unsubscribe. */
907
+ onGiveBack(listener) {
908
+ this.#giveBack.add(listener);
909
+ return () => { this.#giveBack.delete(listener); };
910
+ }
911
+ /**
912
+ * Change what agents may use. No lock: a page already open keeps working,
913
+ * and turning a route off closes its pages.
914
+ */
915
+ async configure(input) {
916
+ if (!this.#enabled)
917
+ throw new Error('Host control is unavailable. Start buddi serve.');
918
+ // Removing a sign-in site removes it wherever it is kept: the owner's list and the sites buddi learned.
919
+ let change = input;
920
+ if (change && typeof change === 'object' && !Array.isArray(change) && 'forgetSignInSite' in change) {
921
+ const { forgetSignInSite, ...rest } = change;
922
+ if (typeof forgetSignInSite !== 'string' || forgetSignInSite.trim() === '')
923
+ throw new Error('forgetSignInSite is a site, like amazon.com.');
924
+ const site = forgetSignInSite.trim().toLowerCase();
925
+ if (this.#learned.delete(site))
926
+ await this.#saveLearned();
927
+ const listed = Array.isArray(rest.signInSites) ? rest.signInSites : this.#settings.signInSites;
928
+ change = { ...rest, signInSites: listed.filter((entry) => entry !== site) };
415
929
  }
930
+ const next = applySettingsChange(this.#settings, change);
931
+ if (next.yourApps !== 'off' && this.#settings.yourApps === 'off' && !this.#pluginApps() && !this.options.drivers?.apps)
932
+ throw new Error('Your apps need the Computer plugin. Install it from Settings → Plugins first.');
933
+ const chromeOff = this.#settings.yourChrome && !next.yourChrome;
934
+ const appsOff = this.#settings.yourApps !== 'off' && next.yourApps === 'off';
935
+ await this.#writeSettings(next);
936
+ if (chromeOff)
937
+ await this.#managers.chrome.control('stop');
938
+ if (appsOff)
939
+ await this.#managers.apps.control('stop');
940
+ for (const [key, route] of this.#current)
941
+ if ((chromeOff && route === 'chrome') || (appsOff && route === 'apps'))
942
+ this.#current.delete(key);
943
+ return this.status();
944
+ }
945
+ async shutdown() {
946
+ this.#enabled = false;
947
+ await Promise.all(ROUTES.map((route) => this.#managers[route].shutdown()));
948
+ await Promise.all([...this.#pending]);
416
949
  }
417
- async shutdown() { this.#enabled = false; await this.#manager.shutdown(); }
418
950
  }
419
951
  //# sourceMappingURL=controller.js.map