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.
package/dist/cli/index.mjs
CHANGED
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-
|
|
2
|
+
import { i as createMockAgenticBrowserCore, n as createAgenticBrowserCore, t as AgenticBrowserCore } from "./runtime-C7B024bN.mjs";
|
|
3
3
|
|
|
4
4
|
export { AgenticBrowserCore, createAgenticBrowserCore, createMockAgenticBrowserCore };
|
package/dist/mcp/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as createAgenticBrowserCore } from "../runtime-
|
|
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
|
}
|