playwriter 0.0.63 → 0.0.89

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 (223) hide show
  1. package/dist/a11y-client.js +18 -8
  2. package/dist/aria-snapshot.d.ts +41 -3
  3. package/dist/aria-snapshot.d.ts.map +1 -1
  4. package/dist/aria-snapshot.js +134 -55
  5. package/dist/aria-snapshot.js.map +1 -1
  6. package/dist/aria-snapshot.test.js +5 -2
  7. package/dist/aria-snapshot.test.js.map +1 -1
  8. package/dist/aria-snapshot.unit.test.js +83 -41
  9. package/dist/aria-snapshot.unit.test.js.map +1 -1
  10. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts +5 -0
  11. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts.map +1 -0
  12. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js +5 -0
  13. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js.map +1 -0
  14. package/dist/bippy.js +1 -1
  15. package/dist/cdp-log.d.ts +1 -1
  16. package/dist/cdp-log.d.ts.map +1 -1
  17. package/dist/cdp-log.js +1 -1
  18. package/dist/cdp-log.js.map +1 -1
  19. package/dist/cdp-relay.d.ts.map +1 -1
  20. package/dist/cdp-relay.js +492 -298
  21. package/dist/cdp-relay.js.map +1 -1
  22. package/dist/cdp-session.d.ts.map +1 -1
  23. package/dist/cdp-session.js.map +1 -1
  24. package/dist/cdp-types.d.ts.map +1 -1
  25. package/dist/cdp-types.js +7 -7
  26. package/dist/cdp-types.js.map +1 -1
  27. package/dist/clean-html.d.ts.map +1 -1
  28. package/dist/clean-html.js +4 -5
  29. package/dist/clean-html.js.map +1 -1
  30. package/dist/cli.js +45 -27
  31. package/dist/cli.js.map +1 -1
  32. package/dist/create-logger.d.ts.map +1 -1
  33. package/dist/create-logger.js +3 -1
  34. package/dist/create-logger.js.map +1 -1
  35. package/dist/debugger-examples-types.d.ts.map +1 -1
  36. package/dist/debugger.d.ts.map +1 -1
  37. package/dist/debugger.js +1 -3
  38. package/dist/debugger.js.map +1 -1
  39. package/dist/diff-utils.d.ts.map +1 -1
  40. package/dist/diff-utils.js +1 -4
  41. package/dist/diff-utils.js.map +1 -1
  42. package/dist/editor-api.md +12 -2
  43. package/dist/editor-examples.d.ts +1 -1
  44. package/dist/editor-examples.d.ts.map +1 -1
  45. package/dist/editor-examples.js +1 -1
  46. package/dist/editor-examples.js.map +1 -1
  47. package/dist/editor.d.ts +1 -1
  48. package/dist/editor.d.ts.map +1 -1
  49. package/dist/editor.js +1 -1
  50. package/dist/editor.js.map +1 -1
  51. package/dist/executor.d.ts +26 -3
  52. package/dist/executor.d.ts.map +1 -1
  53. package/dist/executor.js +297 -64
  54. package/dist/executor.js.map +1 -1
  55. package/dist/executor.unit.test.js +38 -1
  56. package/dist/executor.unit.test.js.map +1 -1
  57. package/dist/extension-connection.test.js +139 -36
  58. package/dist/extension-connection.test.js.map +1 -1
  59. package/dist/ffmpeg.d.ts +148 -0
  60. package/dist/ffmpeg.d.ts.map +1 -0
  61. package/dist/ffmpeg.js +523 -0
  62. package/dist/ffmpeg.js.map +1 -0
  63. package/dist/ghost-browser.d.ts.map +1 -1
  64. package/dist/ghost-browser.js.map +1 -1
  65. package/dist/ghost-cursor-client.js +287 -0
  66. package/dist/ghost-cursor.d.ts +27 -0
  67. package/dist/ghost-cursor.d.ts.map +1 -0
  68. package/dist/ghost-cursor.js +63 -0
  69. package/dist/ghost-cursor.js.map +1 -0
  70. package/dist/htmlrewrite.d.ts.map +1 -1
  71. package/dist/htmlrewrite.js +17 -55
  72. package/dist/htmlrewrite.js.map +1 -1
  73. package/dist/htmlrewrite.test.js.map +1 -1
  74. package/dist/kill-port.d.ts.map +1 -1
  75. package/dist/kill-port.js +1 -3
  76. package/dist/kill-port.js.map +1 -1
  77. package/dist/locator-selector.test.d.ts +2 -0
  78. package/dist/locator-selector.test.d.ts.map +1 -0
  79. package/dist/locator-selector.test.js +96 -0
  80. package/dist/locator-selector.test.js.map +1 -0
  81. package/dist/mcp-client.js.map +1 -1
  82. package/dist/mcp.d.ts.map +1 -1
  83. package/dist/mcp.js +8 -3
  84. package/dist/mcp.js.map +1 -1
  85. package/dist/on-mouse-action.test.d.ts +2 -0
  86. package/dist/on-mouse-action.test.d.ts.map +1 -0
  87. package/dist/on-mouse-action.test.js +155 -0
  88. package/dist/on-mouse-action.test.js.map +1 -0
  89. package/dist/page-markdown.js +4 -4
  90. package/dist/page-markdown.js.map +1 -1
  91. package/dist/prompt.md +450 -377
  92. package/dist/protocol.d.ts +4 -0
  93. package/dist/protocol.d.ts.map +1 -1
  94. package/dist/readability.js +16 -2
  95. package/dist/recording-ghost-cursor.d.ts +41 -0
  96. package/dist/recording-ghost-cursor.d.ts.map +1 -0
  97. package/dist/recording-ghost-cursor.js +79 -0
  98. package/dist/recording-ghost-cursor.js.map +1 -0
  99. package/dist/recording-relay.d.ts.map +1 -1
  100. package/dist/recording-relay.js +8 -8
  101. package/dist/recording-relay.js.map +1 -1
  102. package/dist/relay-client.d.ts +17 -4
  103. package/dist/relay-client.d.ts.map +1 -1
  104. package/dist/relay-client.js +45 -11
  105. package/dist/relay-client.js.map +1 -1
  106. package/dist/relay-core.test.d.ts.map +1 -1
  107. package/dist/relay-core.test.js +515 -26
  108. package/dist/relay-core.test.js.map +1 -1
  109. package/dist/relay-navigation.test.d.ts.map +1 -1
  110. package/dist/relay-navigation.test.js +169 -31
  111. package/dist/relay-navigation.test.js.map +1 -1
  112. package/dist/relay-session.test.d.ts.map +1 -1
  113. package/dist/relay-session.test.js +113 -65
  114. package/dist/relay-session.test.js.map +1 -1
  115. package/dist/relay-state.d.ts +158 -0
  116. package/dist/relay-state.d.ts.map +1 -0
  117. package/dist/relay-state.js +306 -0
  118. package/dist/relay-state.js.map +1 -0
  119. package/dist/relay-state.test.d.ts +2 -0
  120. package/dist/relay-state.test.d.ts.map +1 -0
  121. package/dist/relay-state.test.js +472 -0
  122. package/dist/relay-state.test.js.map +1 -0
  123. package/dist/scoped-fs.d.ts.map +1 -1
  124. package/dist/scoped-fs.js.map +1 -1
  125. package/dist/screen-recording.d.ts +66 -4
  126. package/dist/screen-recording.d.ts.map +1 -1
  127. package/dist/screen-recording.js +150 -13
  128. package/dist/screen-recording.js.map +1 -1
  129. package/dist/screen-recording.test.d.ts +2 -0
  130. package/dist/screen-recording.test.d.ts.map +1 -0
  131. package/dist/screen-recording.test.js +102 -0
  132. package/dist/screen-recording.test.js.map +1 -0
  133. package/dist/selector-generator.js +1 -1
  134. package/dist/snapshot-tools.test.js +71 -28
  135. package/dist/snapshot-tools.test.js.map +1 -1
  136. package/dist/start-relay-server.d.ts +1 -1
  137. package/dist/start-relay-server.d.ts.map +1 -1
  138. package/dist/start-relay-server.js +1 -1
  139. package/dist/start-relay-server.js.map +1 -1
  140. package/dist/styles-api.md +8 -1
  141. package/dist/styles-examples.d.ts +1 -1
  142. package/dist/styles-examples.d.ts.map +1 -1
  143. package/dist/styles-examples.js +1 -1
  144. package/dist/styles-examples.js.map +1 -1
  145. package/dist/styles.d.ts.map +1 -1
  146. package/dist/styles.js +1 -3
  147. package/dist/styles.js.map +1 -1
  148. package/dist/test-declarations.d.ts.map +1 -1
  149. package/dist/test-utils.d.ts +1 -1
  150. package/dist/test-utils.d.ts.map +1 -1
  151. package/dist/test-utils.js +7 -5
  152. package/dist/test-utils.js.map +1 -1
  153. package/dist/utils.d.ts.map +1 -1
  154. package/dist/utils.js.map +1 -1
  155. package/dist/wait-for-page-load.d.ts.map +1 -1
  156. package/dist/wait-for-page-load.js +1 -1
  157. package/dist/wait-for-page-load.js.map +1 -1
  158. package/package.json +4 -3
  159. package/src/a11y-client.ts +5 -4
  160. package/src/aria-snapshot.test.ts +5 -2
  161. package/src/aria-snapshot.ts +306 -117
  162. package/src/aria-snapshot.unit.test.ts +199 -141
  163. package/src/aria-snapshots/github-interactive.txt +2 -0
  164. package/src/aria-snapshots/github-raw.txt +5 -1
  165. package/src/aria-snapshots/hackernews-interactive.txt +238 -241
  166. package/src/aria-snapshots/hackernews-raw.txt +265 -269
  167. package/src/assets/aria-labels-example.png +0 -0
  168. package/src/assets/aria-labels-github.png +0 -0
  169. package/src/assets/aria-labels-hacker-news.png +0 -0
  170. package/src/assets/aria-labels-old-reddit.png +0 -0
  171. package/src/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.ts +5 -0
  172. package/src/assets/cursors/screen-studio/pointer-macos-tahoe.svg +18 -0
  173. package/src/cdp-log.ts +4 -1
  174. package/src/cdp-relay.ts +1059 -737
  175. package/src/cdp-session.ts +12 -3
  176. package/src/cdp-types.ts +51 -51
  177. package/src/clean-html.ts +4 -5
  178. package/src/cli.ts +82 -55
  179. package/src/create-logger.ts +5 -3
  180. package/src/debugger-examples-types.ts +4 -1
  181. package/src/debugger.ts +1 -5
  182. package/src/diff-utils.ts +2 -5
  183. package/src/editor-examples.ts +11 -1
  184. package/src/editor.ts +10 -2
  185. package/src/executor.ts +374 -73
  186. package/src/executor.unit.test.ts +48 -1
  187. package/src/extension-connection.test.ts +612 -488
  188. package/src/ffmpeg.ts +769 -0
  189. package/src/ghost-browser.ts +4 -6
  190. package/src/ghost-cursor-client.ts +369 -0
  191. package/src/ghost-cursor.ts +110 -0
  192. package/src/htmlrewrite.test.ts +6 -2
  193. package/src/htmlrewrite.ts +348 -386
  194. package/src/kill-port.ts +1 -3
  195. package/src/locator-selector.test.ts +115 -0
  196. package/src/mcp-client.ts +1 -1
  197. package/src/mcp.ts +21 -15
  198. package/src/on-mouse-action.test.ts +196 -0
  199. package/src/page-markdown.ts +7 -7
  200. package/src/protocol.ts +73 -57
  201. package/src/recording-ghost-cursor.ts +113 -0
  202. package/src/recording-relay.ts +20 -12
  203. package/src/relay-client.ts +85 -18
  204. package/src/relay-core.test.ts +1117 -578
  205. package/src/relay-navigation.test.ts +648 -483
  206. package/src/relay-session.test.ts +984 -929
  207. package/src/relay-state.test.ts +570 -0
  208. package/src/relay-state.ts +497 -0
  209. package/src/resource.md +21 -49
  210. package/src/scoped-fs.ts +9 -3
  211. package/src/screen-recording.test.ts +111 -0
  212. package/src/screen-recording.ts +256 -31
  213. package/src/skill.md +476 -396
  214. package/src/snapshot-tools.test.ts +580 -528
  215. package/src/snapshots/shadcn-ui-accessibility-full.md +8 -8
  216. package/src/snapshots/shadcn-ui-accessibility-interactive.md +8 -8
  217. package/src/start-relay-server.ts +14 -11
  218. package/src/styles-examples.ts +8 -1
  219. package/src/styles.ts +20 -21
  220. package/src/test-declarations.ts +6 -6
  221. package/src/test-utils.ts +104 -91
  222. package/src/utils.ts +2 -1
  223. package/src/wait-for-page-load.ts +6 -1
@@ -3,27 +3,37 @@
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __moduleCache = /* @__PURE__ */ new WeakMap;
6
+ function __accessProp(key) {
7
+ return this[key];
8
+ }
7
9
  var __toCommonJS = (from) => {
8
- var entry = __moduleCache.get(from), desc;
10
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
9
11
  if (entry)
10
12
  return entry;
11
13
  entry = __defProp({}, "__esModule", { value: true });
12
- if (from && typeof from === "object" || typeof from === "function")
13
- __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
14
- get: () => from[key],
15
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
- }));
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (var key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(entry, key))
17
+ __defProp(entry, key, {
18
+ get: __accessProp.bind(from, key),
19
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
+ });
21
+ }
17
22
  __moduleCache.set(from, entry);
18
23
  return entry;
19
24
  };
25
+ var __moduleCache;
26
+ var __returnValue = (v) => v;
27
+ function __exportSetter(name, newValue) {
28
+ this[name] = __returnValue.bind(null, newValue);
29
+ }
20
30
  var __export = (target, all) => {
21
31
  for (var name in all)
22
32
  __defProp(target, name, {
23
33
  get: all[name],
24
34
  enumerable: true,
25
35
  configurable: true,
26
- set: (newValue) => all[name] = () => newValue
36
+ set: __exportSetter.bind(all, name)
27
37
  });
28
38
  };
29
39
 
@@ -26,6 +26,44 @@ export interface ScreenshotResult {
26
26
  snapshot: string;
27
27
  labelCount: number;
28
28
  }
29
+ /**
30
+ * LLM-optimal max dimension. Claude auto-resizes images larger than 1568px
31
+ * on any edge, adding latency. Token cost: (width * height) / 750.
32
+ */
33
+ export declare const LLM_MAX_DIMENSION = 1568;
34
+ export interface ResizeImageOptions {
35
+ /** Input: file path or Buffer */
36
+ input: string | Buffer;
37
+ /** Max pixels on longest edge. Default 1568 (Claude-optimal).
38
+ * Ignored if explicit width/height provided. */
39
+ maxDimension?: number;
40
+ /** Explicit target width in px (aspect ratio preserved unless both width+height set) */
41
+ width?: number;
42
+ /** Explicit target height in px */
43
+ height?: number;
44
+ /** How to fit when both width+height specified. Default 'inside' (preserve aspect ratio, no crop) */
45
+ fit?: 'inside' | 'cover' | 'contain' | 'fill';
46
+ /** JPEG quality 1-100. Default 80 */
47
+ quality?: number;
48
+ /** Output file path. Defaults to overwriting the input file (when input is a path) */
49
+ output?: string;
50
+ }
51
+ export interface ResizeImageResult {
52
+ buffer: Buffer;
53
+ mimeType: 'image/jpeg';
54
+ /** Only set if output path was provided */
55
+ path?: string;
56
+ }
57
+ /**
58
+ * Resize an image using sharp. Useful for shrinking screenshots before reading
59
+ * them back into context so they consume fewer tokens.
60
+ *
61
+ * Default behavior (no width/height): fits within 1568×1568px, preserving
62
+ * aspect ratio, never upscales. This is optimal for Claude vision.
63
+ *
64
+ * Explicit width/height: resizes to those dimensions using the fit strategy.
65
+ */
66
+ export declare function resizeImage(options: ResizeImageOptions): Promise<ResizeImageResult>;
29
67
  export interface AriaSnapshotResult {
30
68
  snapshot: string;
31
69
  tree: AriaSnapshotNode[];
@@ -140,7 +178,7 @@ export declare function finalizeSnapshotOutput(lines: SnapshotLine[], nodes: Sna
140
178
  * await page.locator(selector).click()
141
179
  * ```
142
180
  */
143
- export declare function getAriaSnapshot({ page, frame, locator, refFilter, interactiveOnly, cdp }: {
181
+ export declare function getAriaSnapshot({ page, frame, locator, refFilter, interactiveOnly, cdp, }: {
144
182
  page: Page;
145
183
  frame?: Frame | FrameLocator;
146
184
  locator?: Locator;
@@ -171,7 +209,7 @@ export declare function getAriaSnapshot({ page, frame, locator, refFilter, inter
171
209
  * await page.locator('[data-testid="submit-btn"]').click()
172
210
  * ```
173
211
  */
174
- export declare function showAriaRefLabels({ page, locator, interactiveOnly, logger }: {
212
+ export declare function showAriaRefLabels({ page, locator, interactiveOnly, logger, }: {
175
213
  page: Page;
176
214
  locator?: Locator;
177
215
  interactiveOnly?: boolean;
@@ -206,7 +244,7 @@ export declare function hideAriaRefLabels({ page }: {
206
244
  * await page.locator('[data-testid="submit-btn"]').click()
207
245
  * ```
208
246
  */
209
- export declare function screenshotWithAccessibilityLabels({ page, locator, interactiveOnly, collector, logger }: {
247
+ export declare function screenshotWithAccessibilityLabels({ page, locator, interactiveOnly, collector, logger, }: {
210
248
  page: Page;
211
249
  locator?: Locator;
212
250
  interactiveOnly?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"aria-snapshot.d.ts","sourceRoot":"","sources":["../src/aria-snapshot.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAKhG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAanD,MAAM,MAAM,cAAc,GAAG,KAAK,CAAA;AAElC,eAAO,MAAM,uBAAuB,EAAE,cAAsB,CAAA;AA8B5D,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAA;CAC3C;AAID,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAA;IAC1C,QAAQ,EAAE,gBAAgB,EAAE,CAAA;CAC7B,CAAA;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,YAAY,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,gBAAgB,EAAE,CAAA;IACxB,IAAI,EAAE,OAAO,EAAE,CAAA;IACf,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC3E,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC;;;;OAIG;IACH,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;IACjD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,GAAG,aAAa,CAAC,KAAK,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAA;IAChG,gBAAgB,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAA;IAC/E,sBAAsB,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;CACrF;AAeD,wBAAgB,gBAAgB,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAMhG;AAkED,KAAK,WAAW,GAAG;IACjB,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAA;IAC3B,QAAQ,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAA;IAC9B,aAAa,EAAE,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAA;IACzC,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAChC,CAAA;AA0ED,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,aAAa,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAA;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,YAAY,EAAE,CAAA;CACzB,CAAA;AAwBD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,MAAM,SAAI,GAAG,YAAY,EAAE,CAcpF;AAQD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE;IAC5C,MAAM,EAAE,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAA;IACvC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAA;IAC3E,aAAa,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,MAAM,KAAK,OAAO,CAAA;CAChE,GAAG,YAAY,GAAG,IAAI,CA4BtB;AAED,wBAAgB,6BAA6B,CAAC,OAAO,EAAE;IACrD,IAAI,EAAE,YAAY,CAAA;IAClB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAA;IAC9D,cAAc,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,aAAa,EAAE,WAAW,CAAC,CAAA;IAC5D,gBAAgB,EAAE,CAAC,OAAO,EAAE;QAAE,aAAa,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,GAAG,IAAI,CAAA;CACzH,GAAG;IAAE,KAAK,EAAE,YAAY,EAAE,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,CAqGhD;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE;IAC9C,IAAI,EAAE,YAAY,CAAA;IAClB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAA;IAC9D,cAAc,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,aAAa,EAAE,WAAW,CAAC,CAAA;IAC5D,gBAAgB,EAAE,CAAC,OAAO,EAAE;QAAE,aAAa,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,GAAG,IAAI,CAAA;CACzH,GAAG;IAAE,KAAK,EAAE,YAAY,EAAE,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,CAsFhD;AAuBD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,YAAY,EAAE,EACrB,KAAK,EAAE,YAAY,EAAE,EACrB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAsDhD;AA2HD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,eAAe,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,eAAuB,EAAE,GAAG,EAAE,EAAE;IACvG,IAAI,EAAE,IAAI,CAAA;IACV,KAAK,CAAC,EAAE,KAAK,GAAG,YAAY,CAAA;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAA;IAC7D,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,GAAG,CAAC,EAAE,WAAW,CAAA;CAClB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAqT9B;AA+FD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,eAAsB,EAAE,MAAM,EAAE,EAAE;IACzF,IAAI,EAAE,IAAI,CAAA;IACV,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAA;CACvF,GAAG,OAAO,CAAC;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAC,CA0DD;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB/E;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,iCAAiC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,eAAsB,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE;IACpH,IAAI,EAAE,IAAI,CAAA;IACV,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,SAAS,EAAE,gBAAgB,EAAE,CAAA;IAC7B,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAA;CACvF,GAAG,OAAO,CAAC,IAAI,CAAC,CAyFhB;AAGD,OAAO,EAAE,eAAe,IAAI,uBAAuB,EAAE,CAAA"}
1
+ {"version":3,"file":"aria-snapshot.d.ts","sourceRoot":"","sources":["../src/aria-snapshot.ts"],"names":[],"mappings":"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"}
@@ -6,8 +6,12 @@ import { Sema } from 'async-sema';
6
6
  import { getCDPSessionForPage } from './cdp-session.js';
7
7
  // Import sharp at module level - resolves to null if not available
8
8
  const sharpPromise = import('sharp')
9
- .then((m) => { return m.default; })
10
- .catch(() => { return null; });
9
+ .then((m) => {
10
+ return m.default;
11
+ })
12
+ .catch(() => {
13
+ return null;
14
+ });
11
15
  export const DEFAULT_SNAPSHOT_FORMAT = 'raw';
12
16
  // ============================================================================
13
17
  // A11y Client Code Loading
@@ -29,6 +33,78 @@ async function ensureA11yClient(page) {
29
33
  await page.evaluate(code);
30
34
  }
31
35
  }
36
+ // ============================================================================
37
+ // Image Resize Utility
38
+ // ============================================================================
39
+ /**
40
+ * LLM-optimal max dimension. Claude auto-resizes images larger than 1568px
41
+ * on any edge, adding latency. Token cost: (width * height) / 750.
42
+ */
43
+ export const LLM_MAX_DIMENSION = 1568;
44
+ /**
45
+ * Resize an image using sharp. Useful for shrinking screenshots before reading
46
+ * them back into context so they consume fewer tokens.
47
+ *
48
+ * Default behavior (no width/height): fits within 1568×1568px, preserving
49
+ * aspect ratio, never upscales. This is optimal for Claude vision.
50
+ *
51
+ * Explicit width/height: resizes to those dimensions using the fit strategy.
52
+ */
53
+ export async function resizeImage(options) {
54
+ const sharp = await sharpPromise;
55
+ if (!sharp) {
56
+ throw new Error('sharp is not installed — install it with: pnpm add sharp');
57
+ }
58
+ const inputBuffer = (() => {
59
+ if (Buffer.isBuffer(options.input)) {
60
+ return options.input;
61
+ }
62
+ return fs.readFileSync(options.input);
63
+ })();
64
+ const quality = options.quality ?? 80;
65
+ const hasExplicitDimensions = options.width !== undefined || options.height !== undefined;
66
+ const fit = options.fit ?? 'inside';
67
+ const resizeOpts = (() => {
68
+ if (hasExplicitDimensions) {
69
+ return {
70
+ width: options.width,
71
+ height: options.height,
72
+ fit,
73
+ withoutEnlargement: false,
74
+ };
75
+ }
76
+ const max = options.maxDimension ?? LLM_MAX_DIMENSION;
77
+ return {
78
+ width: max,
79
+ height: max,
80
+ fit,
81
+ withoutEnlargement: true,
82
+ };
83
+ })();
84
+ const buffer = await sharp(inputBuffer)
85
+ .resize(resizeOpts)
86
+ .jpeg({ quality })
87
+ .toBuffer();
88
+ // Default: overwrite input file. When input is a Buffer, no file is written
89
+ // unless output is explicitly set.
90
+ const outputPath = (() => {
91
+ if (options.output) {
92
+ return options.output;
93
+ }
94
+ if (typeof options.input === 'string') {
95
+ return options.input;
96
+ }
97
+ return undefined;
98
+ })();
99
+ if (outputPath) {
100
+ fs.writeFileSync(outputPath, buffer);
101
+ }
102
+ return {
103
+ buffer,
104
+ mimeType: 'image/jpeg',
105
+ ...(outputPath ? { path: outputPath } : {}),
106
+ };
107
+ }
32
108
  export function buildShortRefMap({ refs }) {
33
109
  const map = new Map();
34
110
  refs.forEach((entry, index) => {
@@ -58,9 +134,7 @@ const INTERACTIVE_ROLES = new Set([
58
134
  'video',
59
135
  'audio',
60
136
  ]);
61
- const LABEL_ROLES = new Set([
62
- 'labeltext',
63
- ]);
137
+ const LABEL_ROLES = new Set(['labeltext']);
64
138
  const MAX_LABEL_POSITION_CONCURRENCY = 24;
65
139
  const BOX_MODEL_TIMEOUT_MS = 5000;
66
140
  const CONTEXT_ROLES = new Set([
@@ -78,12 +152,7 @@ const CONTEXT_ROLES = new Set([
78
152
  'row',
79
153
  'cell',
80
154
  ]);
81
- const SKIP_WRAPPER_ROLES = new Set([
82
- 'generic',
83
- 'group',
84
- 'none',
85
- 'presentation',
86
- ]);
155
+ const SKIP_WRAPPER_ROLES = new Set(['generic', 'group', 'none', 'presentation']);
87
156
  const TEST_ID_ATTRS = [
88
157
  'data-testid',
89
158
  'data-test-id',
@@ -130,7 +199,7 @@ function buildLocatorFromStable(stable) {
130
199
  const escaped = escapeLocatorValue(stable.value);
131
200
  return `[${stable.attr}="${escaped}"]`;
132
201
  }
133
- function buildBaseLocator({ role, name, stable }) {
202
+ function buildBaseLocator({ role, name, stable, }) {
134
203
  if (stable) {
135
204
  return buildLocatorFromStable(stable);
136
205
  }
@@ -158,7 +227,7 @@ function getAxRole(node) {
158
227
  const role = getAxValueString(node.role);
159
228
  return role.toLowerCase();
160
229
  }
161
- function buildSnapshotLine({ role, name, baseLocator, indent, hasChildren }) {
230
+ function buildSnapshotLine({ role, name, baseLocator, indent, hasChildren, }) {
162
231
  const prefix = ' '.repeat(indent);
163
232
  let text = `${prefix}- ${role}`;
164
233
  if (name) {
@@ -199,13 +268,15 @@ export function buildRawSnapshotTree(options) {
199
268
  }
200
269
  const role = getAxRole(node);
201
270
  const name = getAxValueString(node.name).trim();
202
- const children = (node.childIds ?? []).map((childId) => {
271
+ const children = (node.childIds ?? [])
272
+ .map((childId) => {
203
273
  return buildRawSnapshotTree({
204
274
  nodeId: childId,
205
275
  axById: options.axById,
206
276
  isNodeInScope: options.isNodeInScope,
207
277
  });
208
- }).filter(isTruthy);
278
+ })
279
+ .filter(isTruthy);
209
280
  const inScope = options.isNodeInScope(node) || children.length > 0;
210
281
  if (!inScope) {
211
282
  return null;
@@ -429,7 +500,8 @@ export function finalizeSnapshotOutput(lines, nodes, shortRefMap) {
429
500
  return acc;
430
501
  }, []);
431
502
  let lineLocatorIndex = 0;
432
- const snapshot = lines.map((line) => {
503
+ const snapshot = lines
504
+ .map((line) => {
433
505
  let text = line.text;
434
506
  if (line.baseLocator) {
435
507
  const locator = locatorSequence[lineLocatorIndex];
@@ -440,7 +512,8 @@ export function finalizeSnapshotOutput(lines, nodes, shortRefMap) {
440
512
  text += ':';
441
513
  }
442
514
  return text;
443
- }).join('\n');
515
+ })
516
+ .join('\n');
444
517
  let nodeLocatorIndex = 0;
445
518
  const applyLocators = (items) => {
446
519
  return items.map((item) => {
@@ -585,8 +658,8 @@ async function resolveFrame({ frame, page }) {
585
658
  * await page.locator(selector).click()
586
659
  * ```
587
660
  */
588
- export async function getAriaSnapshot({ page, frame, locator, refFilter, interactiveOnly = false, cdp }) {
589
- const session = cdp || await getCDPSessionForPage({ page });
661
+ export async function getAriaSnapshot({ page, frame, locator, refFilter, interactiveOnly = false, cdp, }) {
662
+ const session = cdp || (await getCDPSessionForPage({ page }));
590
663
  // Resolve FrameLocator to an actual Frame. FrameLocator (from locator.contentFrame())
591
664
  // is a scoping helper without CDP access. We need the real Frame from page.frames()
592
665
  // which has frameId() for OOPIF session attachment.
@@ -596,16 +669,16 @@ export async function getAriaSnapshot({ page, frame, locator, refFilter, interac
596
669
  let oopifSessionId = null;
597
670
  const frameId = resolvedFrame?.frameId() ?? null;
598
671
  if (frameId) {
599
- const { targetInfos } = await session.send('Target.getTargets');
672
+ const { targetInfos } = (await session.send('Target.getTargets'));
600
673
  const frameUrl = resolvedFrame.url();
601
674
  const iframeTarget = targetInfos.find((t) => {
602
675
  return t.type === 'iframe' && t.url === frameUrl;
603
676
  });
604
677
  if (iframeTarget) {
605
- const { sessionId } = await session.send('Target.attachToTarget', {
678
+ const { sessionId } = (await session.send('Target.attachToTarget', {
606
679
  targetId: iframeTarget.targetId,
607
680
  flatten: true,
608
- });
681
+ }));
609
682
  oopifSessionId = sessionId;
610
683
  await session.send('Runtime.runIfWaitingForDebugger', undefined, oopifSessionId);
611
684
  }
@@ -623,7 +696,7 @@ export async function getAriaSnapshot({ page, frame, locator, refFilter, interac
623
696
  }, { attr: scopeAttr, value: scopeValue });
624
697
  scopeApplied = true;
625
698
  }
626
- const { nodes: domNodes } = await session.send('DOM.getFlattenedDocument', { depth: -1, pierce: true }, oopifSessionId);
699
+ const { nodes: domNodes } = (await session.send('DOM.getFlattenedDocument', { depth: -1, pierce: true }, oopifSessionId));
627
700
  const { domById, domByBackendId, childrenByParent } = buildDomIndex(domNodes);
628
701
  let scopeRootNodeId = null;
629
702
  let scopeRootBackendId = null;
@@ -636,11 +709,9 @@ export async function getAriaSnapshot({ page, frame, locator, refFilter, interac
636
709
  }
637
710
  }
638
711
  }
639
- const allowedBackendIds = scopeRootNodeId
640
- ? buildBackendIdSet(scopeRootNodeId, childrenByParent, domById)
641
- : null;
712
+ const allowedBackendIds = scopeRootNodeId ? buildBackendIdSet(scopeRootNodeId, childrenByParent, domById) : null;
642
713
  const axParams = !oopifSessionId && frameId ? { frameId } : undefined;
643
- const { nodes: axNodes } = await session.send('Accessibility.getFullAXTree', axParams, oopifSessionId);
714
+ const { nodes: axNodes } = (await session.send('Accessibility.getFullAXTree', axParams, oopifSessionId));
644
715
  const axById = new Map();
645
716
  for (const node of axNodes) {
646
717
  axById.set(node.nodeId, node);
@@ -710,9 +781,11 @@ export async function getAriaSnapshot({ page, frame, locator, refFilter, interac
710
781
  const rootNode = axById.get(rootAxNodeId);
711
782
  const rootRole = rootNode ? getAxRole(rootNode) : '';
712
783
  const rawRoots = rootNode && (rootRole === 'rootwebarea' || rootRole === 'webarea') && rootNode.childIds
713
- ? rootNode.childIds.map((childId) => {
784
+ ? rootNode.childIds
785
+ .map((childId) => {
714
786
  return buildRawSnapshotTree({ nodeId: childId, axById, isNodeInScope });
715
- }).filter(isTruthy)
787
+ })
788
+ .filter(isTruthy)
716
789
  : [buildRawSnapshotTree({ nodeId: rootAxNodeId, axById, isNodeInScope })].filter(isTruthy);
717
790
  const filtered = rawRoots.flatMap((rawNode) => {
718
791
  if (interactiveOnly) {
@@ -791,7 +864,16 @@ export async function getAriaSnapshot({ page, frame, locator, refFilter, interac
791
864
  if (!target) {
792
865
  return null;
793
866
  }
794
- const testIdAttrs = ['data-testid', 'data-test-id', 'data-test', 'data-cy', 'data-pw', 'data-qa', 'data-e2e', 'data-automation-id'];
867
+ const testIdAttrs = [
868
+ 'data-testid',
869
+ 'data-test-id',
870
+ 'data-test',
871
+ 'data-cy',
872
+ 'data-pw',
873
+ 'data-qa',
874
+ 'data-e2e',
875
+ 'data-automation-id',
876
+ ];
795
877
  for (const attr of testIdAttrs) {
796
878
  const value = target.getAttribute(attr);
797
879
  if (value) {
@@ -845,7 +927,9 @@ export async function getAriaSnapshot({ page, frame, locator, refFilter, interac
845
927
  }, scopeAttr);
846
928
  }
847
929
  if (oopifSessionId) {
848
- await session.send('Target.detachFromTarget', { sessionId: oopifSessionId }).catch(() => { });
930
+ await session.send('Target.detachFromTarget', { sessionId: oopifSessionId }).catch((e) => {
931
+ console.error('[aria-snapshot] Failed to detach OOPIF session:', oopifSessionId, e);
932
+ });
849
933
  }
850
934
  if (!cdp) {
851
935
  await session.detach();
@@ -874,7 +958,7 @@ function isTruthy(value) {
874
958
  }
875
959
  async function getLabelBoxesForRefs({ page, refs, maxConcurrency = MAX_LABEL_POSITION_CONCURRENCY, logger, cdp, }) {
876
960
  const log = logger?.info ?? logger?.error ?? console.error;
877
- const session = cdp || await getCDPSessionForPage({ page });
961
+ const session = cdp || (await getCDPSessionForPage({ page }));
878
962
  const sema = new Sema(maxConcurrency);
879
963
  const labelRefs = refs.filter((ref) => {
880
964
  return Boolean(ref.backendNodeId) && INTERACTIVE_ROLES.has(ref.role);
@@ -892,9 +976,13 @@ async function getLabelBoxesForRefs({ page, refs, maxConcurrency = MAX_LABEL_POS
892
976
  await sema.acquire();
893
977
  try {
894
978
  const response = await Promise.race([
895
- session.send('DOM.getBoxModel', { backendNodeId: ref.backendNodeId }),
979
+ session.send('DOM.getBoxModel', {
980
+ backendNodeId: ref.backendNodeId,
981
+ }),
896
982
  new Promise((resolve) => {
897
- setTimeout(() => { resolve(null); }, BOX_MODEL_TIMEOUT_MS);
983
+ setTimeout(() => {
984
+ resolve(null);
985
+ }, BOX_MODEL_TIMEOUT_MS);
898
986
  }),
899
987
  ]);
900
988
  completed++;
@@ -949,7 +1037,7 @@ async function getLabelBoxesForRefs({ page, refs, maxConcurrency = MAX_LABEL_POS
949
1037
  * await page.locator('[data-testid="submit-btn"]').click()
950
1038
  * ```
951
1039
  */
952
- export async function showAriaRefLabels({ page, locator, interactiveOnly = true, logger }) {
1040
+ export async function showAriaRefLabels({ page, locator, interactiveOnly = true, logger, }) {
953
1041
  const startTime = Date.now();
954
1042
  const log = logger?.info ?? logger?.error ?? console.error;
955
1043
  log(`[showAriaRefLabels] starting...`);
@@ -984,7 +1072,8 @@ export async function showAriaRefLabels({ page, locator, interactiveOnly = true,
984
1072
  }
985
1073
  if (a11y?.computeA11ySnapshot) {
986
1074
  const rootElement = root || document.body;
987
- return a11y.computeA11ySnapshot({ root: rootElement, interactiveOnly: intOnly, renderLabels: true }).labelCount;
1075
+ return a11y.computeA11ySnapshot({ root: rootElement, interactiveOnly: intOnly, renderLabels: true })
1076
+ .labelCount;
988
1077
  }
989
1078
  throw new Error('a11y client not loaded');
990
1079
  }, { entries: shortLabels, root: rootHandle, interactiveOnly });
@@ -1035,7 +1124,7 @@ export async function hideAriaRefLabels({ page }) {
1035
1124
  * await page.locator('[data-testid="submit-btn"]').click()
1036
1125
  * ```
1037
1126
  */
1038
- export async function screenshotWithAccessibilityLabels({ page, locator, interactiveOnly = true, collector, logger }) {
1127
+ export async function screenshotWithAccessibilityLabels({ page, locator, interactiveOnly = true, collector, logger, }) {
1039
1128
  const log = logger?.info ?? logger?.error;
1040
1129
  const showLabelsStart = Date.now();
1041
1130
  const { snapshot, labelCount } = await showAriaRefLabels({ page, locator, interactiveOnly, logger });
@@ -1053,15 +1142,12 @@ export async function screenshotWithAccessibilityLabels({ page, locator, interac
1053
1142
  }
1054
1143
  const screenshotPath = path.join(tmpDir, filename);
1055
1144
  // Get viewport size to clip screenshot to visible area
1056
- const viewport = await page.evaluate('({ width: window.innerWidth, height: window.innerHeight })');
1057
- // Max 1568px on any edge (larger gets auto-resized by Claude, adding latency)
1058
- // Token formula: tokens = (width * height) / 750
1059
- const MAX_DIMENSION = 1568;
1145
+ const viewport = (await page.evaluate('({ width: window.innerWidth, height: window.innerHeight })'));
1060
1146
  // Check if sharp is available for resizing
1061
1147
  const sharp = await sharpPromise;
1062
- // Clip dimensions: if sharp unavailable, limit capture area to MAX_DIMENSION
1063
- const clipWidth = sharp ? viewport.width : Math.min(viewport.width, MAX_DIMENSION);
1064
- const clipHeight = sharp ? viewport.height : Math.min(viewport.height, MAX_DIMENSION);
1148
+ // Clip dimensions: if sharp unavailable, limit capture area to LLM_MAX_DIMENSION
1149
+ const clipWidth = sharp ? viewport.width : Math.min(viewport.width, LLM_MAX_DIMENSION);
1150
+ const clipHeight = sharp ? viewport.height : Math.min(viewport.height, LLM_MAX_DIMENSION);
1065
1151
  // Take viewport screenshot with scale: 'css' to ignore device pixel ratio
1066
1152
  const screenshotStart = Date.now();
1067
1153
  const rawBuffer = await page.screenshot({
@@ -1073,23 +1159,16 @@ export async function screenshotWithAccessibilityLabels({ page, locator, interac
1073
1159
  if (log) {
1074
1160
  log(`page.screenshot: ${Date.now() - screenshotStart}ms`);
1075
1161
  }
1076
- // Resize with sharp if available, otherwise use clipped raw buffer
1162
+ // Resize with resizeImage if sharp available, otherwise use clipped raw buffer
1077
1163
  const resizeStart = Date.now();
1078
1164
  const buffer = await (async () => {
1079
1165
  if (!sharp) {
1080
- logger?.error?.('[playwriter] sharp not available, using clipped screenshot (max', MAX_DIMENSION, 'px)');
1166
+ logger?.error?.('[playwriter] sharp not available, using clipped screenshot (max', LLM_MAX_DIMENSION, 'px)');
1081
1167
  return rawBuffer;
1082
1168
  }
1083
1169
  try {
1084
- return await sharp(rawBuffer)
1085
- .resize({
1086
- width: MAX_DIMENSION,
1087
- height: MAX_DIMENSION,
1088
- fit: 'inside', // Scale down to fit, preserving aspect ratio
1089
- withoutEnlargement: true, // Don't upscale small images
1090
- })
1091
- .jpeg({ quality: 80 })
1092
- .toBuffer();
1170
+ const result = await resizeImage({ input: rawBuffer });
1171
+ return result.buffer;
1093
1172
  }
1094
1173
  catch (err) {
1095
1174
  logger?.error?.('[playwriter] sharp resize failed, using raw buffer:', err);