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

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