agentic-browser 1.5.1 → 1.6.0

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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { r as createCliRuntime } from "../runtime-OsYo7Rh2.mjs";
2
+ import { r as createCliRuntime } from "../runtime-C7B024bN.mjs";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import crypto from "node:crypto";
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { i as createMockAgenticBrowserCore, n as createAgenticBrowserCore, t as AgenticBrowserCore } from "./runtime-OsYo7Rh2.mjs";
2
+ import { i as createMockAgenticBrowserCore, n as createAgenticBrowserCore, t as AgenticBrowserCore } from "./runtime-C7B024bN.mjs";
3
3
 
4
4
  export { AgenticBrowserCore, createAgenticBrowserCore, createMockAgenticBrowserCore };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as createAgenticBrowserCore } from "../runtime-OsYo7Rh2.mjs";
2
+ import { n as createAgenticBrowserCore } from "../runtime-C7B024bN.mjs";
3
3
  import { z } from "zod";
4
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -217,6 +217,14 @@ server.tool("browser_search_memory", "Search task memory for previously learned
217
217
  text: JSON.stringify({ results: compactResults })
218
218
  }] };
219
219
  });
220
+ server.tool("browser_dismiss_cookies", "Dismiss cookie consent banners on the current page. Uses the accessibility tree first (most robust), then falls back to known CSS selectors and text-based button matching. Supports banners in English, German, French, Spanish, Italian, Dutch, and Portuguese. Call this after navigating to a new page. A session is auto-started if needed.", { sessionId: z.string().optional().describe("Session ID (auto-resolved if omitted)") }, async ({ sessionId }) => {
221
+ const sid = await resolveSession(sessionId);
222
+ const result = await getCore().dismissCookieBanner(sid);
223
+ return { content: [{
224
+ type: "text",
225
+ text: JSON.stringify(result)
226
+ }] };
227
+ });
220
228
  server.tool("browser_stop_session", "Stop the browser session and terminate Chrome. The next browser tool call will auto-start a fresh session.", { sessionId: z.string().optional().describe("Session ID (uses active session if omitted)") }, async ({ sessionId }) => {
221
229
  const sid = sessionId ?? activeSessionId;
222
230
  if (!sid) return { content: [{
@@ -913,6 +913,161 @@ var ChromeCdpBrowserController = class {
913
913
  }));
914
914
  });
915
915
  }
916
+ /**
917
+ * Best-effort cookie/consent banner dismissal.
918
+ *
919
+ * Strategy (in order):
920
+ * 1. A11y tree scan — find buttons with consent-like accessible names
921
+ * 2. CSS selector scan — check common consent framework IDs/classes
922
+ * 3. Text-based scan — find visible buttons matching accept/agree patterns
923
+ *
924
+ * Returns silently on failure — never blocks navigation.
925
+ */
926
+ async dismissCookieBanner(targetWsUrl) {
927
+ try {
928
+ const a11yResult = await this.dismissViaA11y(targetWsUrl);
929
+ if (a11yResult.dismissed) return a11yResult;
930
+ } catch {}
931
+ const expression = `(() => {
932
+ // Common cookie-consent button selectors (ordered by specificity)
933
+ const selectors = [
934
+ '#onetrust-accept-btn-handler',
935
+ '#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll',
936
+ '#CybotCookiebotDialogBodyButtonAccept',
937
+ '#accept-cookies', '#acceptCookies',
938
+ '#cookie-accept', '#cookieAccept',
939
+ '#gdpr-accept', '#consent-accept',
940
+ '#uc-btn-accept-banner',
941
+ '.cc-accept', '.cc-btn.cc-dismiss',
942
+ '.cookie-consent-accept', '.cookie-accept-btn',
943
+ '.js-cookie-accept', '.js-accept-cookies',
944
+ '.consent-accept', '.consent-btn-accept',
945
+ '.gdpr-accept',
946
+ '[data-testid="cookie-accept"]',
947
+ '[data-action="accept-cookies"]',
948
+ '[data-cookiefirst-action="accept"]',
949
+ ];
950
+
951
+ for (const sel of selectors) {
952
+ const el = document.querySelector(sel);
953
+ if (el && el.offsetParent !== null) {
954
+ el.click();
955
+ return JSON.stringify({ dismissed: true, method: 'selector', detail: sel });
956
+ }
957
+ }
958
+
959
+ // Text-based fallback: find visible buttons with consent text
960
+ const patterns = [
961
+ /^accept\\s*(all)?\\s*(cookies)?$/i,
962
+ /^(alle\\s+)?akzeptieren$/i,
963
+ /^(i\\s+)?agree$/i,
964
+ /^allow\\s*(all)?\\s*(cookies)?$/i,
965
+ /^(alle\\s+)?zustimmen$/i,
966
+ /^got\\s*it$/i,
967
+ /^ok$/i,
968
+ /^consent$/i,
969
+ /^(j')?accepte(r)?$/i,
970
+ /^(tout\\s+)?accepter$/i,
971
+ ];
972
+ const candidates = [
973
+ ...document.querySelectorAll('button'),
974
+ ...document.querySelectorAll('a[role="button"]'),
975
+ ...document.querySelectorAll('[role="button"]'),
976
+ ];
977
+ for (const el of candidates) {
978
+ if (!el.offsetParent) continue;
979
+ const text = (el.textContent || '').trim();
980
+ if (text.length > 40) continue;
981
+ for (const pat of patterns) {
982
+ if (pat.test(text)) {
983
+ el.click();
984
+ return JSON.stringify({ dismissed: true, method: 'text', detail: text });
985
+ }
986
+ }
987
+ }
988
+
989
+ return JSON.stringify({ dismissed: false });
990
+ })()`;
991
+ try {
992
+ return await this.withRetry(targetWsUrl, async (conn) => {
993
+ await this.ensureEnabled(targetWsUrl);
994
+ const raw = (await conn.send("Runtime.evaluate", {
995
+ expression,
996
+ returnByValue: true
997
+ })).result.value ?? "{\"dismissed\":false}";
998
+ try {
999
+ return JSON.parse(raw);
1000
+ } catch {
1001
+ return { dismissed: false };
1002
+ }
1003
+ });
1004
+ } catch {
1005
+ return { dismissed: false };
1006
+ }
1007
+ }
1008
+ /**
1009
+ * Use the CDP Accessibility tree to find and click consent buttons.
1010
+ * This works even when consent banners use shadow DOM, iframes, or obfuscated class names.
1011
+ */
1012
+ async dismissViaA11y(targetWsUrl) {
1013
+ return await this.withRetry(targetWsUrl, async (conn) => {
1014
+ await conn.send("Accessibility.enable");
1015
+ const { nodes } = await conn.send("Accessibility.getFullAXTree");
1016
+ const consentPatterns = [
1017
+ /^accept\s*(all)?\s*(cookies)?$/i,
1018
+ /^(i\s+)?agree(\s+to\s+all)?$/i,
1019
+ /^allow\s*(all)?\s*(cookies)?$/i,
1020
+ /^got\s*it$/i,
1021
+ /^ok$/i,
1022
+ /^consent$/i,
1023
+ /^(alle\s+)?akzeptieren$/i,
1024
+ /^(alle\s+)?zustimmen$/i,
1025
+ /^einverstanden$/i,
1026
+ /^(j')?accepte(r)?(\s+tout)?$/i,
1027
+ /^(tout\s+)?accepter$/i,
1028
+ /^aceptar(\s+todo)?$/i,
1029
+ /^accetta(\s+tutto)?$/i,
1030
+ /^accepteren$/i,
1031
+ /^alle\s+accepteren$/i,
1032
+ /^aceitar(\s+tudo)?$/i
1033
+ ];
1034
+ const candidates = [];
1035
+ for (const node of nodes) {
1036
+ if (node.ignored) continue;
1037
+ const role = node.role?.value;
1038
+ if (role !== "button" && role !== "link") continue;
1039
+ const name = node.name?.value?.trim();
1040
+ if (!name || name.length > 50) continue;
1041
+ if (node.properties?.some((p) => p.name === "disabled" && p.value.value === true)) continue;
1042
+ for (const pat of consentPatterns) if (pat.test(name) && node.backendDOMNodeId) {
1043
+ candidates.push({
1044
+ nodeId: node.nodeId,
1045
+ backendDOMNodeId: node.backendDOMNodeId,
1046
+ name
1047
+ });
1048
+ break;
1049
+ }
1050
+ }
1051
+ if (candidates.length === 0) return { dismissed: false };
1052
+ const target = candidates[0];
1053
+ try {
1054
+ const { object } = await conn.send("DOM.resolveNode", { backendNodeId: target.backendDOMNodeId });
1055
+ if (object?.objectId) {
1056
+ await conn.send("Runtime.callFunctionOn", {
1057
+ objectId: object.objectId,
1058
+ functionDeclaration: "function() { this.click(); }",
1059
+ returnByValue: true
1060
+ });
1061
+ return {
1062
+ dismissed: true,
1063
+ method: "a11y",
1064
+ detail: target.name
1065
+ };
1066
+ }
1067
+ } catch {}
1068
+ return { dismissed: false };
1069
+ });
1070
+ }
916
1071
  terminate(pid) {
917
1072
  if (pid === 0) return;
918
1073
  try {
@@ -1006,6 +1161,9 @@ var MockBrowserController = class {
1006
1161
  truncated: false
1007
1162
  };
1008
1163
  }
1164
+ async dismissCookieBanner(_targetWsUrl) {
1165
+ return { dismissed: false };
1166
+ }
1009
1167
  terminate(_pid) {}
1010
1168
  closeConnection(_targetWsUrl) {}
1011
1169
  };
@@ -1222,6 +1380,10 @@ var SessionManager = class {
1222
1380
  const record = await this.ensureSession(sessionId);
1223
1381
  return await this.browser.getInteractiveElements(record.targetWsUrl, options);
1224
1382
  }
1383
+ async dismissCookieBanner(sessionId) {
1384
+ const record = await this.ensureSession(sessionId);
1385
+ return await this.browser.dismissCookieBanner(record.targetWsUrl);
1386
+ }
1225
1387
  setStatus(status, reason) {
1226
1388
  const active = this.store.getActive();
1227
1389
  if (!active) throw new Error("No active session");
@@ -1488,6 +1650,9 @@ var ControlApi = class {
1488
1650
  async getInteractiveElements(sessionId, options) {
1489
1651
  return await this.sessions.getInteractiveElements(sessionId, options);
1490
1652
  }
1653
+ async dismissCookieBanner(sessionId) {
1654
+ return await this.sessions.dismissCookieBanner(sessionId);
1655
+ }
1491
1656
  listEvents(sessionId, limit = 100) {
1492
1657
  return { events: this.eventStore.list(sessionId, limit) };
1493
1658
  }
@@ -2217,6 +2382,9 @@ var AgenticBrowserCore = class {
2217
2382
  selector: input.selector
2218
2383
  });
2219
2384
  }
2385
+ async dismissCookieBanner(sessionId) {
2386
+ return await this.api.dismissCookieBanner(sessionId);
2387
+ }
2220
2388
  async restartSession(sessionId) {
2221
2389
  return await this.api.restartSession(sessionId);
2222
2390
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-browser",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",