@withbuddi/buddi 0.1.0-pre.45 → 0.1.0-pre.46

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 (250) hide show
  1. package/extension/background.js +157 -1
  2. package/extension/manifest.json +5 -2
  3. package/extension/popup.html +4 -0
  4. package/extension/popup.js +18 -0
  5. package/node_modules/@buddi/cli/dist/.tsbuildinfo +1 -1
  6. package/node_modules/@buddi/cli/dist/mcp/tools.d.ts +3 -8
  7. package/node_modules/@buddi/cli/dist/mcp/tools.d.ts.map +1 -1
  8. package/node_modules/@buddi/cli/dist/mcp/tools.js +22 -4
  9. package/node_modules/@buddi/cli/dist/mcp/tools.js.map +1 -1
  10. package/node_modules/@buddi/core/dist/.tsbuildinfo +1 -1
  11. package/node_modules/@buddi/core/dist/artifacts/orphans.d.ts +6 -4
  12. package/node_modules/@buddi/core/dist/artifacts/orphans.d.ts.map +1 -1
  13. package/node_modules/@buddi/core/dist/artifacts/orphans.js +10 -3
  14. package/node_modules/@buddi/core/dist/artifacts/orphans.js.map +1 -1
  15. package/node_modules/@buddi/core/dist/groups.d.ts +0 -9
  16. package/node_modules/@buddi/core/dist/groups.d.ts.map +1 -1
  17. package/node_modules/@buddi/core/dist/groups.js +13 -1
  18. package/node_modules/@buddi/core/dist/groups.js.map +1 -1
  19. package/node_modules/@buddi/core/dist/pages.d.ts +24 -1
  20. package/node_modules/@buddi/core/dist/pages.d.ts.map +1 -1
  21. package/node_modules/@buddi/core/dist/pages.js +61 -1
  22. package/node_modules/@buddi/core/dist/pages.js.map +1 -1
  23. package/node_modules/@buddi/core/dist/pending-input.d.ts +13 -2
  24. package/node_modules/@buddi/core/dist/pending-input.d.ts.map +1 -1
  25. package/node_modules/@buddi/core/dist/pending-input.js +57 -12
  26. package/node_modules/@buddi/core/dist/pending-input.js.map +1 -1
  27. package/node_modules/@buddi/core/dist/plugin/version.d.ts +1 -1
  28. package/node_modules/@buddi/core/dist/plugin/version.js +1 -1
  29. package/node_modules/@buddi/core/dist/web-settings.d.ts +8 -0
  30. package/node_modules/@buddi/core/dist/web-settings.d.ts.map +1 -1
  31. package/node_modules/@buddi/core/dist/web-settings.js +14 -0
  32. package/node_modules/@buddi/core/dist/web-settings.js.map +1 -1
  33. package/node_modules/@buddi/core/migrations/078_pending_input_files.sql +8 -0
  34. package/node_modules/@buddi/gateway/dist/.tsbuildinfo +1 -1
  35. package/node_modules/@buddi/gateway/dist/browser-host.d.ts.map +1 -1
  36. package/node_modules/@buddi/gateway/dist/browser-host.js +1 -0
  37. package/node_modules/@buddi/gateway/dist/browser-host.js.map +1 -1
  38. package/node_modules/@buddi/gateway/dist/web/api-routes.d.ts.map +1 -1
  39. package/node_modules/@buddi/gateway/dist/web/api-routes.js +19 -1
  40. package/node_modules/@buddi/gateway/dist/web/api-routes.js.map +1 -1
  41. package/node_modules/@buddi/gateway/dist/web/attention.d.ts +37 -0
  42. package/node_modules/@buddi/gateway/dist/web/attention.d.ts.map +1 -1
  43. package/node_modules/@buddi/gateway/dist/web/attention.js +54 -10
  44. package/node_modules/@buddi/gateway/dist/web/attention.js.map +1 -1
  45. package/node_modules/@buddi/gateway/dist/web/canvas-tabs.d.ts +41 -0
  46. package/node_modules/@buddi/gateway/dist/web/canvas-tabs.d.ts.map +1 -0
  47. package/node_modules/@buddi/gateway/dist/web/canvas-tabs.js +68 -0
  48. package/node_modules/@buddi/gateway/dist/web/canvas-tabs.js.map +1 -0
  49. package/node_modules/@buddi/gateway/dist/web/chat.d.ts +0 -9
  50. package/node_modules/@buddi/gateway/dist/web/chat.d.ts.map +1 -1
  51. package/node_modules/@buddi/gateway/dist/web/chat.js +33 -19
  52. package/node_modules/@buddi/gateway/dist/web/chat.js.map +1 -1
  53. package/node_modules/@buddi/gateway/dist/web/extension.d.ts +11 -1
  54. package/node_modules/@buddi/gateway/dist/web/extension.d.ts.map +1 -1
  55. package/node_modules/@buddi/gateway/dist/web/extension.js +51 -0
  56. package/node_modules/@buddi/gateway/dist/web/extension.js.map +1 -1
  57. package/node_modules/@buddi/gateway/dist/web/pages.d.ts.map +1 -1
  58. package/node_modules/@buddi/gateway/dist/web/pages.js +10 -1
  59. package/node_modules/@buddi/gateway/dist/web/pages.js.map +1 -1
  60. package/node_modules/@buddi/gateway/dist/web/server.d.ts +0 -4
  61. package/node_modules/@buddi/gateway/dist/web/server.d.ts.map +1 -1
  62. package/node_modules/@buddi/gateway/dist/web/server.js +72 -2
  63. package/node_modules/@buddi/gateway/dist/web/server.js.map +1 -1
  64. package/node_modules/@buddi/install/dist/.tsbuildinfo +1 -1
  65. package/node_modules/@buddi/runtime/dist/.tsbuildinfo +1 -1
  66. package/node_modules/@buddi/runtime/dist/loop.d.ts +6 -0
  67. package/node_modules/@buddi/runtime/dist/loop.d.ts.map +1 -1
  68. package/node_modules/@buddi/runtime/dist/loop.js +25 -10
  69. package/node_modules/@buddi/runtime/dist/loop.js.map +1 -1
  70. package/node_modules/@buddi/tool-artifacts/dist/.tsbuildinfo +1 -1
  71. package/node_modules/@buddi/tool-artifacts/dist/extract.d.ts +6 -0
  72. package/node_modules/@buddi/tool-artifacts/dist/extract.d.ts.map +1 -1
  73. package/node_modules/@buddi/tool-artifacts/dist/extract.js +6 -0
  74. package/node_modules/@buddi/tool-artifacts/dist/extract.js.map +1 -1
  75. package/node_modules/@buddi/tool-artifacts/dist/tools/artifacts.d.ts +1 -0
  76. package/node_modules/@buddi/tool-artifacts/dist/tools/artifacts.d.ts.map +1 -1
  77. package/node_modules/@buddi/tool-artifacts/dist/tools/artifacts.js +30 -8
  78. package/node_modules/@buddi/tool-artifacts/dist/tools/artifacts.js.map +1 -1
  79. package/node_modules/@buddi/tool-browser/dist/.tsbuildinfo +1 -1
  80. package/node_modules/@buddi/tool-browser/dist/controller.d.ts +25 -0
  81. package/node_modules/@buddi/tool-browser/dist/controller.d.ts.map +1 -1
  82. package/node_modules/@buddi/tool-browser/dist/controller.js +25 -1
  83. package/node_modules/@buddi/tool-browser/dist/controller.js.map +1 -1
  84. package/node_modules/@buddi/tool-browser/dist/downloads.d.ts +138 -0
  85. package/node_modules/@buddi/tool-browser/dist/downloads.d.ts.map +1 -0
  86. package/node_modules/@buddi/tool-browser/dist/downloads.js +529 -0
  87. package/node_modules/@buddi/tool-browser/dist/downloads.js.map +1 -0
  88. package/node_modules/@buddi/tool-browser/dist/driver.d.ts +17 -1
  89. package/node_modules/@buddi/tool-browser/dist/driver.d.ts.map +1 -1
  90. package/node_modules/@buddi/tool-browser/dist/driver.js +48 -0
  91. package/node_modules/@buddi/tool-browser/dist/driver.js.map +1 -1
  92. package/node_modules/@buddi/tool-browser/dist/extension.d.ts +23 -0
  93. package/node_modules/@buddi/tool-browser/dist/extension.d.ts.map +1 -1
  94. package/node_modules/@buddi/tool-browser/dist/extension.js +20 -0
  95. package/node_modules/@buddi/tool-browser/dist/extension.js.map +1 -1
  96. package/node_modules/@buddi/tool-browser/dist/host.d.ts +3 -1
  97. package/node_modules/@buddi/tool-browser/dist/host.d.ts.map +1 -1
  98. package/node_modules/@buddi/tool-browser/dist/host.js +9 -2
  99. package/node_modules/@buddi/tool-browser/dist/host.js.map +1 -1
  100. package/node_modules/@buddi/tool-browser/dist/index.d.ts +7 -3
  101. package/node_modules/@buddi/tool-browser/dist/index.d.ts.map +1 -1
  102. package/node_modules/@buddi/tool-browser/dist/index.js +5 -3
  103. package/node_modules/@buddi/tool-browser/dist/index.js.map +1 -1
  104. package/node_modules/@buddi/tool-browser/dist/service.d.ts +28 -0
  105. package/node_modules/@buddi/tool-browser/dist/service.d.ts.map +1 -1
  106. package/node_modules/@buddi/tool-browser/dist/service.js +58 -1
  107. package/node_modules/@buddi/tool-browser/dist/service.js.map +1 -1
  108. package/node_modules/@buddi/tool-browser/dist/settings.d.ts +8 -0
  109. package/node_modules/@buddi/tool-browser/dist/settings.d.ts.map +1 -1
  110. package/node_modules/@buddi/tool-browser/dist/settings.js +9 -0
  111. package/node_modules/@buddi/tool-browser/dist/settings.js.map +1 -1
  112. package/node_modules/@buddi/tool-browser/dist/types.d.ts +31 -24
  113. package/node_modules/@buddi/tool-browser/dist/types.d.ts.map +1 -1
  114. package/node_modules/@buddi/tool-browser/dist/types.js.map +1 -1
  115. package/node_modules/@buddi/tool-email/dist/.tsbuildinfo +1 -1
  116. package/node_modules/@buddi/tool-host/dist/.tsbuildinfo +1 -1
  117. package/node_modules/@buddi/tool-mcp/dist/.tsbuildinfo +1 -1
  118. package/node_modules/@buddi/tool-memory/dist/.tsbuildinfo +1 -1
  119. package/node_modules/@buddi/tool-web/dist/.tsbuildinfo +1 -1
  120. package/node_modules/nanoid/README.md +3 -3
  121. package/node_modules/nanoid/index.browser.js +4 -5
  122. package/node_modules/nanoid/index.d.ts +3 -3
  123. package/node_modules/nanoid/index.js +2 -3
  124. package/node_modules/nanoid/nanoid.js +1 -1
  125. package/node_modules/nanoid/package.json +2 -2
  126. package/node_modules/nanoid/url-alphabet/index.js +1 -1
  127. package/package.json +2 -2
  128. package/packages/cli/dist/.tsbuildinfo +1 -1
  129. package/packages/cli/dist/mcp/tools.d.ts +3 -8
  130. package/packages/cli/dist/mcp/tools.d.ts.map +1 -1
  131. package/packages/cli/dist/mcp/tools.js +22 -4
  132. package/packages/cli/dist/mcp/tools.js.map +1 -1
  133. package/packages/core/dist/.tsbuildinfo +1 -1
  134. package/packages/core/dist/artifacts/orphans.d.ts +6 -4
  135. package/packages/core/dist/artifacts/orphans.d.ts.map +1 -1
  136. package/packages/core/dist/artifacts/orphans.js +10 -3
  137. package/packages/core/dist/artifacts/orphans.js.map +1 -1
  138. package/packages/core/dist/groups.d.ts +0 -9
  139. package/packages/core/dist/groups.d.ts.map +1 -1
  140. package/packages/core/dist/groups.js +13 -1
  141. package/packages/core/dist/groups.js.map +1 -1
  142. package/packages/core/dist/pages.d.ts +24 -1
  143. package/packages/core/dist/pages.d.ts.map +1 -1
  144. package/packages/core/dist/pages.js +61 -1
  145. package/packages/core/dist/pages.js.map +1 -1
  146. package/packages/core/dist/pending-input.d.ts +13 -2
  147. package/packages/core/dist/pending-input.d.ts.map +1 -1
  148. package/packages/core/dist/pending-input.js +57 -12
  149. package/packages/core/dist/pending-input.js.map +1 -1
  150. package/packages/core/dist/plugin/version.d.ts +1 -1
  151. package/packages/core/dist/plugin/version.js +1 -1
  152. package/packages/core/dist/web-settings.d.ts +8 -0
  153. package/packages/core/dist/web-settings.d.ts.map +1 -1
  154. package/packages/core/dist/web-settings.js +14 -0
  155. package/packages/core/dist/web-settings.js.map +1 -1
  156. package/packages/core/migrations/078_pending_input_files.sql +8 -0
  157. package/packages/gateway/dist/.tsbuildinfo +1 -1
  158. package/packages/gateway/dist/browser-host.d.ts.map +1 -1
  159. package/packages/gateway/dist/browser-host.js +1 -0
  160. package/packages/gateway/dist/browser-host.js.map +1 -1
  161. package/packages/gateway/dist/web/api-routes.d.ts.map +1 -1
  162. package/packages/gateway/dist/web/api-routes.js +19 -1
  163. package/packages/gateway/dist/web/api-routes.js.map +1 -1
  164. package/packages/gateway/dist/web/attention.d.ts +37 -0
  165. package/packages/gateway/dist/web/attention.d.ts.map +1 -1
  166. package/packages/gateway/dist/web/attention.js +54 -10
  167. package/packages/gateway/dist/web/attention.js.map +1 -1
  168. package/packages/gateway/dist/web/canvas-tabs.d.ts +41 -0
  169. package/packages/gateway/dist/web/canvas-tabs.d.ts.map +1 -0
  170. package/packages/gateway/dist/web/canvas-tabs.js +68 -0
  171. package/packages/gateway/dist/web/canvas-tabs.js.map +1 -0
  172. package/packages/gateway/dist/web/chat.d.ts +0 -9
  173. package/packages/gateway/dist/web/chat.d.ts.map +1 -1
  174. package/packages/gateway/dist/web/chat.js +33 -19
  175. package/packages/gateway/dist/web/chat.js.map +1 -1
  176. package/packages/gateway/dist/web/extension.d.ts +11 -1
  177. package/packages/gateway/dist/web/extension.d.ts.map +1 -1
  178. package/packages/gateway/dist/web/extension.js +51 -0
  179. package/packages/gateway/dist/web/extension.js.map +1 -1
  180. package/packages/gateway/dist/web/pages.d.ts.map +1 -1
  181. package/packages/gateway/dist/web/pages.js +10 -1
  182. package/packages/gateway/dist/web/pages.js.map +1 -1
  183. package/packages/gateway/dist/web/server.d.ts +0 -4
  184. package/packages/gateway/dist/web/server.d.ts.map +1 -1
  185. package/packages/gateway/dist/web/server.js +72 -2
  186. package/packages/gateway/dist/web/server.js.map +1 -1
  187. package/packages/install/dist/.tsbuildinfo +1 -1
  188. package/packages/runtime/dist/.tsbuildinfo +1 -1
  189. package/packages/runtime/dist/loop.d.ts +6 -0
  190. package/packages/runtime/dist/loop.d.ts.map +1 -1
  191. package/packages/runtime/dist/loop.js +25 -10
  192. package/packages/runtime/dist/loop.js.map +1 -1
  193. package/packages/tools/artifacts/dist/.tsbuildinfo +1 -1
  194. package/packages/tools/artifacts/dist/extract.d.ts +6 -0
  195. package/packages/tools/artifacts/dist/extract.d.ts.map +1 -1
  196. package/packages/tools/artifacts/dist/extract.js +6 -0
  197. package/packages/tools/artifacts/dist/extract.js.map +1 -1
  198. package/packages/tools/artifacts/dist/tools/artifacts.d.ts +1 -0
  199. package/packages/tools/artifacts/dist/tools/artifacts.d.ts.map +1 -1
  200. package/packages/tools/artifacts/dist/tools/artifacts.js +30 -8
  201. package/packages/tools/artifacts/dist/tools/artifacts.js.map +1 -1
  202. package/packages/tools/browser/dist/.tsbuildinfo +1 -1
  203. package/packages/tools/browser/dist/controller.d.ts +25 -0
  204. package/packages/tools/browser/dist/controller.d.ts.map +1 -1
  205. package/packages/tools/browser/dist/controller.js +25 -1
  206. package/packages/tools/browser/dist/controller.js.map +1 -1
  207. package/packages/tools/browser/dist/downloads.d.ts +138 -0
  208. package/packages/tools/browser/dist/downloads.d.ts.map +1 -0
  209. package/packages/tools/browser/dist/downloads.js +529 -0
  210. package/packages/tools/browser/dist/downloads.js.map +1 -0
  211. package/packages/tools/browser/dist/driver.d.ts +17 -1
  212. package/packages/tools/browser/dist/driver.d.ts.map +1 -1
  213. package/packages/tools/browser/dist/driver.js +48 -0
  214. package/packages/tools/browser/dist/driver.js.map +1 -1
  215. package/packages/tools/browser/dist/extension.d.ts +23 -0
  216. package/packages/tools/browser/dist/extension.d.ts.map +1 -1
  217. package/packages/tools/browser/dist/extension.js +20 -0
  218. package/packages/tools/browser/dist/extension.js.map +1 -1
  219. package/packages/tools/browser/dist/host.d.ts +3 -1
  220. package/packages/tools/browser/dist/host.d.ts.map +1 -1
  221. package/packages/tools/browser/dist/host.js +9 -2
  222. package/packages/tools/browser/dist/host.js.map +1 -1
  223. package/packages/tools/browser/dist/index.d.ts +7 -3
  224. package/packages/tools/browser/dist/index.d.ts.map +1 -1
  225. package/packages/tools/browser/dist/index.js +5 -3
  226. package/packages/tools/browser/dist/index.js.map +1 -1
  227. package/packages/tools/browser/dist/service.d.ts +28 -0
  228. package/packages/tools/browser/dist/service.d.ts.map +1 -1
  229. package/packages/tools/browser/dist/service.js +58 -1
  230. package/packages/tools/browser/dist/service.js.map +1 -1
  231. package/packages/tools/browser/dist/settings.d.ts +8 -0
  232. package/packages/tools/browser/dist/settings.d.ts.map +1 -1
  233. package/packages/tools/browser/dist/settings.js +9 -0
  234. package/packages/tools/browser/dist/settings.js.map +1 -1
  235. package/packages/tools/browser/dist/types.d.ts +31 -24
  236. package/packages/tools/browser/dist/types.d.ts.map +1 -1
  237. package/packages/tools/browser/dist/types.js.map +1 -1
  238. package/packages/tools/email/dist/.tsbuildinfo +1 -1
  239. package/packages/tools/host/dist/.tsbuildinfo +1 -1
  240. package/packages/tools/mcp/dist/.tsbuildinfo +1 -1
  241. package/packages/tools/memory/dist/.tsbuildinfo +1 -1
  242. package/packages/tools/web/dist/.tsbuildinfo +1 -1
  243. package/packages/web/dist/assets/index-C2yWZED2.css +1 -0
  244. package/packages/web/dist/assets/index-CIhME8Ui.js +150 -0
  245. package/packages/web/dist/assets/{lottie_light-DxWeiVDC.js → lottie_light-CVXFbeEK.js} +1 -1
  246. package/packages/web/dist/build.json +1 -1
  247. package/packages/web/dist/index.html +2 -2
  248. package/packages/web/dist/precache.json +4 -4
  249. package/packages/web/dist/assets/index-CPFSREcP.css +0 -1
  250. package/packages/web/dist/assets/index-DYUn1V0x.js +0 -150
@@ -910,6 +910,7 @@ function fieldFacts(read) {
910
910
  function fieldObservation(read) {
911
911
  return { field: fieldFacts(read) };
912
912
  }
913
+ var DOWNLOAD_COMMANDS = /* @__PURE__ */ new Set(["navigate", "click", "press", "select", "fill"]);
913
914
  var BrowserCommands = class {
914
915
  #chrome;
915
916
  #sessions = /* @__PURE__ */ new Map();
@@ -936,6 +937,7 @@ var BrowserCommands = class {
936
937
  #ownerWaitMs;
937
938
  constructor(chrome2, options = {}) {
938
939
  this.#chrome = chrome2;
940
+ this.downloads = options.downloads;
939
941
  this.logins = new HeldLogins(options.onLogin ?? (() => void 0));
940
942
  chrome2.tabs.onRemoved?.addListener((tabId) => this.logins.clearTab(tabId));
941
943
  this.#onEvent = options.onEvent ?? (() => void 0);
@@ -959,8 +961,32 @@ var BrowserCommands = class {
959
961
  this.#uuid = options.uuid ?? (() => crypto.randomUUID());
960
962
  this.#contentFile = options.contentFile ?? "content.js";
961
963
  }
964
+ /** Downloads an agent's command starts, noticed while it runs (and a few seconds after). */
965
+ downloads;
966
+ /** The addresses of a session's tabs, for telling its downloads from the owner's. */
967
+ async #tabUrls(name) {
968
+ const session = this.#sessions.get(name);
969
+ if (!session) return [];
970
+ const urls = [];
971
+ for (const tabId of session.tabs.values()) {
972
+ const tab = await this.#chrome.tabs.get(tabId).catch(() => void 0);
973
+ if (tab?.url) urls.push(tab.url);
974
+ }
975
+ return urls;
976
+ }
962
977
  async run(command, cancel = new Cancellation()) {
963
978
  cancel.check();
979
+ if (this.downloads?.attached && !command.owner && DOWNLOAD_COMMANDS.has(command.name)) {
980
+ const action = this.downloads.begin(command.session, await this.#tabUrls(command.session));
981
+ try {
982
+ return await this.#dispatch(command, cancel);
983
+ } finally {
984
+ this.downloads.end(action, await this.#tabUrls(command.session).catch(() => []));
985
+ }
986
+ }
987
+ return this.#dispatch(command, cancel);
988
+ }
989
+ async #dispatch(command, cancel) {
964
990
  switch (command.name) {
965
991
  case "navigate":
966
992
  return this.#navigate(command, cancel);
@@ -1017,6 +1043,7 @@ var BrowserCommands = class {
1017
1043
  this.#held.clear();
1018
1044
  this.#heldLogins.clear();
1019
1045
  this.logins.clear();
1046
+ this.downloads?.forget();
1020
1047
  }
1021
1048
  /* ---- take-over in place ---- */
1022
1049
  /**
@@ -1365,6 +1392,7 @@ var BrowserCommands = class {
1365
1392
  }
1366
1393
  this.#sessions.delete(command.session);
1367
1394
  this.#refs.delete(command.session);
1395
+ this.downloads?.forget(command.session);
1368
1396
  return {};
1369
1397
  }
1370
1398
  /** The owner may have closed or adopted an agent tab; a session forgets those before it reports. */
@@ -1953,6 +1981,126 @@ function heldLoginFacts(raw) {
1953
1981
  return { never: sites, saved: kept };
1954
1982
  }
1955
1983
 
1984
+ // src/downloads.ts
1985
+ var DOWNLOAD_GRACE_MS = 15e3;
1986
+ var DOWNLOADS_PERMISSION = "downloads";
1987
+ function originOf(url) {
1988
+ if (!url) return void 0;
1989
+ try {
1990
+ const parsed = new URL(url);
1991
+ if (parsed.protocol === "blob:") return new URL(parsed.pathname).origin;
1992
+ return parsed.protocol === "http:" || parsed.protocol === "https:" ? parsed.origin : void 0;
1993
+ } catch {
1994
+ return void 0;
1995
+ }
1996
+ }
1997
+ function basename(file) {
1998
+ return file.split(/[\\/]/).pop() || "download";
1999
+ }
2000
+ var AgentDownloads = class {
2001
+ #actions = /* @__PURE__ */ new Map();
2002
+ #next = 1;
2003
+ #claimed = /* @__PURE__ */ new Map();
2004
+ #api;
2005
+ #send;
2006
+ #now;
2007
+ constructor(options) {
2008
+ this.#send = options.send;
2009
+ this.#now = options.now ?? (() => Date.now());
2010
+ }
2011
+ /** Chrome's downloads API, once the owner granted it. Listening starts here, once. */
2012
+ attach(api) {
2013
+ if (!api || this.#api) return;
2014
+ this.#api = api;
2015
+ api.onCreated.addListener((item) => this.created(item));
2016
+ api.onChanged.addListener((delta) => {
2017
+ void this.changed(delta).catch(() => void 0);
2018
+ });
2019
+ }
2020
+ get attached() {
2021
+ return this.#api !== void 0;
2022
+ }
2023
+ /** An agent command starts in this session, whose tabs are on these addresses. Returns the command's handle for `end`. */
2024
+ begin(session, urls) {
2025
+ this.#expire();
2026
+ const id = this.#next++;
2027
+ const origins = /* @__PURE__ */ new Set();
2028
+ for (const url of urls) {
2029
+ const origin = originOf(url);
2030
+ if (origin) origins.add(origin);
2031
+ }
2032
+ this.#actions.set(id, { session, origins, running: true, until: 0, at: this.#now() });
2033
+ return id;
2034
+ }
2035
+ /** That command ended; its tabs may have moved on to these. Its downloads still count for a few seconds, its own. */
2036
+ end(id, urls = []) {
2037
+ const action = this.#actions.get(id);
2038
+ if (!action) return;
2039
+ for (const url of urls) {
2040
+ const origin = originOf(url);
2041
+ if (origin) action.origins.add(origin);
2042
+ }
2043
+ action.running = false;
2044
+ action.until = this.#now() + DOWNLOAD_GRACE_MS;
2045
+ }
2046
+ /** Commands whose few seconds are over count for nothing any more. */
2047
+ #expire() {
2048
+ const now = this.#now();
2049
+ for (const [id, action] of this.#actions) if (!action.running && now > action.until) this.#actions.delete(id);
2050
+ }
2051
+ /** The session ended or the socket went: nothing more is its. */
2052
+ forget(session) {
2053
+ if (session === void 0) {
2054
+ this.#actions.clear();
2055
+ this.#claimed.clear();
2056
+ return;
2057
+ }
2058
+ for (const [id, action] of this.#actions) if (action.session === session) this.#actions.delete(id);
2059
+ for (const [id, owner] of this.#claimed) if (owner === session) this.#claimed.delete(id);
2060
+ }
2061
+ /** Which session's command this download belongs to, if any. */
2062
+ #owner(item) {
2063
+ if (item.byExtensionId) return void 0;
2064
+ const origin = originOf(item.referrer) ?? originOf(item.finalUrl ?? item.url);
2065
+ if (!origin) return void 0;
2066
+ this.#expire();
2067
+ let best;
2068
+ for (const action of this.#actions.values()) {
2069
+ if (!action.origins.has(origin)) continue;
2070
+ if (!best || action.at > best.at) best = action;
2071
+ }
2072
+ return best?.session;
2073
+ }
2074
+ created(item) {
2075
+ const session = this.#owner(item);
2076
+ if (session) this.#claimed.set(item.id, session);
2077
+ }
2078
+ async changed(delta) {
2079
+ const session = this.#claimed.get(delta.id);
2080
+ const state = delta.state?.current;
2081
+ if (!session || !state) return;
2082
+ if (state === "interrupted") {
2083
+ this.#claimed.delete(delta.id);
2084
+ return;
2085
+ }
2086
+ if (state !== "complete") return;
2087
+ this.#claimed.delete(delta.id);
2088
+ const [item] = await (this.#api?.search({ id: delta.id }) ?? Promise.resolve([]));
2089
+ if (!item?.filename) return;
2090
+ const url = item.finalUrl || item.url || "";
2091
+ const size = item.fileSize !== void 0 && item.fileSize >= 0 ? item.fileSize : item.totalBytes !== void 0 && item.totalBytes >= 0 ? item.totalBytes : void 0;
2092
+ this.#send({
2093
+ type: "download",
2094
+ session,
2095
+ path: item.filename,
2096
+ filename: basename(item.filename),
2097
+ url,
2098
+ ...item.mime ? { mime: item.mime } : {},
2099
+ ...size !== void 0 ? { size } : {}
2100
+ });
2101
+ }
2102
+ };
2103
+
1956
2104
  // src/external.ts
1957
2105
  function isLoopbackOrigin(origin) {
1958
2106
  if (!origin) return false;
@@ -2028,7 +2176,15 @@ function flush(open) {
2028
2176
  }
2029
2177
  }
2030
2178
  }
2031
- var commands = new BrowserCommands(chrome, { onFrame: send, onEvent: send, onLogin: send });
2179
+ var downloads = new AgentDownloads({ send });
2180
+ var attachDownloads = () => {
2181
+ if (chrome.downloads) downloads.attach(chrome.downloads);
2182
+ };
2183
+ attachDownloads();
2184
+ chrome.permissions?.onAdded?.addListener((added) => {
2185
+ if (added.permissions?.includes(DOWNLOADS_PERMISSION)) attachDownloads();
2186
+ });
2187
+ var commands = new BrowserCommands(chrome, { onFrame: send, onEvent: send, onLogin: send, downloads });
2032
2188
  var attempt = 0;
2033
2189
  var timer;
2034
2190
  var silence;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "buddi",
4
- "version": "0.1.0.45",
4
+ "version": "0.1.0.46",
5
5
  "description": "Lets your buddi work in background tabs of this browser. The sites it opens are the ones you ask it for; it opens none on its own.",
6
6
  "minimum_chrome_version": "116",
7
7
  "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwR4JT/OlKKPcZQ33euO9mSv7RrSIWNVanldhT2Uzc9YfzF/X0lg5NfXLc+G/UGFjB8v+uMCbpMhRBZ2SVwDHQH3buv3VEUzuOIDTPHgv99T5lq5imZrDxmIE+EL/fWrsjhcXaIB4e4fn0tJqw6ivJUGmYpG5XhWn65nlLniHfFBKMpZ/y7bVnvfzAgMQUa13qTAVxPTpMRtNl/flQq4Q/vWYm28H7W7OzygDV+/4X2azUrB8yPk67QsipbdDLxiX2GMxjXuKK6iD5CQiytoxTsAqUzB886HbOZsxJfQpRIjrUgBmGjLyaKuz617ZGJW9zS23LmnlL6mkX3+ggca1AQIDAQAB",
@@ -13,6 +13,9 @@
13
13
  "storage",
14
14
  "alarms"
15
15
  ],
16
+ "optional_permissions": [
17
+ "downloads"
18
+ ],
16
19
  "host_permissions": [
17
20
  "http://*/*",
18
21
  "https://*/*"
@@ -42,5 +45,5 @@
42
45
  "48": "icons/48.png",
43
46
  "128": "icons/128.png"
44
47
  },
45
- "version_name": "0.1.0-pre.45"
48
+ "version_name": "0.1.0-pre.46"
46
49
  }
@@ -46,7 +46,11 @@
46
46
  <p class="fact" id="paired-to"></p>
47
47
  <p class="quiet" id="working">Nothing open right now.</p>
48
48
  </div>
49
+ <div class="facts" id="downloads-box" hidden>
50
+ <p class="quiet" id="downloads-note">Let agents hand buddi the files they download in your Chrome, like a bank statement. Only downloads an agent's click starts are read; yours are never touched.</p>
51
+ </div>
49
52
  <div class="actions">
53
+ <button class="btn" id="allow-downloads" type="button" hidden>Allow downloads</button>
50
54
  <button class="btn" id="open-buddi" type="button">Open buddi</button>
51
55
  </div>
52
56
  <footer class="foot">
@@ -1,3 +1,6 @@
1
+ // src/downloads.ts
2
+ var DOWNLOADS_PERMISSION = "downloads";
3
+
1
4
  // src/popup.ts
2
5
  var SETTINGS_HASH = "#/settings/computer";
3
6
  var PILL = {
@@ -125,6 +128,19 @@ function wireCopy(button, read) {
125
128
  })();
126
129
  });
127
130
  }
131
+ async function wireDownloads(doc, permissions) {
132
+ const box = byId(doc, "downloads-box");
133
+ const button = byId(doc, "allow-downloads");
134
+ if (!permissions || !box || !button) return;
135
+ const show = (granted) => {
136
+ box.hidden = granted;
137
+ button.hidden = granted;
138
+ };
139
+ show(await permissions.contains({ permissions: [DOWNLOADS_PERMISSION] }).catch(() => true));
140
+ button.addEventListener("click", () => {
141
+ void permissions.request({ permissions: [DOWNLOADS_PERMISSION] }).then(show, () => void 0);
142
+ });
143
+ }
128
144
  async function countBuddiTabs(api) {
129
145
  try {
130
146
  const groups = new Set((await api.tabGroups.query({ title: "buddi" })).map((group) => group.id));
@@ -229,6 +245,7 @@ async function main() {
229
245
  });
230
246
  });
231
247
  byId(document, "open-buddi").addEventListener("click", () => open(""));
248
+ void wireDownloads(document, chrome.permissions);
232
249
  byId(document, "forget").addEventListener("click", async () => {
233
250
  const answer = await ask({ type: "buddi-forget" });
234
251
  if (answer?.state) {
@@ -253,5 +270,6 @@ export {
253
270
  triesApp,
254
271
  viewOf,
255
272
  wireCopy,
273
+ wireDownloads,
256
274
  workingLine
257
275
  };