@agenttool/browser 0.1.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.
Files changed (45) hide show
  1. package/CLAUDE.md +66 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +4 -0
  4. package/README.md +295 -0
  5. package/dist/bin/agenttool-browser.d.ts +3 -0
  6. package/dist/bin/agenttool-browser.d.ts.map +1 -0
  7. package/dist/bin/agenttool-browser.js +11 -0
  8. package/dist/bin/agenttool-browser.js.map +1 -0
  9. package/dist/src/browser.d.ts +56 -0
  10. package/dist/src/browser.d.ts.map +1 -0
  11. package/dist/src/browser.js +1354 -0
  12. package/dist/src/browser.js.map +1 -0
  13. package/dist/src/cli.d.ts +33 -0
  14. package/dist/src/cli.d.ts.map +1 -0
  15. package/dist/src/cli.js +447 -0
  16. package/dist/src/cli.js.map +1 -0
  17. package/dist/src/config.d.ts +40 -0
  18. package/dist/src/config.d.ts.map +1 -0
  19. package/dist/src/config.js +219 -0
  20. package/dist/src/config.js.map +1 -0
  21. package/dist/src/errors.d.ts +11 -0
  22. package/dist/src/errors.d.ts.map +1 -0
  23. package/dist/src/errors.js +20 -0
  24. package/dist/src/errors.js.map +1 -0
  25. package/dist/src/index.d.ts +16 -0
  26. package/dist/src/index.d.ts.map +1 -0
  27. package/dist/src/index.js +9 -0
  28. package/dist/src/index.js.map +1 -0
  29. package/dist/src/mcp.d.ts +76 -0
  30. package/dist/src/mcp.d.ts.map +1 -0
  31. package/dist/src/mcp.js +408 -0
  32. package/dist/src/mcp.js.map +1 -0
  33. package/dist/src/policy.d.ts +49 -0
  34. package/dist/src/policy.d.ts.map +1 -0
  35. package/dist/src/policy.js +315 -0
  36. package/dist/src/policy.js.map +1 -0
  37. package/dist/src/snapshot.d.ts +45 -0
  38. package/dist/src/snapshot.d.ts.map +1 -0
  39. package/dist/src/snapshot.js +184 -0
  40. package/dist/src/snapshot.js.map +1 -0
  41. package/dist/src/types.d.ts +352 -0
  42. package/dist/src/types.d.ts.map +1 -0
  43. package/dist/src/types.js +2 -0
  44. package/dist/src/types.js.map +1 -0
  45. package/package.json +70 -0
@@ -0,0 +1,315 @@
1
+ import { lookup } from "node:dns/promises";
2
+ import { isIP } from "node:net";
3
+ import { BrowserError } from "./errors.js";
4
+ export async function defaultResolveHostname(hostname) {
5
+ return lookup(hostname, { all: true, verbatim: true });
6
+ }
7
+ /**
8
+ * Construction-fixed navigation policy.
9
+ *
10
+ * DNS checks are a useful local safety boundary, not an SSRF sandbox. Chromium
11
+ * performs its own DNS resolution after this check, so DNS rebinding creates a
12
+ * time-of-check/time-of-use gap and the connected address is not pinned.
13
+ */
14
+ export class BrowserNetworkPolicy {
15
+ boundary;
16
+ allowPublicWeb;
17
+ allowLocalNetwork;
18
+ resolveHostname;
19
+ constructor(options = {}) {
20
+ this.allowPublicWeb = options.allowPublicWeb ?? true;
21
+ this.allowLocalNetwork = options.allowLocalNetwork ?? false;
22
+ this.resolveHostname = options.resolveHostname ?? defaultResolveHostname;
23
+ this.boundary = Object.freeze({
24
+ mode: "local_browser_public_web",
25
+ publicWeb: this.allowPublicWeb,
26
+ localNetwork: this.allowLocalNetwork,
27
+ schemes: Object.freeze(["http", "https"]),
28
+ urlCredentials: "blocked",
29
+ dnsPreflight: true,
30
+ connectionAddressPinning: false,
31
+ webSockets: "blocked",
32
+ statement: "HTTP(S) destinations are checked before browser requests; DNS preflight does not pin Chromium's connected address.",
33
+ });
34
+ }
35
+ async assertAllowed(input) {
36
+ const url = parseBrowserUrl(input);
37
+ const hostname = normalizeHostname(url.hostname);
38
+ const namedClass = classifySpecialHostname(hostname);
39
+ if (namedClass) {
40
+ this.assertClassAllowed(namedClass);
41
+ return url;
42
+ }
43
+ if (isIP(hostname) !== 0) {
44
+ this.assertClassAllowed(classifyIpAddress(hostname));
45
+ return url;
46
+ }
47
+ let addresses;
48
+ try {
49
+ addresses = await this.resolveHostname(hostname);
50
+ }
51
+ catch (error) {
52
+ throw new BrowserError("dns_failed", "Browser policy could not resolve the destination.", { cause: error });
53
+ }
54
+ if (addresses.length === 0) {
55
+ throw new BrowserError("dns_failed", "Browser policy could not resolve the destination.");
56
+ }
57
+ for (const address of addresses) {
58
+ this.assertClassAllowed(classifyIpAddress(address.address));
59
+ }
60
+ return url;
61
+ }
62
+ assertClassAllowed(destination) {
63
+ if (destination === "reserved") {
64
+ throw new BrowserError("network_blocked", "Browser policy blocks reserved network destinations.");
65
+ }
66
+ if (destination === "local" && !this.allowLocalNetwork) {
67
+ throw new BrowserError("network_blocked", "Browser policy blocks localhost and private network destinations by default.");
68
+ }
69
+ if (destination === "public" && !this.allowPublicWeb) {
70
+ throw new BrowserError("network_blocked", "Browser policy does not permit public web destinations.");
71
+ }
72
+ }
73
+ }
74
+ export function parseBrowserUrl(input) {
75
+ let url;
76
+ try {
77
+ url = input instanceof URL ? new URL(input.href) : new URL(input);
78
+ }
79
+ catch (error) {
80
+ throw new BrowserError("invalid_url", "URL must be absolute.", { cause: error });
81
+ }
82
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
83
+ throw new BrowserError("url_scheme_blocked", "Browser navigation only permits http: and https: URLs.");
84
+ }
85
+ if (url.username || url.password) {
86
+ throw new BrowserError("url_credentials_blocked", "Credentials are not permitted in browser URLs.");
87
+ }
88
+ return url;
89
+ }
90
+ /**
91
+ * Redact query values at every structured URL boundary. Paths, fragments, and
92
+ * screenshot pixels are outside this filter; free-form text has a separate
93
+ * URL sanitizer.
94
+ */
95
+ export function redactUrlForOutput(input) {
96
+ let url;
97
+ try {
98
+ url = new URL(input);
99
+ }
100
+ catch {
101
+ return input;
102
+ }
103
+ url.username = "";
104
+ url.password = "";
105
+ if (url.search) {
106
+ const redacted = new URLSearchParams();
107
+ for (const [name] of url.searchParams)
108
+ redacted.append(name, "[redacted]");
109
+ url.search = redacted.toString();
110
+ }
111
+ return url.href;
112
+ }
113
+ export function redactUrlsInText(input) {
114
+ return input.replace(/https?:\/\/[^\s<>"'`]+/gi, (candidate) => {
115
+ const trailing = candidate.match(/[),.;!?]+$/)?.[0] ?? "";
116
+ const url = trailing ? candidate.slice(0, -trailing.length) : candidate;
117
+ return `${redactUrlForOutput(url)}${trailing}`;
118
+ });
119
+ }
120
+ export function redactHtmlUrlAttributes(input) {
121
+ return input.replace(/(\s+(?:href|src|action|formaction|poster)\s*=\s*)("[^"]*"|'[^']*'|[^\s>]+)/gi, (_match, prefix, encodedValue) => {
122
+ const quote = encodedValue.startsWith('"') || encodedValue.startsWith("'")
123
+ ? encodedValue[0]
124
+ : "";
125
+ const value = quote ? encodedValue.slice(1, -1) : encodedValue;
126
+ return `${prefix}${quote}${redactUrlReferenceForOutput(value)}${quote}`;
127
+ });
128
+ }
129
+ /** Redact query values while preserving an absolute, protocol-relative, or relative reference. */
130
+ export function redactUrlReferenceForOutput(input) {
131
+ if (/^[a-z][a-z0-9+.-]*:/i.test(input))
132
+ return redactUrlForOutput(input);
133
+ if (input.startsWith("//")) {
134
+ try {
135
+ const redacted = new URL(redactUrlForOutput(`https:${input}`));
136
+ return `//${redacted.host}${redacted.pathname}${redacted.search}${redacted.hash}`;
137
+ }
138
+ catch {
139
+ // Fall through to the query-only redactor.
140
+ }
141
+ }
142
+ const queryStart = input.indexOf("?");
143
+ if (queryStart < 0)
144
+ return input;
145
+ const fragmentStart = input.indexOf("#", queryStart);
146
+ const queryEnd = fragmentStart < 0 ? input.length : fragmentStart;
147
+ const query = input.slice(queryStart + 1, queryEnd);
148
+ const redacted = new URLSearchParams();
149
+ for (const [name] of new URLSearchParams(query)) {
150
+ redacted.append(name, "[redacted]");
151
+ }
152
+ return (`${input.slice(0, queryStart)}?${redacted.toString()}`
153
+ + (fragmentStart < 0 ? "" : input.slice(fragmentStart)));
154
+ }
155
+ export function classifyIpAddress(address) {
156
+ const normalized = address.toLowerCase().split("%", 1)[0];
157
+ if (isIP(normalized) === 4)
158
+ return classifyIpv4(normalized);
159
+ if (isIP(normalized) === 6)
160
+ return classifyIpv6(normalized);
161
+ return "reserved";
162
+ }
163
+ export function isPrivateOrReservedAddress(address) {
164
+ return classifyIpAddress(address) !== "public";
165
+ }
166
+ function normalizeHostname(hostname) {
167
+ return hostname
168
+ .replace(/^\[|\]$/g, "")
169
+ .replace(/\.$/, "")
170
+ .toLowerCase();
171
+ }
172
+ function classifySpecialHostname(hostname) {
173
+ if (hostname === "localhost"
174
+ || hostname.endsWith(".localhost")
175
+ || hostname === "local"
176
+ || hostname.endsWith(".local")
177
+ || hostname === "home.arpa"
178
+ || hostname.endsWith(".home.arpa")
179
+ || hostname === "internal"
180
+ || hostname.endsWith(".internal")) {
181
+ return "local";
182
+ }
183
+ if (hostname === "test"
184
+ || hostname.endsWith(".test")
185
+ || hostname === "invalid"
186
+ || hostname.endsWith(".invalid")
187
+ || hostname === "example"
188
+ || hostname.endsWith(".example")
189
+ || hostname === "onion"
190
+ || hostname.endsWith(".onion")) {
191
+ return "reserved";
192
+ }
193
+ return null;
194
+ }
195
+ function classifyIpv4(address) {
196
+ const parts = address.split(".").map(Number);
197
+ const [a, b, c] = parts;
198
+ if (a === undefined || b === undefined || c === undefined)
199
+ return "reserved";
200
+ if (a === 10
201
+ || a === 127
202
+ || (a === 100 && b >= 64 && b <= 127)
203
+ || (a === 169 && b === 254)
204
+ || (a === 172 && b >= 16 && b <= 31)
205
+ || (a === 192 && b === 168)) {
206
+ return "local";
207
+ }
208
+ if (a === 0
209
+ || (a === 192 && b === 0)
210
+ || (a === 192 && b === 88 && c === 99)
211
+ || (a === 198 && (b === 18 || b === 19))
212
+ || (a === 198 && b === 51 && c === 100)
213
+ || (a === 203 && b === 0 && c === 113)
214
+ || a >= 224) {
215
+ return "reserved";
216
+ }
217
+ return "public";
218
+ }
219
+ function classifyIpv6(address) {
220
+ const bytes = parseIpv6(address);
221
+ if (!bytes)
222
+ return "reserved";
223
+ if (bytes.every((byte) => byte === 0))
224
+ return "local";
225
+ if (bytes.slice(0, 15).every((byte) => byte === 0) && bytes[15] === 1) {
226
+ return "local";
227
+ }
228
+ if ((bytes[0] & 0xfe) === 0xfc)
229
+ return "local";
230
+ if (bytes[0] === 0xfe && (bytes[1] & 0xc0) === 0x80)
231
+ return "local";
232
+ if (bytes[0] === 0xfe && (bytes[1] & 0xc0) === 0xc0)
233
+ return "local";
234
+ if (bytes[0] === 0xff)
235
+ return "reserved";
236
+ if (bytes[0] === 0x20
237
+ && bytes[1] === 0x01
238
+ && bytes[2] === 0x0d
239
+ && bytes[3] === 0xb8) {
240
+ return "reserved";
241
+ }
242
+ const firstTenZero = bytes.slice(0, 10).every((byte) => byte === 0);
243
+ if (firstTenZero && bytes[10] === 0xff && bytes[11] === 0xff) {
244
+ return classifyEmbeddedIpv4(bytes, 12);
245
+ }
246
+ const firstTwelveZero = bytes.slice(0, 12).every((byte) => byte === 0);
247
+ if (firstTwelveZero)
248
+ return classifyEmbeddedIpv4(bytes, 12);
249
+ const nat64 = bytes[0] === 0x00
250
+ && bytes[1] === 0x64
251
+ && bytes[2] === 0xff
252
+ && bytes[3] === 0x9b
253
+ && bytes.slice(4, 12).every((byte) => byte === 0);
254
+ if (nat64)
255
+ return classifyEmbeddedIpv4(bytes, 12);
256
+ const sixToFour = bytes[0] === 0x20 && bytes[1] === 0x02;
257
+ if (sixToFour)
258
+ return classifyEmbeddedIpv4(bytes, 2);
259
+ // IANA protocol assignments, benchmarking/ORCHID ranges and documentation
260
+ // prefixes are not ordinary global-unicast destinations.
261
+ const protocolAssignments = bytes[0] === 0x20
262
+ && bytes[1] === 0x01
263
+ && bytes[2] <= 0x01;
264
+ const documentation3fff = bytes[0] === 0x3f
265
+ && bytes[1] === 0xff
266
+ && (bytes[2] & 0xf0) === 0;
267
+ if (protocolAssignments || documentation3fff)
268
+ return "reserved";
269
+ // Only 2000::/3 can be globally routed. All other special-purpose IPv6
270
+ // space remains denied even when local-network access is opted in.
271
+ return (bytes[0] & 0xe0) === 0x20 ? "public" : "reserved";
272
+ }
273
+ function classifyEmbeddedIpv4(bytes, offset) {
274
+ return classifyIpv4(`${bytes[offset]}.${bytes[offset + 1]}.${bytes[offset + 2]}.${bytes[offset + 3]}`);
275
+ }
276
+ function parseIpv6(address) {
277
+ let input = address;
278
+ if (input.includes(".")) {
279
+ const separator = input.lastIndexOf(":");
280
+ const ipv4 = input.slice(separator + 1).split(".").map(Number);
281
+ if (separator < 0
282
+ || ipv4.length !== 4
283
+ || ipv4.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) {
284
+ return null;
285
+ }
286
+ input =
287
+ `${input.slice(0, separator)}`
288
+ + `:${((ipv4[0] << 8) | ipv4[1]).toString(16)}`
289
+ + `:${((ipv4[2] << 8) | ipv4[3]).toString(16)}`;
290
+ }
291
+ const halves = input.split("::");
292
+ if (halves.length > 2)
293
+ return null;
294
+ const left = halves[0] ? halves[0].split(":") : [];
295
+ const right = halves.length === 2 && halves[1] ? halves[1].split(":") : [];
296
+ const missing = 8 - left.length - right.length;
297
+ if ((halves.length === 1 && missing !== 0)
298
+ || (halves.length === 2 && missing < 1)) {
299
+ return null;
300
+ }
301
+ const groups = [...left, ...Array.from({ length: missing }, () => "0"), ...right];
302
+ if (groups.length !== 8)
303
+ return null;
304
+ const bytes = new Uint8Array(16);
305
+ for (let index = 0; index < groups.length; index += 1) {
306
+ const group = groups[index];
307
+ if (!/^[a-f0-9]{1,4}$/.test(group))
308
+ return null;
309
+ const value = Number.parseInt(group, 16);
310
+ bytes[index * 2] = value >> 8;
311
+ bytes[index * 2 + 1] = value & 0xff;
312
+ }
313
+ return bytes;
314
+ }
315
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import type { BoundingBox, BrowserViewport, SnapshotRef } from "./types.js";
2
+ export interface AriaCandidate {
3
+ nativeRef: string;
4
+ role: string;
5
+ name: string | null;
6
+ line: string;
7
+ }
8
+ export interface CompactAriaSnapshotOptions {
9
+ publicRefs: ReadonlyMap<string, string>;
10
+ visibleRefs: ReadonlySet<string>;
11
+ secretRefs?: ReadonlySet<string>;
12
+ maxChars: number;
13
+ maxElements: number;
14
+ }
15
+ export interface CompactAriaSnapshotResult {
16
+ snapshot: string;
17
+ refs: SnapshotRef[];
18
+ truncated: {
19
+ snapshot: boolean;
20
+ elements: boolean;
21
+ };
22
+ }
23
+ export declare function parseAriaCandidates(snapshot: string): AriaCandidate[];
24
+ export declare function compactAriaSnapshot(rawSnapshot: string, options: CompactAriaSnapshotOptions): CompactAriaSnapshotResult;
25
+ /**
26
+ * Defense-in-depth sanitizer for raw AI-mode snapshots. The compact snapshot
27
+ * path also redacts while rewriting refs, so callers never receive a password
28
+ * value even if Playwright includes it after the textbox node.
29
+ */
30
+ export declare function redactAriaSecrets(snapshot: string, secretRefs: ReadonlySet<string>): string;
31
+ export declare function looksLikeSensitiveControl(attributes: Readonly<Record<string, string | null>>, accessibleName: string | null): boolean;
32
+ export declare function intersectsViewport(box: BoundingBox | null, viewport: BrowserViewport): boolean;
33
+ export declare function boundText(value: string, maxChars: number): {
34
+ value: string;
35
+ truncated: boolean;
36
+ };
37
+ /**
38
+ * HTML extraction cannot be a general secret detector, but values on inputs
39
+ * carrying the same recognized password/secret hints as observations are
40
+ * removed before returning markup.
41
+ */
42
+ export declare function redactSensitiveInputValues(html: string): string;
43
+ /** Backwards-compatible narrow name; now covers every recognized secret hint. */
44
+ export declare function redactPasswordValues(html: string): string;
45
+ //# sourceMappingURL=snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../src/snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA0B5E,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,SAAS,EAAE;QACT,QAAQ,EAAE,OAAO,CAAC;QAClB,QAAQ,EAAE,OAAO,CAAC;KACnB,CAAC;CACH;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,EAAE,CAwBrE;AAED,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,0BAA0B,GAClC,yBAAyB,CAgD3B;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,GAC9B,MAAM,CAUR;AAED,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,EACnD,cAAc,EAAE,MAAM,GAAG,IAAI,GAC5B,OAAO,CAiBT;AAED,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,WAAW,GAAG,IAAI,EACvB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAQT;AAED,wBAAgB,SAAS,CACvB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAGvC;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgB/D;AAED,iFAAiF;AACjF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD"}
@@ -0,0 +1,184 @@
1
+ const INTERACTIVE_ROLES = new Set([
2
+ "button",
3
+ "checkbox",
4
+ "combobox",
5
+ "gridcell",
6
+ "link",
7
+ "listbox",
8
+ "menuitem",
9
+ "menuitemcheckbox",
10
+ "menuitemradio",
11
+ "option",
12
+ "radio",
13
+ "searchbox",
14
+ "slider",
15
+ "spinbutton",
16
+ "switch",
17
+ "tab",
18
+ "textbox",
19
+ "treeitem",
20
+ ]);
21
+ const SENSITIVE_HINT = /\b(?:password|passwd|passcode|pin|secret|token|api[\s_-]*key|private[\s_-]*key|cvv|cvc)\b/i;
22
+ export function parseAriaCandidates(snapshot) {
23
+ const candidates = [];
24
+ const seen = new Set();
25
+ for (const rawLine of snapshot.split(/\r?\n/)) {
26
+ const refMatch = rawLine.match(/\[ref=([A-Za-z0-9_-]+)\]/);
27
+ const roleMatch = rawLine.match(/^\s*-\s+([a-z][a-z0-9_-]*)\b/i);
28
+ if (!refMatch?.[1] || !roleMatch?.[1])
29
+ continue;
30
+ const nativeRef = refMatch[1];
31
+ const role = roleMatch[1].toLowerCase();
32
+ if (seen.has(nativeRef)
33
+ || (!INTERACTIVE_ROLES.has(role) && !rawLine.includes("[cursor=pointer]"))) {
34
+ continue;
35
+ }
36
+ seen.add(nativeRef);
37
+ candidates.push({
38
+ nativeRef,
39
+ role,
40
+ name: parseAccessibleName(rawLine),
41
+ line: rawLine.trim().replace(/^-\s*/, "- "),
42
+ });
43
+ }
44
+ return candidates;
45
+ }
46
+ export function compactAriaSnapshot(rawSnapshot, options) {
47
+ const secretRefs = options.secretRefs ?? new Set();
48
+ const eligible = parseAriaCandidates(rawSnapshot).filter((candidate) => options.visibleRefs.has(candidate.nativeRef)
49
+ && options.publicRefs.has(candidate.nativeRef));
50
+ const refs = [];
51
+ const lines = [];
52
+ let usedChars = 0;
53
+ let snapshotTruncated = false;
54
+ for (const candidate of eligible) {
55
+ if (refs.length >= options.maxElements)
56
+ break;
57
+ const publicRef = options.publicRefs.get(candidate.nativeRef);
58
+ const secret = secretRefs.has(candidate.nativeRef);
59
+ let line = candidate.line.replace(`[ref=${candidate.nativeRef}]`, `[ref=${publicRef}]`);
60
+ if (secret)
61
+ line = redactLineValue(line, publicRef);
62
+ const addition = (lines.length === 0 ? 0 : 1) + line.length;
63
+ if (usedChars + addition > options.maxChars) {
64
+ snapshotTruncated = true;
65
+ break;
66
+ }
67
+ lines.push(line);
68
+ usedChars += addition;
69
+ refs.push({
70
+ ref: publicRef,
71
+ role: candidate.role,
72
+ name: candidate.name,
73
+ secret,
74
+ });
75
+ }
76
+ const elementsTruncated = eligible.length > refs.length;
77
+ if (elementsTruncated && refs.length >= options.maxElements) {
78
+ snapshotTruncated = true;
79
+ }
80
+ const empty = "(no viewport-visible interactive elements)";
81
+ return {
82
+ snapshot: lines.join("\n") || empty.slice(0, options.maxChars),
83
+ refs,
84
+ truncated: {
85
+ snapshot: snapshotTruncated,
86
+ elements: elementsTruncated,
87
+ },
88
+ };
89
+ }
90
+ /**
91
+ * Defense-in-depth sanitizer for raw AI-mode snapshots. The compact snapshot
92
+ * path also redacts while rewriting refs, so callers never receive a password
93
+ * value even if Playwright includes it after the textbox node.
94
+ */
95
+ export function redactAriaSecrets(snapshot, secretRefs) {
96
+ return snapshot
97
+ .split(/\r?\n/)
98
+ .map((line) => {
99
+ for (const ref of secretRefs) {
100
+ if (line.includes(`[ref=${ref}]`))
101
+ return redactLineValue(line, ref);
102
+ }
103
+ return line;
104
+ })
105
+ .join("\n");
106
+ }
107
+ export function looksLikeSensitiveControl(attributes, accessibleName) {
108
+ if ((attributes.type ?? "").toLowerCase() === "password")
109
+ return true;
110
+ const autocomplete = (attributes.autocomplete ?? "").toLowerCase();
111
+ if (autocomplete.includes("current-password")
112
+ || autocomplete.includes("new-password")
113
+ || autocomplete.includes("one-time-code")) {
114
+ return true;
115
+ }
116
+ return [
117
+ accessibleName,
118
+ attributes.name,
119
+ attributes.id,
120
+ attributes.placeholder,
121
+ attributes["aria-label"],
122
+ ].some((value) => value !== null && value !== undefined && SENSITIVE_HINT.test(value));
123
+ }
124
+ export function intersectsViewport(box, viewport) {
125
+ if (!box || box.width <= 0 || box.height <= 0)
126
+ return false;
127
+ return (box.x < viewport.width
128
+ && box.y < viewport.height
129
+ && box.x + box.width > 0
130
+ && box.y + box.height > 0);
131
+ }
132
+ export function boundText(value, maxChars) {
133
+ if (value.length <= maxChars)
134
+ return { value, truncated: false };
135
+ return { value: value.slice(0, maxChars), truncated: true };
136
+ }
137
+ /**
138
+ * HTML extraction cannot be a general secret detector, but values on inputs
139
+ * carrying the same recognized password/secret hints as observations are
140
+ * removed before returning markup.
141
+ */
142
+ export function redactSensitiveInputValues(html) {
143
+ return html.replace(/<input\b[^>]*>/gi, (tag) => {
144
+ const attributes = {
145
+ type: inputAttribute(tag, "type"),
146
+ autocomplete: inputAttribute(tag, "autocomplete"),
147
+ name: inputAttribute(tag, "name"),
148
+ id: inputAttribute(tag, "id"),
149
+ placeholder: inputAttribute(tag, "placeholder"),
150
+ "aria-label": inputAttribute(tag, "aria-label"),
151
+ };
152
+ if (!looksLikeSensitiveControl(attributes, null))
153
+ return tag;
154
+ return tag.replace(/(\s+value\s*=\s*)(?:"[^"]*"|'[^']*'|[^\s>]+)/i, '$1"[redacted]"');
155
+ });
156
+ }
157
+ /** Backwards-compatible narrow name; now covers every recognized secret hint. */
158
+ export function redactPasswordValues(html) {
159
+ return redactSensitiveInputValues(html);
160
+ }
161
+ function parseAccessibleName(line) {
162
+ const match = line.match(/^\s*-\s+[a-z][a-z0-9_-]*\s+"((?:[^"\\]|\\.)*)"/i);
163
+ if (!match?.[1])
164
+ return null;
165
+ try {
166
+ return JSON.parse(`"${match[1]}"`);
167
+ }
168
+ catch {
169
+ return match[1];
170
+ }
171
+ }
172
+ function redactLineValue(line, ref) {
173
+ const refEnd = line.indexOf(`[ref=${ref}]`) + `[ref=${ref}]`.length;
174
+ const valueSeparator = line.indexOf(":", refEnd);
175
+ if (valueSeparator < 0)
176
+ return line;
177
+ return `${line.slice(0, valueSeparator)}: [redacted]`;
178
+ }
179
+ function inputAttribute(tag, name) {
180
+ const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
181
+ const match = tag.match(new RegExp(`\\s+${escapedName}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s>]+))`, "i"));
182
+ return match?.[1] ?? match?.[2] ?? match?.[3] ?? null;
183
+ }
184
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/snapshot.ts"],"names":[],"mappings":"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"}