@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,51 +1,55 @@
1
1
  import { randomUUID } from 'node:crypto';
2
- import { mkdir, readFile, writeFile, rename } from 'node:fs/promises';
3
- import path from 'node:path';
4
2
  import { FORM_KIND, NATIVE_KIND, fieldBoundTo, secretKindFor, takeDelivered } from './secrets.js';
5
- import { APP_BEHIND, BrowserPreconditionError, UNTRUSTED, observedLine } from './types.js';
3
+ import { LOGIN_GONE, LOGIN_GRACE_MS, APP_BEHIND, BrowserOpenedError, BrowserPreconditionError, UNTRUSTED, observedLine } from './types.js';
4
+ import { ownerCard, siteOf } from './routes.js';
5
+ import { missionMark } from './telemetry.js';
6
6
  /**
7
- * "The owner stopped the browser", said where the owner can undo it.
8
- *
9
- * The *fact* is one sentence; the way back differs by surface, and the surface
10
- * is already on the tool context (`ctx.surface`), so the plugin says it rather
11
- * than leaving a relay to guess. On Telegram the way back is a command in the
12
- * same chat; everywhere else it is the dashboard's own Settings page, which is
13
- * where the Stop button lives.
7
+ * Said when the owner has stopped agents' browsing. On Telegram the way back
8
+ * is a command in the same chat; everywhere else the Resume card in the chat
9
+ * itself, or Settings.
14
10
  */
15
- /** Said when control paused: the tab or window is gone, or the page kept failing to answer. The way back depends on where the owner is. */
11
+ export function browserStoppedMessage(surface) {
12
+ return surface?.id === 'telegram'
13
+ ? 'The owner stopped agents\' browsing. Tap Resume on the card, or send /browser resume here.'
14
+ : 'The owner stopped agents\' browsing. Tap Resume on the card in this chat to let agents look again.';
15
+ }
16
+ /** Kept for the surfaces that still name it: the owner has the page in their hands. */
16
17
  export function browserPausedMessage(surface) {
17
18
  return surface?.id === 'telegram'
18
- ? 'Control is paused: the page closed or stopped answering. Send /browser resume here, then ask again for a fresh look.'
19
- : 'Control is paused. Ask the owner to inspect the selected app/window and the reported cause, then use Resume access and ask for a fresh observation.';
19
+ ? 'You have the page. Give it back from the dashboard, or send /browser resume here.'
20
+ : 'You have the page. Give it back when you are done and the agent carries on.';
20
21
  }
21
- /**
22
- * Said when an observation did not answer and control stays with the agent.
23
- * A slow page is something the model can wait out itself, so there is nothing
24
- * for the owner to do and the wording is the same on every surface.
25
- */
22
+ /** A page that did not answer after every retry: said once, never as an instruction to retry. */
26
23
  export function browserWaitMessage(_surface) {
27
- return 'The page has not answered yet. Wait a few seconds and observe again.';
24
+ return 'The page did not answer after several tries.';
28
25
  }
29
- /** An observation failure that no waiting fixes: the tab or window it was reading is gone. */
30
- const SCREEN_GONE = /\b(tab|window)\b[^.]*\b(closed|gone)\b|has been closed|target closed/i;
31
- /** A gone tab the driver can replace by itself ("observe again to continue in a new one") is not a screen lost. */
32
- const SCREEN_REPLACEABLE = /observe again to continue in a new one/i;
33
- /** The extension's refusal to act in the tab the owner is viewing (extension commands.ts, `WATCHED`). */
26
+ /** The extension's last word after waiting for the owner to leave their tab (extension commands.ts, `WATCHED`). */
34
27
  const OWNER_WATCHING = /You are looking at this tab/i;
35
- /** What the model is told instead: one ask of the owner, not a retry. */
36
- export const OWNER_WATCHING_MESSAGE = 'The owner is looking at that tab. Ask them to switch to another tab or window, then try once more.';
37
- /** Consecutive observation failures on one session before control pauses. */
38
- const MAX_OBSERVATION_FAILURES = 3;
39
- export function browserStoppedMessage(surface) {
40
- return surface?.id === 'telegram'
41
- ? 'The owner stopped the browser. Only the owner can enable it again — send /browser resume here.'
42
- : 'The owner stopped the browser. Only the owner can enable it again in the dashboard, on the Settings page.';
43
- }
44
- /** Already classified: do not retry observation or overwrite the paused state. */
45
- class ObservationFailure extends Error {
28
+ /** What the agent is told instead: no ask, no retry loop; the bar in the tab already asks the owner. */
29
+ export const OWNER_WATCHING_MESSAGE = 'The owner is looking at that tab, and the bar in it asks them whether you may carry on there. Nothing was done. Work on something else for a moment, then try again.';
30
+ /** An observation failure no waiting fixes: the tab or window it was reading is gone. */
31
+ const SCREEN_GONE = /\b(tab|window)\b[^.]*\b(closed|gone)\b|has been closed|target closed/i;
32
+ /** The waits before each re-read when the page gave no answer: 0.5, 1, 2, 4 and 8 seconds (six attempts in all). */
33
+ export const RETRY_DELAYS_MS = [500, 1_000, 2_000, 4_000, 8_000];
34
+ /** Targeting refusals in a row before the task asks the owner whether to keep going. */
35
+ export const MAX_TARGETING_FAILURES = 8;
36
+ /** The task's budget: actions and minutes, renewed by any owner touch in the conversation. */
37
+ export const DEFAULT_MAX_STEPS = 200;
38
+ export const DEFAULT_LIFETIME_MS = 60 * 60_000;
39
+ /** How long a run stays parked on its page waiting for the owner's card. */
40
+ export const PARK_MS = 60 * 60_000;
41
+ /** A route by the mode name the dashboard and Telegram already know. */
42
+ export function modeOf(route) {
43
+ return route === 'chrome' ? 'extension' : route === 'apps' ? 'computer' : 'playwright';
46
44
  }
47
- /** One host controller shared by all registry instances/surfaces in serve.
48
- * CLI processes are deliberately unavailable, not a second browser owner. */
45
+ /**
46
+ * One conversation's page on one route.
47
+ *
48
+ * Every action returns the page as it is afterwards. Refusals that used to
49
+ * stop the task are retried here (a slow page, a stale ref, a redirect) or
50
+ * become one card the owner answers (an input that may not have landed, the
51
+ * budget). Only the owner's own take-over pauses a page.
52
+ */
49
53
  export class BrowserService {
50
54
  driver;
51
55
  options;
@@ -55,81 +59,112 @@ export class BrowserService {
55
59
  #observation;
56
60
  #picture;
57
61
  #busy = false;
58
- /**
59
- * The screen this session had is gone.
60
- *
61
- * Set when a take-over had to close the driver to end the action in flight,
62
- * and cleared by resume. Belt to `handReady`'s braces: a hand offered over
63
- * nothing is a live view that never paints its first frame, and the owner
64
- * has no way to tell that from a slow link.
65
- */
66
62
  #handless = false;
63
+ /** The owner holds the page in place (their Chrome brought it forward): no frames, no hand. */
64
+ #held = false;
65
+ /** The page the owner last held in place, and until when a Save they tapped there still counts (the driver's grace). */
66
+ #lastHeld;
67
+ /** Who waits for the action in flight to settle (a Give it back pressed while it stops). */
68
+ #settleWaiters = [];
67
69
  #controller;
68
70
  #expiry;
69
71
  #lastAction;
70
72
  #message;
71
- #preconditionFailures = 0;
72
- #observationFailures = 0;
73
- #needsObservation = false;
74
- #spent = new Set();
73
+ #targetingFailures = 0;
74
+ #card;
75
+ /** Where the page last was, so a closed tab or a new request re-opens it rather than stopping. */
76
+ #lastUrl;
77
+ #lastActivity = 0;
78
+ #tail = Promise.resolve();
75
79
  #controlTail = Promise.resolve();
76
- #diskTail = Promise.resolve();
77
80
  constructor(driver, options = {}) {
78
81
  this.driver = driver;
79
82
  this.options = options;
80
83
  }
81
84
  #now() { return this.options.now?.() ?? Date.now(); }
82
- /** When buddi took this observation, so the model can tell the newest from an older one. */
83
- #stamp(observation) {
84
- return { ...observation, observedAt: new Date(this.#now()).toISOString() };
85
+ get #route() { return this.options.route ?? (this.options.allowOpen ? 'apps' : 'own'); }
86
+ #sleep(ms) { return this.options.sleep ? this.options.sleep(ms) : new Promise((resolve) => setTimeout(resolve, ms)); }
87
+ #stamp(observation) { return { ...observation, observedAt: new Date(this.#now()).toISOString() }; }
88
+ #stop(cause, ctx, recovered) {
89
+ this.options.telemetry?.stop(cause, { route: this.#route, ...(ctx?.agentId ? { agent: ctx.agentId } : {}), ...(ctx?.surface?.id ? { surface: ctx.surface.id } : {}), ...missionMark(ctx),
90
+ ...(siteOf(this.#observation?.url ?? this.#lastUrl) ? { host: siteOf(this.#observation?.url ?? this.#lastUrl) } : {}), ...(recovered ? { recovered } : {}) });
85
91
  }
86
92
  async enable() {
87
93
  if (this.#enabled)
88
94
  return;
89
- if (this.options.controlFile) {
90
- try {
91
- const state = JSON.parse(await readFile(this.options.controlFile, 'utf8'));
92
- this.#state = state.stopped ? 'stopped' : 'idle';
93
- }
94
- catch (error) {
95
- if (error.code !== 'ENOENT')
96
- throw error;
97
- this.#state = 'idle';
98
- }
99
- }
100
- else
101
- this.#state = 'idle';
95
+ // Take over pressed in the page's own bar is the Canvas button.
96
+ this.driver.onOwnerTakeover?.(() => {
97
+ const id = this.#session?.id;
98
+ if (!id)
99
+ return;
100
+ if (this.options.requestTakeover)
101
+ this.options.requestTakeover(id);
102
+ else
103
+ void this.control('takeover').catch(() => undefined);
104
+ });
105
+ // Give it back pressed in the held tab's bar is the Canvas's Give it back.
106
+ this.driver.onOwnerGiveBack?.(() => {
107
+ const id = this.#session?.id;
108
+ if (!id || this.#state !== 'paused')
109
+ return;
110
+ if (this.options.requestResume)
111
+ this.options.requestResume(id);
112
+ else
113
+ void this.control('resume').catch(() => undefined);
114
+ });
115
+ // A sign-in the owner made on the page they hold: the keeper asks them, never a model.
116
+ // A Save the owner tapped in their Chrome a beat after Give it back still counts, for the page they held, within the driver's grace.
117
+ this.driver.onLoginSeen?.((login) => {
118
+ const live = this.#state === 'paused' ? this.#session?.id : undefined;
119
+ if (login.decision === 'check' && !live)
120
+ return Promise.resolve({ ask: 'none' });
121
+ const recent = !live && login.decision && this.#lastHeld && this.#now() < this.#lastHeld.until ? this.#lastHeld.id : undefined;
122
+ const id = live ?? recent;
123
+ if (!id)
124
+ return login.decision ? Promise.resolve({ saved: false, reason: LOGIN_GONE }) : undefined;
125
+ return this.options.loginSeen?.(id, login);
126
+ });
127
+ this.#state = 'idle';
102
128
  this.#enabled = true;
103
129
  }
104
130
  status(_scope) {
105
131
  const { tree: _tree, targets: _targets, ...page } = this.#observation ?? {};
106
- const { ownerId: _owner, ...session } = this.#session ?? {};
132
+ const session = this.#session ? (({ ownerId: _o, startedAt: _s, actions: _a, cards: _c, ...rest }) => rest)(this.#session) : undefined;
107
133
  return { state: this.#state, enabled: this.#enabled, busy: this.#busy,
108
- ...(this.#session ? { session: session } : {}),
134
+ ...(session ? { session: { ...session, route: this.#route }, route: this.#route, mode: modeOf(this.#route) } : {}),
109
135
  ...(this.#observation ? { page: page } : {}),
136
+ ...(this.#card ? { needsOwner: this.#card } : {}),
137
+ ...(this.#state === 'paused' && this.#held && this.driver.holdsInPlace ? { held: { by: 'owner', where: this.driver.holdsInPlace } } : {}),
110
138
  lastAction: this.#lastAction, message: this.#message, hasScreenshot: !!this.#picture };
111
139
  }
112
140
  screenshot(_sessionId) { return this.#picture; }
141
+ /** The card this page waits on, if any. */
142
+ get card() { return this.#card; }
143
+ /** Where this page is, or was. */
144
+ get lastUrl() { return this.#observation?.url ?? this.#lastUrl; }
145
+ /** The latest page, with its tree: what the route's post-processing reads. */
146
+ get observation() { return this.#observation; }
147
+ get busy() { return this.#busy; }
148
+ /** Where this conversation's page was before it was let go, so the next action opens it again there. */
149
+ seed(url) { this.#lastUrl ??= url; }
150
+ /** No action for this long: a page a waiting conversation may take over. */
151
+ idleFor() { return this.#busy || this.#state === 'paused' || this.#card ? 0 : this.#now() - this.#lastActivity; }
113
152
  /**
114
- * The remote hand, and only while the owner holds this screen.
115
- *
116
- * Paused is the take-over state, so it is also the only state in which a
117
- * dashboard may drive: an agent mid-action and a hand on the same page would
118
- * be two drivers, and the evidence rules here assume exactly one.
153
+ * The remote hand, and only while the owner holds this screen. Paused is the
154
+ * take-over state, the only one in which a dashboard may drive.
119
155
  */
120
156
  hand(_scope) {
157
+ if (this.#held && this.#state === 'paused')
158
+ return { supported: false, message: 'The page is in front of you in your Chrome.' };
121
159
  if (this.driver.supportsHand === false || !this.driver.hand) {
122
- return { supported: false, message: this.driver.handMessage ?? 'Take over at the computer for this mode.' };
160
+ return { supported: false, message: this.driver.handMessage ?? 'Take over at the computer for this route.' };
123
161
  }
124
162
  if (!this.#session)
125
- return { supported: true, message: 'No agent is driving this screen.' };
163
+ return { supported: true, message: 'No agent is looking at this page.' };
126
164
  if (this.#state !== 'paused')
127
165
  return { supported: true, message: 'Take over first, then you can drive.' };
128
- // Paused is not the same as paintable. A take-over that interrupted an
129
- // action closed the screen that action was on, and a hand offered over
130
- // nothing is a live view that never draws its first frame.
131
166
  if (this.#handless || this.driver.handReady?.() === false) {
132
- return { supported: true, message: this.#message ?? 'There is no screen to drive. Resume and ask the agent to open the page again.' };
167
+ return { supported: true, message: this.#message ?? 'There is no screen to drive. Give it back and the agent opens the page again.' };
133
168
  }
134
169
  return { supported: true, hand: this.driver.hand };
135
170
  }
@@ -138,120 +173,195 @@ export class BrowserService {
138
173
  if (!session || session.ownerId !== input.ownerId || session.agentId !== input.agentId || session.conversationId !== input.previousConversationId)
139
174
  return false;
140
175
  if (!this.#enabled || this.#busy || !['running', 'paused'].includes(this.#state))
141
- throw new Error('Wait for computer/browser control to settle before continuing the conversation.');
142
- if (Date.parse(session.expiresAt) <= this.#now())
143
- return false;
144
- this.#spent.add(session.requestId);
176
+ throw new Error('Wait for the page to settle before continuing the conversation.');
145
177
  session.conversationId = input.conversationId;
146
178
  this.#observation = undefined;
147
179
  this.#picture = undefined;
148
- this.#needsObservation = true;
149
- this.#message = 'Task continued after conversation rollover. Observe the current page before acting. Human takeover, if active, still requires owner resume.';
180
+ this.#message = 'Task continued after conversation rollover. The next action returns the current page.';
150
181
  return true;
151
182
  }
152
- async execute(command, ctx) {
183
+ /**
184
+ * Put the page on a card and wait for the owner. The run stops (the tool's
185
+ * result carries the card) and the page stays open for at least an hour.
186
+ */
187
+ park(kind, facts = {}) {
188
+ const card = ownerCard(kind, { site: siteOf(this.lastUrl), ...facts });
189
+ this.#card = card;
190
+ if (this.#session)
191
+ this.#session.cards++;
192
+ this.#schedule(Math.max(Date.parse(this.#session?.expiresAt ?? '') || 0, this.#now()) + Math.max(this.options.parkMs ?? PARK_MS, PARK_MS) - this.#now());
193
+ return card;
194
+ }
195
+ #cardResult(card, dispatched, message) {
196
+ return { completed: false, dispatched, needsOwner: card, notice: UNTRUSTED,
197
+ message: message ?? `Waiting for the owner: "${card.title}" Say that in one sentence and stop; the card in the chat has the buttons. The page stays open; you continue when they answer.`,
198
+ ...(this.#observation ? { observation: this.#observation } : {}) };
199
+ }
200
+ /**
201
+ * The owner spoke or tapped in this conversation: the budget renews (200
202
+ * actions, an hour) and a waiting card is cleared. Returns the card it
203
+ * cleared, so the caller can act on the answer (take over, use Chrome).
204
+ */
205
+ renew() {
206
+ const card = this.#card;
207
+ this.#card = undefined;
208
+ this.#targetingFailures = 0;
209
+ if (this.#session) {
210
+ this.#session.steps = 0;
211
+ this.#session.maxSteps = this.options.maxSteps ?? DEFAULT_MAX_STEPS;
212
+ const expiresAt = this.#now() + (this.options.lifetimeMs ?? DEFAULT_LIFETIME_MS);
213
+ this.#session.expiresAt = new Date(expiresAt).toISOString();
214
+ this.#schedule(expiresAt - this.#now() + Math.max(this.options.parkMs ?? PARK_MS, PARK_MS));
215
+ }
216
+ return card;
217
+ }
218
+ #schedule(ms) {
219
+ clearTimeout(this.#expiry);
220
+ this.#expiry = setTimeout(() => { void this.#release('expired'); }, Math.max(1, ms));
221
+ this.#expiry.unref?.();
222
+ }
223
+ #open(request, ctx) {
224
+ const lifetime = this.options.lifetimeMs ?? DEFAULT_LIFETIME_MS;
225
+ if (!this.#session) {
226
+ const expiresAt = this.#now() + lifetime;
227
+ this.#session = { id: randomUUID(), ownerId: ctx.buddi.owner.id, agentId: ctx.agentId, conversationId: ctx.conversationId,
228
+ requestId: request?.id ?? 'unattended', task: (request?.text ?? 'An unattended task').slice(0, 4000),
229
+ expiresAt: new Date(expiresAt).toISOString(), steps: 0, maxSteps: this.options.maxSteps ?? DEFAULT_MAX_STEPS,
230
+ startedAt: this.#now(), actions: 0, cards: 0 };
231
+ this.#schedule(lifetime + Math.max(this.options.parkMs ?? PARK_MS, PARK_MS));
232
+ return;
233
+ }
234
+ // A new owner message is an owner touch: the same page, a fresh budget.
235
+ if (request && this.#session.requestId !== request.id) {
236
+ this.#session.requestId = request.id;
237
+ this.#session.task = request.text.slice(0, 4000);
238
+ this.renew();
239
+ }
240
+ }
241
+ /** One action at a time per page: a second call waits for the first rather than being refused. */
242
+ #serial(run) {
243
+ const next = this.#tail.then(run, run);
244
+ this.#tail = next.catch(() => { });
245
+ return next;
246
+ }
247
+ execute(command, ctx) {
248
+ return this.#serial(() => this.#execute(command, ctx));
249
+ }
250
+ async #execute(command, ctx) {
153
251
  ctx.signal?.throwIfAborted();
154
252
  const request = ctx.ownerRequest;
155
- if (!request || !request.id || !request.text.trim() || request.expiresAt <= this.#now() ||
156
- !ctx.agentId || !ctx.conversationId || (ctx.delegationDepth ?? 0) > 0) {
157
- throw new Error('A current authenticated owner request is required.');
158
- }
253
+ if (!ctx.agentId || !ctx.conversationId)
254
+ throw new Error('A browser action belongs to an agent and a conversation.');
159
255
  if (!this.#enabled)
160
256
  throw new Error('Browser driving is available through buddi serve (dashboard or Telegram), not a separate CLI process.');
161
257
  if (this.#state === 'stopped')
162
258
  throw new Error(browserStoppedMessage(ctx.surface));
163
- if (this.#busy)
164
- throw new Error('Browser is busy; overlapping actions are refused.');
165
259
  if (this.#session && (this.#session.ownerId !== ctx.buddi.owner.id || this.#session.agentId !== ctx.agentId || this.#session.conversationId !== ctx.conversationId)) {
166
- throw new Error('Another agent/conversation owns the browser. Ask the owner to release it from the dashboard.');
260
+ throw new Error('Another conversation owns this page.');
167
261
  }
168
- if (this.#spent.has(request.id))
169
- throw new Error('This browser request has ended. A new owner message is required.');
170
262
  if (command.action === 'close') {
171
- this.#spent.add(request.id);
172
263
  await this.#release('idle');
173
264
  return { closed: true, notice: UNTRUSTED };
174
265
  }
175
- if (this.#state === 'paused')
176
- throw new Error('Browser is under human control or needs inspection. Wait for the owner to resume in the dashboard, then observe.');
177
- // Computer mode's open only brings an app forward, then observes: nothing earlier is replayed.
178
- // navigate still waits for a fresh look, since it loads a page.
179
- const reopens = this.options.allowOpen === true && command.action === 'open';
180
- if (this.#needsObservation && command.action !== 'observe' && !reopens)
181
- throw new Error('A fresh observation is required: observe the current page before acting. Do not replay an earlier action.');
182
- if (!this.#session || this.#session.requestId !== request.id) {
183
- if (!this.#session && command.action !== 'navigate' && !(this.options.allowOpen && command.action === 'open'))
184
- throw new Error('Start with navigate, or open an allowed application in computer mode.');
185
- this.#rekey(request, ctx.agentId, ctx.conversationId, ctx.buddi.owner.id);
266
+ if (this.#state === 'paused') {
267
+ throw new Error('The owner has this page in their hands. Wait for them to give it back; you continue when they do.');
268
+ }
269
+ // Parked on a card: nothing is done until the owner answers it.
270
+ if (this.#card) {
271
+ this.#open(request, ctx);
272
+ if (this.#card)
273
+ return this.#cardResult(this.#card, false);
274
+ }
275
+ let run = command;
276
+ let reopened = false;
277
+ if (!this.#session && command.action !== 'navigate' && command.action !== 'open') {
278
+ // No page yet, or the last one was let go: open it again where it was.
279
+ if (!this.#lastUrl || this.#route === 'apps') {
280
+ this.#stop('start-with-navigate', ctx);
281
+ return { completed: false, dispatched: false, notice: UNTRUSTED, message: 'No page is open in this conversation yet. Navigate to the website first.' };
282
+ }
283
+ this.#stop('request-ended', ctx);
284
+ run = { action: 'navigate', url: this.#lastUrl };
285
+ reopened = true;
186
286
  }
287
+ this.#open(request, ctx);
187
288
  const active = this.#session;
188
- if (!active || Date.parse(active.expiresAt) <= this.#now() || active.steps >= active.maxSteps) {
189
- await this.#release('expired');
190
- throw new Error('Browser task reached its time or step limit. Ask the owner for a new request.');
289
+ if (active.steps >= active.maxSteps || Date.parse(active.expiresAt) <= this.#now()) {
290
+ this.#stop('budget', ctx);
291
+ return this.#cardResult(this.park('budget'), false);
292
+ }
293
+ // The observation is the latest one unless the agent named another.
294
+ if (['click', 'fill', 'select', 'press', 'scroll'].includes(run.action) && run.observation === undefined && this.#observation) {
295
+ run = { ...run, observation: this.#observation.id };
191
296
  }
192
297
  ++active.steps;
298
+ ++active.actions;
193
299
  this.#busy = true;
194
- this.#lastAction = command.action; // Never record form values here.
300
+ this.#lastAction = run.action; // Never record form values here.
301
+ this.#lastActivity = this.#now();
195
302
  this.#message = undefined;
196
303
  const controller = new AbortController();
197
304
  this.#controller = controller;
198
305
  const cancel = () => {
199
306
  controller.abort(ctx.signal?.reason ?? new Error('Browser action stopped.'));
200
- this.#spent.add(request.id);
201
- void this.#release('stopped');
202
- void this.#persistStop(true).catch(() => { });
307
+ void this.#release('idle');
203
308
  };
204
309
  ctx.signal?.addEventListener('abort', cancel, { once: true });
205
310
  try {
206
311
  this.#state = 'starting';
207
312
  await this.driver.start();
208
313
  controller.signal.throwIfAborted();
209
- ctx.signal?.throwIfAborted();
210
314
  this.#state = 'running';
211
- await this.driver.perform(command);
212
- if (command.action !== 'observe')
213
- this.#preconditionFailures = 0;
315
+ await this.driver.perform(run);
316
+ const note = this.driver.takeNote?.();
317
+ if (note)
318
+ this.#message = note;
319
+ if (run.action !== 'observe')
320
+ this.#targetingFailures = 0;
214
321
  controller.signal.throwIfAborted();
215
- // Once input succeeds, observation loss must not invite replaying it.
216
- // For an observe-only command, however, observation IS the whole action.
217
- try {
218
- const observation = await this.driver.observe();
219
- const picture = await this.driver.screenshot();
220
- controller.signal.throwIfAborted();
221
- this.#observation = this.#stamp(observation);
222
- this.#picture = picture;
223
- this.#needsObservation = false;
224
- this.#observationFailures = 0;
322
+ const seen = await this.#look(controller, ctx);
323
+ if (!seen) {
324
+ // Six reads over fifteen seconds and nothing: one card, not a loop.
325
+ this.#stop('observation-failures', ctx, 'card');
326
+ return this.#cardResult(this.park('uncertain'), run.action !== 'observe');
225
327
  }
226
- catch (error) {
227
- controller.signal.throwIfAborted();
228
- const cause = error instanceof Error ? error.message : String(error);
229
- const paused = this.#observationFailed(cause);
230
- // The extension's final error already says to wait and observe again; do not say it twice.
231
- // The app pushed behind already says how to bring it back.
232
- const recovery = paused ? browserPausedMessage(ctx.surface) : APP_BEHIND.test(cause) || /observe again\.?$/i.test(cause.trim()) ? '' : browserWaitMessage(ctx.surface);
233
- this.#message = `${command.action === 'observe' ? 'Observation failed' : 'Action completed, but observation failed'}: ${cause.replace(/\.$/, '')}.${recovery ? ` ${recovery}` : ''}${command.action === 'observe' ? '' : ' Do not repeat the action; its effect may already have happened.'}`;
234
- const result = { completed: command.action !== 'observe', observed: false, error: cause,
235
- state: this.#state, recovery, message: this.#message, notice: UNTRUSTED };
236
- if (command.action === 'observe')
237
- throw new ObservationFailure(JSON.stringify(result));
238
- return result;
239
- }
240
- controller.signal.throwIfAborted();
241
328
  const observed = observedLine(this.#observation.observedAt);
329
+ if (reopened) {
330
+ const asked = command.action;
331
+ return { completed: false, dispatched: false, notice: UNTRUSTED, observation: this.#observation,
332
+ message: `${observed} No page was open, so I opened ${siteOf(this.#lastUrl) ?? 'the last page'} again. Nothing else was done; ${asked === 'observe' ? 'here it is' : 'act on this page now'}.` };
333
+ }
242
334
  return { completed: true, notice: UNTRUSTED, observation: this.#observation, message: this.#message ? `${observed} ${this.#message}` : observed };
243
335
  }
244
336
  catch (error) {
245
- if (error instanceof ObservationFailure)
337
+ if (controller.signal.aborted)
246
338
  throw error;
247
- if (!controller.signal.aborted && error instanceof BrowserPreconditionError) {
248
- await this.#precondition(controller, error);
339
+ const message = error instanceof Error ? error.message : String(error);
340
+ if (error instanceof BrowserPreconditionError)
341
+ return await this.#precondition(controller, error, ctx);
342
+ this.#state = 'running';
343
+ if (error instanceof BrowserOpenedError) {
344
+ // The page opened and a later step failed: hand back the page, not just the error.
345
+ const site = siteOf(error.page.url) ?? 'the page';
346
+ const failed = message.replace(/\.$/, '');
347
+ if (error.page.url)
348
+ this.#lastUrl = error.page.url;
349
+ const seen = await this.#look(controller, ctx).catch(() => false);
350
+ if (seen) {
351
+ return { completed: false, dispatched: true, notice: UNTRUSTED, observation: this.#observation,
352
+ message: `${observedLine(this.#observation.observedAt)} Opened ${site}, then this failed: ${failed}. Carry on from this page; don't open it again.` };
353
+ }
354
+ this.#message = `Opened ${site} in a tab, then this failed: ${failed}.`;
355
+ throw new Error(this.#message);
249
356
  }
250
- if (!controller.signal.aborted) {
251
- this.#state = error instanceof BrowserPreconditionError ? 'running'
252
- : ['click', 'fill', 'select', 'press'].includes(command.action) ? 'paused' : 'error';
253
- this.#message = `${error instanceof Error ? error.message : String(error)}${this.#state === 'paused' ? ' The action may have partially completed. Inspect it before resuming; do not repeat a submission.' : ''}`;
357
+ if (['click', 'fill', 'select', 'press'].includes(run.action)) {
358
+ // The input may have landed part-way: the owner looks, or tells the agent to judge from the page.
359
+ this.#stop('uncertain-input', ctx, 'card');
360
+ this.#observation = undefined;
361
+ this.#picture = undefined;
362
+ return this.#cardResult(this.park('uncertain'), true, `${message.replace(/\.$/, '')}. I'm not sure that went through. Say so in one sentence and stop; the card asks the owner whether to look.`);
254
363
  }
364
+ this.#message = message;
255
365
  throw error;
256
366
  }
257
367
  finally {
@@ -259,204 +369,177 @@ export class BrowserService {
259
369
  if (this.#controller === controller)
260
370
  this.#controller = undefined;
261
371
  this.#busy = false;
372
+ this.#settled();
262
373
  }
263
374
  }
264
375
  /**
265
- * An observation that did not come back. Usually a page still loading or
266
- * busy, which the agent can wait out and observe again, so control stays
267
- * with it and the next action must be a fresh observation. Control pauses
268
- * only when the tab or window is gone, or on the third failure in a row.
269
- * Returns whether it paused.
376
+ * Read the page, re-reading at 0.5, 1, 2, 4 and 8 seconds when it does not
377
+ * answer. A closed tab is opened again at its last address once. False when
378
+ * all six reads failed. The app pushed behind the owner's window is said
379
+ * straight away: open brings it back and no wait helps.
270
380
  */
271
- #observationFailed(cause) {
272
- this.#observation = undefined;
273
- this.#picture = undefined;
274
- this.#needsObservation = true;
275
- // The owner's window in front of the app is not a failing screen: the agent brings it back with open.
276
- if (APP_BEHIND.test(cause)) {
277
- if (this.#state !== 'paused')
278
- this.#state = 'running';
279
- return false;
381
+ async #look(controller, ctx) {
382
+ const delays = this.options.retryDelays ?? RETRY_DELAYS_MS;
383
+ let reopened = false;
384
+ let counted = false;
385
+ for (let attempt = 0; attempt <= delays.length; attempt++) {
386
+ if (attempt > 0)
387
+ await this.#sleep(delays[attempt - 1]);
388
+ controller.signal.throwIfAborted();
389
+ try {
390
+ const observation = await this.driver.observe();
391
+ const picture = await this.driver.screenshot();
392
+ controller.signal.throwIfAborted();
393
+ this.#observation = this.#stamp(observation);
394
+ this.#picture = picture;
395
+ if (observation.url)
396
+ this.#lastUrl = observation.url;
397
+ return true;
398
+ }
399
+ catch (error) {
400
+ controller.signal.throwIfAborted();
401
+ const cause = error instanceof Error ? error.message : String(error);
402
+ this.#observation = undefined;
403
+ this.#picture = undefined;
404
+ if (APP_BEHIND.test(cause)) {
405
+ this.#stop('app-behind', ctx);
406
+ throw new BrowserPreconditionError(cause);
407
+ }
408
+ if (SCREEN_GONE.test(cause) && !reopened && this.#lastUrl && this.#route !== 'apps') {
409
+ reopened = true;
410
+ this.#stop('screen-gone', ctx);
411
+ try {
412
+ await this.driver.perform({ action: 'navigate', url: this.#lastUrl });
413
+ }
414
+ catch { /* the next read says */ }
415
+ continue;
416
+ }
417
+ if (!counted) {
418
+ counted = true;
419
+ this.#stop('page-not-answered', ctx);
420
+ }
421
+ }
280
422
  }
281
- const paused = ++this.#observationFailures >= MAX_OBSERVATION_FAILURES || (SCREEN_GONE.test(cause) && !SCREEN_REPLACEABLE.test(cause));
282
- this.#state = paused ? 'paused' : 'running';
283
- return paused;
423
+ return false;
284
424
  }
285
425
  /**
286
- * A new owner message continues the session under that message's request:
287
- * the old one is spent, the step budget and the failure count reset, and the
288
- * expiry runs from now. The session id survives, so the conversation still
289
- * owns the same screen it always did.
426
+ * Refused before anything was dispatched: a stale observation, a ref that
427
+ * no longer matches, a page that moved. The tool looks again and answers
428
+ * with the fresh page; nothing pauses. Eight in a row asks the owner
429
+ * whether to keep going. The owner looking at the tab and the app behind
430
+ * their window are said as what they are.
290
431
  */
291
- #rekey(request, agentId, conversationId, ownerId) {
292
- const expiresAt = Math.min(request.expiresAt, this.#now() + (this.options.lifetimeMs ?? 20 * 60_000));
293
- if (this.#session)
294
- this.#spent.add(this.#session.requestId);
295
- this.#preconditionFailures = 0;
296
- this.#session = { id: this.#session?.id ?? randomUUID(), ownerId, agentId,
297
- conversationId, requestId: request.id, task: request.text.slice(0, 4000),
298
- expiresAt: new Date(expiresAt).toISOString(), steps: 0, maxSteps: this.options.maxSteps ?? 80 };
299
- clearTimeout(this.#expiry);
300
- this.#expiry = setTimeout(() => { void this.#release('expired'); }, Math.max(1, expiresAt - this.#now()));
301
- this.#expiry.unref?.();
302
- }
303
- /**
304
- * The precondition path every refused action takes, `browser.act`'s and the
305
- * secret tools' alike: count the failure, pause on the third, and recover
306
- * fresh evidence so the next call acts on what the page now shows rather
307
- * than on the stale arguments. Nothing was dispatched for any of these.
308
- */
309
- async #precondition(controller, error) {
432
+ async #precondition(controller, error, ctx) {
433
+ this.#state = 'running';
310
434
  if (OWNER_WATCHING.test(error.message)) {
311
- // Not a targeting failure and nothing waiting fixes: only the owner
312
- // moving to another tab does. No pause and no count; the next action
313
- // must observe first, so the model asks once instead of retrying.
435
+ this.#stop('owner-watching', ctx);
314
436
  this.#message = OWNER_WATCHING_MESSAGE;
315
- this.#state = 'running';
316
- this.#needsObservation = true;
317
- throw new BrowserPreconditionError(JSON.stringify({ error: OWNER_WATCHING_MESSAGE, dispatched: false,
318
- recovery: 'Ask the owner now and wait for their answer. Do not retry by yourself.' }));
437
+ throw new BrowserPreconditionError(JSON.stringify({ error: OWNER_WATCHING_MESSAGE, dispatched: false }));
319
438
  }
320
439
  if (APP_BEHIND.test(error.message)) {
321
- // The owner's own window came forward (typing in the dashboard does it).
322
- // Not a targeting failure and nothing for the owner to do: the agent
323
- // calls open for the same app. No count, no pause, and no recovery
324
- // observation, which would only be refused the same way.
325
440
  this.#message = error.message;
326
- this.#state = 'running';
327
441
  this.#observation = undefined;
328
442
  this.#picture = undefined;
329
- this.#needsObservation = true;
330
443
  throw new BrowserPreconditionError(JSON.stringify({ error: error.message, dispatched: false,
331
- recovery: 'Call browser.act open with the same app now; it needs no approval. Then observe and continue.' }));
444
+ recovery: 'Call browser.act open with the same app now; it needs no approval. It returns the app as it is.' }));
332
445
  }
446
+ const cause = /stale|latest observation/i.test(error.message) ? 'stale-observation'
447
+ : /changed since|moved|redirect|different page/i.test(error.message) ? 'redirect' : 'stale-ref';
448
+ this.#stop(cause, ctx);
333
449
  this.#message = error.message;
334
- this.#state = ++this.#preconditionFailures >= 3 ? 'paused' : 'running';
335
- if (this.#state === 'paused')
336
- this.#message += ' Repeated targeting failures: ask the owner to inspect and resume. No input was dispatched.';
337
- // Recover evidence, never replay input. Keep this a failed tool result
338
- // so the runtime skips any remaining sequential calls in this batch.
339
- try {
340
- const observation = await this.driver.observe();
341
- const picture = await this.driver.screenshot();
342
- controller.signal.throwIfAborted();
343
- this.#observation = this.#stamp(observation);
344
- this.#picture = picture;
345
- this.#observationFailures = 0;
346
- }
347
- catch (observationError) {
348
- controller.signal.throwIfAborted();
349
- const cause = observationError instanceof Error ? observationError.message : String(observationError);
350
- const targeting = this.#state === 'paused';
351
- const paused = this.#observationFailed(cause) || targeting;
352
- if (paused)
353
- this.#state = 'paused';
354
- this.#message += ` Recovery observation failed: ${cause.replace(/\.$/, '')}.${paused ? ' Inspect the selected app/window and this error, then resume and observe. Do not retry while paused.' : APP_BEHIND.test(cause) ? '' : ` ${browserWaitMessage()}`}`;
450
+ if (++this.#targetingFailures >= MAX_TARGETING_FAILURES) {
451
+ this.#stop('targeting-cap', ctx, 'card');
452
+ return this.#cardResult(this.park('budget'), false);
355
453
  }
356
- throw new BrowserPreconditionError(JSON.stringify({ error: this.#message, dispatched: false,
357
- ...(this.#observation?.observedAt ? { message: observedLine(this.#observation.observedAt) } : {}),
358
- recovery: this.#state === 'paused' ? 'Wait for owner resume. Do not retry.' : this.#needsObservation ? (APP_BEHIND.test(this.#message) ? 'Call browser.act open with the same app; it needs no approval. Then observe.' : browserWaitMessage()) : 'Re-evaluate using the fresh observation below. Prefer target:{ref:"..."} and this observation.id. Do not guess an index or reuse the previous observation.',
359
- observation: this.#observation }));
454
+ const seen = await this.#look(controller, ctx).catch(() => false);
455
+ throw new BrowserPreconditionError(JSON.stringify({ error: error.message, dispatched: false,
456
+ ...(seen && this.#observation?.observedAt ? { message: `${observedLine(this.#observation.observedAt)} The page changed; here it is now.` } : {}),
457
+ recovery: seen ? 'Nothing was done. Re-evaluate from the page below and act on it; prefer target:{ref:"..."} from it.' : browserWaitMessage(),
458
+ ...(seen ? { observation: this.#observation } : {}) }));
360
459
  }
361
460
  /**
362
- * The authority shell the secret tools run under: exactly `execute`'s gates —
363
- * the same authenticated owner request, the same single-owner lock, the same
364
- * stopped/busy/paused/fresh-evidence refusals, the same step and expiry
365
- * budget — and its start sequence and precondition path. A secret fill is a
366
- * browser action like any other; only the value's route differs.
461
+ * The authority shell the secret tools run under: the same page, budget and
462
+ * card rules as `execute`. A secret fill is a browser action like any other;
463
+ * only the value's route differs.
367
464
  */
368
- async #under(ctx, action, run) {
369
- ctx.signal?.throwIfAborted();
370
- const request = ctx.ownerRequest;
371
- if (!request || !request.id || !request.text.trim() || request.expiresAt <= this.#now() ||
372
- !ctx.agentId || !ctx.conversationId || (ctx.delegationDepth ?? 0) > 0) {
373
- throw new Error('A current authenticated owner request is required.');
374
- }
375
- if (!this.#enabled)
376
- throw new Error('Browser driving is available through buddi serve (dashboard or Telegram), not a separate CLI process.');
377
- if (this.#state === 'stopped')
378
- throw new Error(browserStoppedMessage(ctx.surface));
379
- if (this.#busy)
380
- throw new Error('Browser is busy; overlapping actions are refused.');
381
- if (this.#session && (this.#session.ownerId !== ctx.buddi.owner.id || this.#session.agentId !== ctx.agentId || this.#session.conversationId !== ctx.conversationId)) {
382
- throw new Error('Another agent/conversation owns the browser. Ask the owner to release it from the dashboard.');
383
- }
384
- if (this.#spent.has(request.id))
385
- throw new Error('This browser request has ended. A new owner message is required.');
386
- if (this.#state === 'paused')
387
- throw new Error('Browser is under human control or needs inspection. Wait for the owner to resume in the dashboard, then observe.');
388
- if (this.#needsObservation)
389
- throw new Error('A fresh observation is required: observe the current page before acting. Do not replay an earlier action.');
390
- if (!this.#session)
391
- throw new Error('Start with navigate, or open an allowed application, and observe before using a secret here.');
392
- if (this.#session.requestId !== request.id)
393
- this.#rekey(request, ctx.agentId, ctx.conversationId, ctx.buddi.owner.id);
394
- const active = this.#session;
395
- if (!active || Date.parse(active.expiresAt) <= this.#now() || active.steps >= active.maxSteps) {
396
- await this.#release('expired');
397
- throw new Error('Browser task reached its time or step limit. Ask the owner for a new request.');
398
- }
399
- ++active.steps;
400
- this.#busy = true;
401
- this.#lastAction = action;
402
- this.#message = undefined;
403
- const controller = new AbortController();
404
- this.#controller = controller;
405
- const cancel = () => {
406
- controller.abort(ctx.signal?.reason ?? new Error('Browser action stopped.'));
407
- this.#spent.add(request.id);
408
- void this.#release('stopped');
409
- void this.#persistStop(true).catch(() => { });
410
- };
411
- ctx.signal?.addEventListener('abort', cancel, { once: true });
412
- try {
413
- this.#state = 'starting';
414
- await this.driver.start();
415
- controller.signal.throwIfAborted();
465
+ #under(ctx, action, run) {
466
+ return this.#serial(async () => {
416
467
  ctx.signal?.throwIfAborted();
417
- this.#state = 'running';
418
- return await run(controller);
419
- }
420
- catch (error) {
421
- if (!controller.signal.aborted && error instanceof BrowserPreconditionError) {
422
- await this.#precondition(controller, error);
468
+ if (!ctx.agentId || !ctx.conversationId)
469
+ throw new Error('A browser action belongs to an agent and a conversation.');
470
+ if (!this.#enabled)
471
+ throw new Error('Browser driving is available through buddi serve (dashboard or Telegram), not a separate CLI process.');
472
+ if (this.#state === 'stopped')
473
+ throw new Error(browserStoppedMessage(ctx.surface));
474
+ if (this.#session && (this.#session.ownerId !== ctx.buddi.owner.id || this.#session.agentId !== ctx.agentId || this.#session.conversationId !== ctx.conversationId)) {
475
+ throw new Error('Another conversation owns this page.');
423
476
  }
424
- if (!controller.signal.aborted) {
425
- // A failed fill or a failed typing is an uncertain input: the value may
426
- // be part-way into the field, so the session pauses rather than invites
427
- // a repeat, exactly as a fill or a click does.
428
- this.#state = 'paused';
429
- this.#message = `${error instanceof Error ? error.message : String(error)} The action may have partially completed. Inspect it before resuming; do not repeat a submission.`;
477
+ if (this.#state === 'paused')
478
+ throw new Error('The owner has this page in their hands. Wait for them to give it back.');
479
+ if (!this.#session)
480
+ throw new Error('Open the page with browser.act navigate before using a secret here.');
481
+ this.#open(ctx.ownerRequest, ctx);
482
+ if (this.#card)
483
+ return this.#cardResult(this.#card, false);
484
+ const active = this.#session;
485
+ if (active.steps >= active.maxSteps || Date.parse(active.expiresAt) <= this.#now()) {
486
+ this.#stop('budget', ctx);
487
+ return this.#cardResult(this.park('budget'), false);
430
488
  }
431
- throw error;
432
- }
433
- finally {
434
- ctx.signal?.removeEventListener('abort', cancel);
435
- if (this.#controller === controller)
436
- this.#controller = undefined;
437
- this.#busy = false;
438
- }
489
+ ++active.steps;
490
+ ++active.actions;
491
+ this.#busy = true;
492
+ this.#lastAction = action;
493
+ this.#lastActivity = this.#now();
494
+ this.#message = undefined;
495
+ const controller = new AbortController();
496
+ this.#controller = controller;
497
+ const cancel = () => { controller.abort(ctx.signal?.reason ?? new Error('Browser action stopped.')); void this.#release('idle'); };
498
+ ctx.signal?.addEventListener('abort', cancel, { once: true });
499
+ try {
500
+ this.#state = 'starting';
501
+ await this.driver.start();
502
+ controller.signal.throwIfAborted();
503
+ this.#state = 'running';
504
+ return await run(controller);
505
+ }
506
+ catch (error) {
507
+ if (controller.signal.aborted)
508
+ throw error;
509
+ if (error instanceof BrowserPreconditionError)
510
+ return await this.#precondition(controller, error, ctx);
511
+ // The value may be part-way into the field: the owner looks.
512
+ this.#state = 'running';
513
+ this.#stop('uncertain-input', ctx, 'card');
514
+ return this.#cardResult(this.park('uncertain'), true, `${error instanceof Error ? error.message.replace(/\.$/, '') : String(error)}. I'm not sure that went through.`);
515
+ }
516
+ finally {
517
+ ctx.signal?.removeEventListener('abort', cancel);
518
+ if (this.#controller === controller)
519
+ this.#controller = undefined;
520
+ this.#busy = false;
521
+ this.#settled();
522
+ }
523
+ });
524
+ }
525
+ /** After a fill or typing the page changed: answer with it, as every action does. */
526
+ async #after(controller, ctx, result) {
527
+ const seen = await this.#look(controller, ctx).catch(() => false);
528
+ return seen ? { ...result, observation: this.#observation, message: observedLine(this.#observation.observedAt) } : result;
439
529
  }
440
530
  /**
441
531
  * One owner secret into one field of the page this conversation drives
442
- * (docs/owner-secrets.md §3, §4).
443
- *
444
- * The order is the security argument. The driver reads the field's frame
445
- * origin, its password mark and its accessible name from the live page — the
446
- * backend reports, the agent never claims (§8) — then core finds the binding,
447
- * the destination checks that target against it, the rule is applied and the
448
- * vault read, and the destination's `deliver` parks the value against the use
449
- * id. Only then does the driver fill, re-checking the origin once more
450
- * against what the use was delivered for. The result is `{ filled: true }`
451
- * or a pending card; a refusal is the refusal's own sentence, and a value
452
- * appears in none of them.
532
+ * (docs/owner-secrets.md §3, §4). The driver reads the field's frame origin,
533
+ * its password mark and its name from the live page; core finds the binding
534
+ * and the destination checks it; the value crosses only into the fill.
453
535
  */
454
536
  async secretFill(input, ctx) {
455
- return this.#under(ctx, 'secret.fill', async () => {
537
+ return this.#under(ctx, 'secret.fill', async (controller) => {
456
538
  if (typeof this.driver.secretFieldInfo !== 'function' || typeof this.driver.secretFillField !== 'function') {
457
- throw new BrowserPreconditionError('secret.fill works in Playwright browser automation or in the buddi extension mode; this mode has no page fields to fill. Switch modes on the dashboard Settings page.');
539
+ throw new BrowserPreconditionError('secret.fill works on web pages (buddi\'s own browser or your Chrome); an app window has no page fields to fill.');
458
540
  }
459
- const facts = await this.driver.secretFieldInfo(input.observation, input.ref);
541
+ const observation = input.observation ?? this.#observation?.id ?? '';
542
+ const facts = await this.driver.secretFieldInfo(observation, input.ref);
460
543
  const secrets = ctx.buddi?.secrets;
461
544
  if (secrets === undefined)
462
545
  throw new Error('This plugin has no secrets area; the owner updates the browser plugin to one that declares it.');
@@ -464,12 +547,10 @@ export class BrowserService {
464
547
  if (secret === undefined) {
465
548
  throw new BrowserPreconditionError(`There is no secret named "${input.name}" bound to this browser's destinations. The owner keeps one in Settings, under Keys and secrets.`);
466
549
  }
467
- // A visible field on an origin the owner bound as browser.field takes
468
- // that binding; the card then names the field (§3).
469
550
  const visibleField = !secret.totp && !facts.password && fieldBoundTo(secret.bindings, facts.origin);
470
551
  const kind = secretKindFor(secret.totp, facts.password, visibleField);
471
552
  if (kind === FORM_KIND && facts.name.trim() === '') {
472
- throw new BrowserPreconditionError('That field has no name the page gives it, so it cannot be a form-field destination. Observe again, or ask the owner to bind the secret to the page instead.');
553
+ throw new BrowserPreconditionError('That field has no name the page gives it, so it cannot be a form-field destination. Pick another ref, or ask the owner to bind the secret to the page instead.');
473
554
  }
474
555
  const named = { origin: facts.origin, field: facts.name };
475
556
  const target = kind === FORM_KIND || (visibleField && facts.name.trim() !== '') ? named : facts.origin;
@@ -482,26 +563,15 @@ export class BrowserService {
482
563
  const value = takeDelivered(outcome.use);
483
564
  if (value === undefined)
484
565
  throw new Error('The use delivered nothing to fill with. Ask for the secret again.');
485
- await this.driver.secretFillField(input.observation, input.ref, value, facts.origin);
486
- this.#needsObservation = true; // The field just changed; the next action observes first.
487
- return { filled: true };
566
+ await this.driver.secretFillField(observation, input.ref, value, facts.origin);
567
+ return this.#after(controller, ctx, { filled: true });
488
568
  });
489
569
  }
490
- /**
491
- * One owner secret typed into the focused field of the focused app
492
- * (owner-secrets.md §3, native typing).
493
- *
494
- * The bundle id is the backend's answer about whatever app is in front right
495
- * now, and the helper re-checks it before the first keystroke, so an app
496
- * switch between the owner's approval and the typing refuses with nothing
497
- * typed. There is no observed target here — the field is whatever the owner
498
- * left focused — which is why the destination's loosest rule is a card every
499
- * time.
500
- */
570
+ /** One owner secret typed into the focused field of the focused app (owner-secrets.md §3, native typing). */
501
571
  async secretType(input, ctx) {
502
- return this.#under(ctx, 'secret.type', async () => {
572
+ return this.#under(ctx, 'secret.type', async (controller) => {
503
573
  if (typeof this.driver.focusedBundleId !== 'function' || typeof this.driver.nativeType !== 'function') {
504
- throw new BrowserPreconditionError('secret.type works in Computer mode, which types into the focused app on this machine through macOS accessibility; this mode has no native typing. Switch modes on the dashboard Settings page.');
574
+ throw new BrowserPreconditionError('secret.type types into an app on this machine; a web page takes secret.fill instead.');
505
575
  }
506
576
  const bundleId = await this.driver.focusedBundleId();
507
577
  if (!bundleId)
@@ -519,32 +589,36 @@ export class BrowserService {
519
589
  if (value === undefined)
520
590
  throw new Error('The use delivered nothing to type. Ask for the secret again.');
521
591
  await this.driver.nativeType(value);
522
- this.#needsObservation = true; // The screen just changed; the next action observes first.
523
- return { typed: true };
592
+ return this.#after(controller, ctx, { typed: true });
524
593
  });
525
594
  }
526
- async #persistStop(stopped) {
527
- if (!this.options.controlFile)
528
- return;
529
- const file = this.options.controlFile;
530
- const write = async () => {
531
- await mkdir(path.dirname(file), { recursive: true, mode: 0o700 });
532
- const temp = `${file}.${randomUUID()}.tmp`;
533
- await writeFile(temp, JSON.stringify({ stopped }), { mode: 0o600 });
534
- await rename(temp, file);
535
- };
536
- const next = this.#diskTail.then(write, write);
537
- this.#diskTail = next.catch(() => { });
538
- await next;
595
+ #markHeldEnd() {
596
+ const id = this.#session?.id;
597
+ if (id)
598
+ this.#lastHeld = { id, until: this.#now() + LOGIN_GRACE_MS };
599
+ }
600
+ /** The action in flight went (its `finally` ran): whoever waited on it hears. */
601
+ #settled() {
602
+ for (const resolve of this.#settleWaiters.splice(0))
603
+ resolve();
539
604
  }
540
605
  /**
541
- * Stop the action, keep the screen if the driver can.
542
- *
543
- * True when there is still something to drive afterwards. A driver with no
544
- * `interrupt` — or one whose page really did go — has its screen closed
545
- * instead, which is the old behaviour and still the honest answer when there
546
- * is nothing left to paint.
606
+ * The interrupted action, stopped and gone: abort it again, interrupt the
607
+ * driver, and wait for its `finally` — at most a few seconds, because a give
608
+ * back must not hang on an action that will not finish.
547
609
  */
610
+ async #settle(limitMs = 10_000) {
611
+ this.#controller?.abort(new Error('Owner took control during an action. Inspect the site before retrying.'));
612
+ const gone = new Promise((resolve) => { this.#settleWaiters.push(resolve); });
613
+ if (this.driver.interrupt)
614
+ await this.#interrupt().catch(() => false);
615
+ if (!this.#busy)
616
+ return;
617
+ let timer;
618
+ await Promise.race([gone, new Promise((resolve) => { timer = setTimeout(resolve, limitMs); timer.unref?.(); })]);
619
+ clearTimeout(timer);
620
+ }
621
+ /** Stop the action, keep the screen if the driver can. True when there is still something to drive. */
548
622
  async #interrupt() {
549
623
  if (!this.driver.interrupt) {
550
624
  await this.driver.close().catch(() => { });
@@ -560,11 +634,20 @@ export class BrowserService {
560
634
  return this.driver.handReady?.() !== false;
561
635
  }
562
636
  async #release(state) {
563
- this.#needsObservation = false;
637
+ const session = this.#session;
638
+ if (session && this.options.telemetry) {
639
+ this.options.telemetry.record({ type: 'browser.task', outcome: this.#card ? (this.#card.kind === 'budget' ? 'budget' : 'needs-owner') : state === 'stopped' ? 'stopped' : 'done',
640
+ actions: session.actions, seconds: Math.round((this.#now() - session.startedAt) / 1000), cards: session.cards, agent: session.agentId, route: this.#route, ...(session.requestId === 'unattended' ? { mission: true } : {}) });
641
+ }
642
+ if (this.#observation?.url)
643
+ this.#lastUrl = this.#observation.url;
564
644
  this.#handless = false;
645
+ if (this.#held) {
646
+ this.#markHeldEnd();
647
+ this.#held = false;
648
+ this.driver.resume?.();
649
+ }
565
650
  this.#state = state;
566
- if (this.#session)
567
- this.#spent.add(this.#session.requestId);
568
651
  this.#controller?.abort(new Error(`Browser ${state}. An in-flight submission may have completed; inspect before retrying.`));
569
652
  clearTimeout(this.#expiry);
570
653
  this.#session = undefined;
@@ -572,69 +655,89 @@ export class BrowserService {
572
655
  this.#picture = undefined;
573
656
  this.#lastAction = undefined;
574
657
  this.#message = undefined;
575
- this.#preconditionFailures = 0;
576
- this.#observationFailures = 0;
658
+ this.#card = undefined;
659
+ this.#targetingFailures = 0;
577
660
  await this.driver.close();
578
661
  }
662
+ /**
663
+ * Take over a page in the owner's own Chrome: no stream, the tab itself.
664
+ * An action in flight is abandoned first (the tab is kept), then the tab is
665
+ * brought to the front of their Chrome with its bar saying buddi waits.
666
+ * When Chrome cannot do that (closed, an extension too old to know how),
667
+ * the page stays paused and the message says where it is instead.
668
+ */
669
+ async #holdInPlace() {
670
+ this.#held = false;
671
+ if (this.#busy) {
672
+ this.#controller?.abort(new Error('Owner took control during an action. Inspect the site before retrying.'));
673
+ this.#picture = undefined;
674
+ this.#observation = undefined;
675
+ await this.#interrupt();
676
+ }
677
+ try {
678
+ await this.driver.takeover?.();
679
+ this.#held = true;
680
+ this.#message = 'The page is in front of you in your Chrome. Give it back when you are done.';
681
+ }
682
+ catch (error) {
683
+ const why = error instanceof Error ? error.message.replace(/\.$/, '') : String(error);
684
+ this.#message = `Your Chrome couldn't bring the page forward (${why}). It is in the buddi tab group there; give it back when you are done.`;
685
+ }
686
+ }
579
687
  /** Only authenticated owner UI handlers call this; it is not an agent tool. */
580
688
  control(action, expectedSessionId) {
581
689
  const run = async () => {
582
690
  if (!this.#enabled)
583
691
  throw new Error('The host browser service is unavailable.');
584
692
  if (expectedSessionId !== undefined && this.#session?.id !== expectedSessionId) {
585
- throw new Error('The browser session changed. Refresh before controlling it.');
693
+ throw new Error('The page changed. Refresh before controlling it.');
586
694
  }
587
695
  if (action === 'stop') {
588
- // Revoke in memory before disk IO, so a pending call cannot race it.
589
- const closing = this.#release('stopped');
590
- await this.#persistStop(true);
591
- await closing;
696
+ await this.#release('stopped');
592
697
  }
593
698
  else if (action === 'takeover') {
594
699
  this.#state = 'paused';
595
700
  this.#message = undefined;
596
- if (this.#busy) {
597
- // The owner presses Take over *because* the agent is working: it
598
- // reached a login, an MFA prompt or a consent banner and is still
599
- // going round on it. That page is the whole point of the button, so
600
- // the action is abandoned and the page is kept. Every branch of
601
- // `execute` that would otherwise decide what this failure means is
602
- // guarded by `controller.signal.aborted`, so aborting here is also
603
- // what stops the interrupted command from overwriting `paused`.
701
+ this.#card = undefined;
702
+ if (this.driver.holdsInPlace) {
703
+ await this.#holdInPlace();
704
+ }
705
+ else if (this.#busy) {
706
+ // Take over is pressed most often *while* the agent works on a login:
707
+ // the action is abandoned and the page kept, when the driver can.
604
708
  this.#controller?.abort(new Error('Owner took control during an action. Inspect the site before retrying.'));
605
709
  this.#picture = undefined;
606
710
  this.#observation = undefined;
607
- this.#needsObservation = !!this.#session;
608
711
  const kept = await this.#interrupt();
609
712
  this.#handless = !kept;
610
713
  this.#message = kept
611
- ? 'The in-flight action was interrupted; the page is still open and yours to use. Resume here when ready, then ask the agent to observe.'
612
- : this.driver.preservesWindows ? 'Computer input was interrupted. Your apps remain open. Inspect the result, resume, then ask the agent to observe.' : 'The in-flight action was interrupted and the window closed. Resume and ask the agent to navigate again.';
714
+ ? 'The action in flight was stopped; the page is yours. Give it back when you are done.'
715
+ : this.driver.preservesWindows ? 'Computer input was interrupted. Your apps remain open. Give it back when you are done.' : 'The action in flight was stopped and the window closed. Give it back and the agent opens the page again.';
613
716
  }
614
717
  else {
615
718
  await this.driver.takeover?.();
616
- this.#message = this.driver.preservesWindows ? 'Computer control is paused. Use the selected app, then resume here and ask the agent to observe.' : 'Use this conversation’s host tab for login or manual work. Resume here when ready, then ask the agent to observe.';
719
+ this.#message = this.driver.preservesWindows ? 'The app is yours. Give it back when you are done.' : 'The page is yours. Give it back when you are done.';
617
720
  }
618
721
  }
619
722
  else if (action === 'resume') {
723
+ // Given back while the interrupted action is still stopping: stop it for good and wait for it, then give back. Never a refusal:
724
+ // the owner's Chrome has already taken its bar down.
620
725
  if (this.#busy)
621
- throw new Error('Wait for the interrupted action to settle before resuming.');
622
- await this.#persistStop(false);
726
+ await this.#settle();
727
+ if (this.#held)
728
+ this.#markHeldEnd();
623
729
  this.driver.resume?.();
624
730
  this.#handless = false;
625
- this.#preconditionFailures = 0;
626
- this.#observationFailures = 0;
731
+ this.#held = false;
627
732
  this.#observation = undefined;
628
733
  this.#picture = undefined;
629
- this.#needsObservation = !!this.#session;
630
- if (this.#session && Date.parse(this.#session.expiresAt) <= this.#now())
631
- await this.#release('idle');
734
+ // The owner acted: a fresh budget, and the agent's next action returns the page as the owner left it.
735
+ this.renew();
632
736
  this.#state = this.#session ? 'running' : 'idle';
633
- this.#message = 'Ready. Send a new message to the agent to continue.';
737
+ this.#message = 'Given back. The agent carries on from the page as you left it.';
634
738
  }
635
739
  else {
636
- const stopped = this.#state === 'stopped';
637
- await this.#release(stopped ? 'stopped' : 'idle');
740
+ await this.#release(this.#state === 'stopped' ? 'stopped' : 'idle');
638
741
  }
639
742
  return this.status();
640
743
  };