craftdriver 1.6.0 → 1.8.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 (229) hide show
  1. package/CHANGELOG.md +35 -6
  2. package/README.md +17 -6
  3. package/dist/cli/agentSession.d.ts +62 -0
  4. package/dist/cli/agentSession.d.ts.map +1 -0
  5. package/dist/cli/agentSession.js +100 -0
  6. package/dist/cli/agentSession.js.map +1 -0
  7. package/dist/cli/artifactPaths.d.ts +42 -0
  8. package/dist/cli/artifactPaths.d.ts.map +1 -0
  9. package/dist/cli/artifactPaths.js +144 -0
  10. package/dist/cli/artifactPaths.js.map +1 -0
  11. package/dist/cli/bounds.d.ts +88 -0
  12. package/dist/cli/bounds.d.ts.map +1 -0
  13. package/dist/cli/bounds.js +128 -0
  14. package/dist/cli/bounds.js.map +1 -0
  15. package/dist/cli/client.d.ts +3 -0
  16. package/dist/cli/client.d.ts.map +1 -1
  17. package/dist/cli/client.js +24 -8
  18. package/dist/cli/client.js.map +1 -1
  19. package/dist/cli/daemon.d.ts +3 -0
  20. package/dist/cli/daemon.d.ts.map +1 -1
  21. package/dist/cli/daemon.js +152 -39
  22. package/dist/cli/daemon.js.map +1 -1
  23. package/dist/cli/defaults.d.ts +23 -3
  24. package/dist/cli/defaults.d.ts.map +1 -1
  25. package/dist/cli/defaults.js +50 -5
  26. package/dist/cli/defaults.js.map +1 -1
  27. package/dist/cli/dispatcher.d.ts +54 -11
  28. package/dist/cli/dispatcher.d.ts.map +1 -1
  29. package/dist/cli/dispatcher.js +851 -54
  30. package/dist/cli/dispatcher.js.map +1 -1
  31. package/dist/cli/index.d.ts.map +1 -1
  32. package/dist/cli/index.js +305 -56
  33. package/dist/cli/index.js.map +1 -1
  34. package/dist/cli/init.d.ts +14 -14
  35. package/dist/cli/init.d.ts.map +1 -1
  36. package/dist/cli/init.js +328 -180
  37. package/dist/cli/init.js.map +1 -1
  38. package/dist/cli/journal.d.ts +153 -0
  39. package/dist/cli/journal.d.ts.map +1 -0
  40. package/dist/cli/journal.js +252 -0
  41. package/dist/cli/journal.js.map +1 -0
  42. package/dist/cli/lineReader.d.ts +33 -0
  43. package/dist/cli/lineReader.d.ts.map +1 -0
  44. package/dist/cli/lineReader.js +66 -0
  45. package/dist/cli/lineReader.js.map +1 -0
  46. package/dist/cli/locatorCandidates.d.ts +44 -0
  47. package/dist/cli/locatorCandidates.d.ts.map +1 -0
  48. package/dist/cli/locatorCandidates.js +190 -0
  49. package/dist/cli/locatorCandidates.js.map +1 -0
  50. package/dist/cli/mcp/artifacts.d.ts +39 -1
  51. package/dist/cli/mcp/artifacts.d.ts.map +1 -1
  52. package/dist/cli/mcp/artifacts.js +104 -9
  53. package/dist/cli/mcp/artifacts.js.map +1 -1
  54. package/dist/cli/mcp/bounds.d.ts +65 -0
  55. package/dist/cli/mcp/bounds.d.ts.map +1 -0
  56. package/dist/cli/mcp/bounds.js +124 -0
  57. package/dist/cli/mcp/bounds.js.map +1 -0
  58. package/dist/cli/mcp/params.d.ts +38 -0
  59. package/dist/cli/mcp/params.d.ts.map +1 -0
  60. package/dist/cli/mcp/params.js +174 -0
  61. package/dist/cli/mcp/params.js.map +1 -0
  62. package/dist/cli/mcp/server.d.ts +94 -16
  63. package/dist/cli/mcp/server.d.ts.map +1 -1
  64. package/dist/cli/mcp/server.js +304 -150
  65. package/dist/cli/mcp/server.js.map +1 -1
  66. package/dist/cli/mcp/tools.d.ts +62 -17
  67. package/dist/cli/mcp/tools.d.ts.map +1 -1
  68. package/dist/cli/mcp/tools.js +373 -158
  69. package/dist/cli/mcp/tools.js.map +1 -1
  70. package/dist/cli/pageSemantics.d.ts +42 -0
  71. package/dist/cli/pageSemantics.d.ts.map +1 -0
  72. package/dist/cli/pageSemantics.js +194 -0
  73. package/dist/cli/pageSemantics.js.map +1 -0
  74. package/dist/cli/parseArgs.d.ts +6 -18
  75. package/dist/cli/parseArgs.d.ts.map +1 -1
  76. package/dist/cli/parseArgs.js +689 -45
  77. package/dist/cli/parseArgs.js.map +1 -1
  78. package/dist/cli/protocol.d.ts +8 -0
  79. package/dist/cli/protocol.d.ts.map +1 -1
  80. package/dist/cli/sessionRegistry.d.ts +42 -0
  81. package/dist/cli/sessionRegistry.d.ts.map +1 -0
  82. package/dist/cli/sessionRegistry.js +99 -0
  83. package/dist/cli/sessionRegistry.js.map +1 -0
  84. package/dist/cli/snapshot.d.ts +100 -18
  85. package/dist/cli/snapshot.d.ts.map +1 -1
  86. package/dist/cli/snapshot.js +248 -102
  87. package/dist/cli/snapshot.js.map +1 -1
  88. package/dist/cli/stateStore.d.ts +50 -0
  89. package/dist/cli/stateStore.d.ts.map +1 -0
  90. package/dist/cli/stateStore.js +122 -0
  91. package/dist/cli/stateStore.js.map +1 -0
  92. package/dist/index.d.ts +2 -1
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +2 -0
  95. package/dist/index.js.map +1 -1
  96. package/dist/lib/bidi/index.d.ts +1 -1
  97. package/dist/lib/bidi/index.d.ts.map +1 -1
  98. package/dist/lib/bidi/index.js +2 -2
  99. package/dist/lib/bidi/index.js.map +1 -1
  100. package/dist/lib/bidi/logs.d.ts +3 -0
  101. package/dist/lib/bidi/logs.d.ts.map +1 -1
  102. package/dist/lib/bidi/logs.js +7 -0
  103. package/dist/lib/bidi/logs.js.map +1 -1
  104. package/dist/lib/bidi/network.d.ts +14 -1
  105. package/dist/lib/bidi/network.d.ts.map +1 -1
  106. package/dist/lib/bidi/network.js +45 -7
  107. package/dist/lib/bidi/network.js.map +1 -1
  108. package/dist/lib/bidi/storage.d.ts +30 -6
  109. package/dist/lib/bidi/storage.d.ts.map +1 -1
  110. package/dist/lib/bidi/storage.js +190 -45
  111. package/dist/lib/bidi/storage.js.map +1 -1
  112. package/dist/lib/bidi/types.d.ts +7 -2
  113. package/dist/lib/bidi/types.d.ts.map +1 -1
  114. package/dist/lib/browser.d.ts +38 -3
  115. package/dist/lib/browser.d.ts.map +1 -1
  116. package/dist/lib/browser.js +196 -30
  117. package/dist/lib/browser.js.map +1 -1
  118. package/dist/lib/browserContext.d.ts +54 -18
  119. package/dist/lib/browserContext.d.ts.map +1 -1
  120. package/dist/lib/browserContext.js +295 -92
  121. package/dist/lib/browserContext.js.map +1 -1
  122. package/dist/lib/by.d.ts +3 -3
  123. package/dist/lib/by.d.ts.map +1 -1
  124. package/dist/lib/by.js +7 -3
  125. package/dist/lib/by.js.map +1 -1
  126. package/dist/lib/driver.d.ts +7 -0
  127. package/dist/lib/driver.d.ts.map +1 -1
  128. package/dist/lib/driver.js +12 -0
  129. package/dist/lib/driver.js.map +1 -1
  130. package/dist/lib/errors.d.ts +15 -0
  131. package/dist/lib/errors.d.ts.map +1 -1
  132. package/dist/lib/errors.js +15 -0
  133. package/dist/lib/errors.js.map +1 -1
  134. package/dist/lib/initScript.d.ts +9 -0
  135. package/dist/lib/initScript.d.ts.map +1 -0
  136. package/dist/lib/initScript.js +14 -0
  137. package/dist/lib/initScript.js.map +1 -0
  138. package/dist/lib/page.d.ts +22 -0
  139. package/dist/lib/page.d.ts.map +1 -1
  140. package/dist/lib/page.js +48 -0
  141. package/dist/lib/page.js.map +1 -1
  142. package/dist/lib/secureFile.d.ts +8 -0
  143. package/dist/lib/secureFile.d.ts.map +1 -0
  144. package/dist/lib/secureFile.js +67 -0
  145. package/dist/lib/secureFile.js.map +1 -0
  146. package/dist/lib/sessionStateValidation.d.ts +35 -0
  147. package/dist/lib/sessionStateValidation.d.ts.map +1 -0
  148. package/dist/lib/sessionStateValidation.js +223 -0
  149. package/dist/lib/sessionStateValidation.js.map +1 -0
  150. package/dist/lib/timing.d.ts +8 -0
  151. package/dist/lib/timing.d.ts.map +1 -1
  152. package/dist/lib/timing.js +8 -0
  153. package/dist/lib/timing.js.map +1 -1
  154. package/dist/lib/tracing.d.ts +2 -1
  155. package/dist/lib/tracing.d.ts.map +1 -1
  156. package/dist/lib/tracing.js +12 -1
  157. package/dist/lib/tracing.js.map +1 -1
  158. package/dist/lib/visual/antialias.d.ts +41 -0
  159. package/dist/lib/visual/antialias.d.ts.map +1 -0
  160. package/dist/lib/visual/antialias.js +126 -0
  161. package/dist/lib/visual/antialias.js.map +1 -0
  162. package/dist/lib/visual/codec.d.ts +24 -0
  163. package/dist/lib/visual/codec.d.ts.map +1 -0
  164. package/dist/lib/visual/codec.js +11 -0
  165. package/dist/lib/visual/codec.js.map +1 -0
  166. package/dist/lib/visual/compare.d.ts +38 -0
  167. package/dist/lib/visual/compare.d.ts.map +1 -0
  168. package/dist/lib/visual/compare.js +209 -0
  169. package/dist/lib/visual/compare.js.map +1 -0
  170. package/dist/lib/visual/diff.d.ts +18 -0
  171. package/dist/lib/visual/diff.d.ts.map +1 -0
  172. package/dist/lib/visual/diff.js +23 -0
  173. package/dist/lib/visual/diff.js.map +1 -0
  174. package/dist/lib/visual/expectScreenshot.d.ts +65 -0
  175. package/dist/lib/visual/expectScreenshot.d.ts.map +1 -0
  176. package/dist/lib/visual/expectScreenshot.js +287 -0
  177. package/dist/lib/visual/expectScreenshot.js.map +1 -0
  178. package/dist/lib/visual/index.d.ts +10 -0
  179. package/dist/lib/visual/index.d.ts.map +1 -0
  180. package/dist/lib/visual/index.js +9 -0
  181. package/dist/lib/visual/index.js.map +1 -0
  182. package/dist/lib/visual/pixelMath.d.ts +32 -0
  183. package/dist/lib/visual/pixelMath.d.ts.map +1 -0
  184. package/dist/lib/visual/pixelMath.js +70 -0
  185. package/dist/lib/visual/pixelMath.js.map +1 -0
  186. package/dist/lib/visual/pngHeader.d.ts +27 -0
  187. package/dist/lib/visual/pngHeader.d.ts.map +1 -0
  188. package/dist/lib/visual/pngHeader.js +63 -0
  189. package/dist/lib/visual/pngHeader.js.map +1 -0
  190. package/dist/lib/visual/pngjsCodec.d.ts +22 -0
  191. package/dist/lib/visual/pngjsCodec.d.ts.map +1 -0
  192. package/dist/lib/visual/pngjsCodec.js +70 -0
  193. package/dist/lib/visual/pngjsCodec.js.map +1 -0
  194. package/dist/lib/visual/types.d.ts +89 -0
  195. package/dist/lib/visual/types.d.ts.map +1 -0
  196. package/dist/lib/visual/types.js +20 -0
  197. package/dist/lib/visual/types.js.map +1 -0
  198. package/dist/lib/visual/visualError.d.ts +32 -0
  199. package/dist/lib/visual/visualError.d.ts.map +1 -0
  200. package/dist/lib/visual/visualError.js +59 -0
  201. package/dist/lib/visual/visualError.js.map +1 -0
  202. package/dist/lib/wait.d.ts.map +1 -1
  203. package/dist/lib/wait.js +7 -1
  204. package/dist/lib/wait.js.map +1 -1
  205. package/docs/agents.md +56 -61
  206. package/docs/api-reference.md +16 -1
  207. package/docs/browser-api.md +24 -4
  208. package/docs/browser-context.md +18 -12
  209. package/docs/cli.md +346 -26
  210. package/docs/error-codes.md +6 -4
  211. package/docs/getting-started.md +6 -1
  212. package/docs/index.md +1 -1
  213. package/docs/mcp.md +129 -62
  214. package/docs/public/examples/agent-actions.html +48 -0
  215. package/docs/public/examples/agent-debug.html +86 -0
  216. package/docs/public/examples/agent-late-mutation.html +18 -0
  217. package/docs/public/examples/agent-ref-shift.html +33 -0
  218. package/docs/recipes/login-once-reuse-session.md +32 -4
  219. package/docs/screenshots.md +15 -6
  220. package/docs/session-management.md +64 -3
  221. package/docs/visual-testing.md +254 -0
  222. package/docs/why-craftdriver.md +4 -3
  223. package/package.json +5 -1
  224. package/skills/craftdriver/SKILL.md +59 -75
  225. package/skills/craftdriver/agents/openai.yaml +4 -0
  226. package/skills/craftdriver/cheatsheet.md +18 -4
  227. package/skills/craftdriver/cli.md +194 -68
  228. package/skills/craftdriver/patterns.md +14 -8
  229. package/skills/craftdriver/workflow.md +149 -0
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Optional anti-aliasing detector.
3
+ *
4
+ * The `antialiased()` / `hasManySiblings()` neighbourhood heuristic below is
5
+ * adapted from Pixelmatch (https://github.com/mapbox/pixelmatch) by Vladimir
6
+ * Agafonkin, which itself implements the anti-aliasing detection from:
7
+ *
8
+ * V. Vysniauskas, "Anti-aliased pixel and intensity slope detector", 2009.
9
+ *
10
+ * Pixelmatch is distributed under the ISC License:
11
+ *
12
+ * Copyright (c) 2019, Mapbox
13
+ *
14
+ * Permission to use, copy, modify, and/or distribute this software for any
15
+ * purpose with or without fee is hereby granted, provided that the above
16
+ * copyright notice and this permission notice appear in all copies.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
19
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
20
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
23
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
24
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25
+ *
26
+ * Adaptations from the original: brightness deltas and sibling equality use
27
+ * white-composited visible colour (see `./pixelMath`) instead of Pixelmatch's
28
+ * checkerboard blend, and all neighbour reads are byte-indexed so no 4-byte
29
+ * `Uint32Array` alignment is assumed of the codec output.
30
+ */
31
+ import { brightnessDelta, visibleEqual } from './pixelMath.js';
32
+ /**
33
+ * Determine whether the pixel at (x1, y1) in `data` looks like anti-aliasing,
34
+ * cross-checked against `other`. A pixel is a candidate when it has a bright and
35
+ * a dark neighbour (an intensity slope) and the extreme neighbour has many
36
+ * identical siblings in both images.
37
+ *
38
+ * `width`/`height` bound the compared region (the overlap of the two images);
39
+ * `stride`/`otherStride` are the true row widths used to byte-index `data` and
40
+ * `other` respectively. These differ only on a dimension mismatch — indexing a
41
+ * buffer at anything but its own row width reads the wrong pixels. For equal
42
+ * dimensions all three widths coincide and behaviour is unchanged.
43
+ */
44
+ function antialiased(data, x1, y1, width, height, stride, other, otherStride) {
45
+ const x0 = Math.max(x1 - 1, 0);
46
+ const y0 = Math.max(y1 - 1, 0);
47
+ const x2 = Math.min(x1 + 1, width - 1);
48
+ const y2 = Math.min(y1 + 1, height - 1);
49
+ const pos = (y1 * stride + x1) * 4;
50
+ let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;
51
+ let min = 0;
52
+ let max = 0;
53
+ let minX = -1;
54
+ let minY = -1;
55
+ let maxX = -1;
56
+ let maxY = -1;
57
+ for (let x = x0; x <= x2; x++) {
58
+ for (let y = y0; y <= y2; y++) {
59
+ if (x === x1 && y === y1)
60
+ continue;
61
+ const delta = brightnessDelta(data, pos, (y * stride + x) * 4);
62
+ if (delta === 0) {
63
+ zeroes++;
64
+ // If a pixel has many equal-brightness siblings it is not an edge.
65
+ if (zeroes > 2)
66
+ return false;
67
+ }
68
+ else if (delta < min) {
69
+ min = delta;
70
+ minX = x;
71
+ minY = y;
72
+ }
73
+ else if (delta > max) {
74
+ max = delta;
75
+ maxX = x;
76
+ maxY = y;
77
+ }
78
+ }
79
+ }
80
+ // Need both a darker and a brighter neighbour to form an intensity slope.
81
+ if (min === 0 || max === 0)
82
+ return false;
83
+ return ((hasManySiblings(data, minX, minY, width, height, stride) &&
84
+ hasManySiblings(other, minX, minY, width, height, otherStride)) ||
85
+ (hasManySiblings(data, maxX, maxY, width, height, stride) &&
86
+ hasManySiblings(other, maxX, maxY, width, height, otherStride)));
87
+ }
88
+ /**
89
+ * Whether the pixel at (x1, y1) shares its visible colour with ≥3 neighbours.
90
+ * `width`/`height` bound the compared region; `stride` is `data`'s true row
91
+ * width used for byte indexing (see {@link antialiased}).
92
+ */
93
+ function hasManySiblings(data, x1, y1, width, height, stride) {
94
+ const x0 = Math.max(x1 - 1, 0);
95
+ const y0 = Math.max(y1 - 1, 0);
96
+ const x2 = Math.min(x1 + 1, width - 1);
97
+ const y2 = Math.min(y1 + 1, height - 1);
98
+ const pos = (y1 * stride + x1) * 4;
99
+ let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;
100
+ for (let x = x0; x <= x2; x++) {
101
+ for (let y = y0; y <= y2; y++) {
102
+ if (x === x1 && y === y1)
103
+ continue;
104
+ if (visibleEqual(data, pos, (y * stride + x) * 4)) {
105
+ zeroes++;
106
+ if (zeroes > 2)
107
+ return true;
108
+ }
109
+ }
110
+ }
111
+ return false;
112
+ }
113
+ /**
114
+ * Whether the pixel at (x, y) is anti-aliasing in either image (Pixelmatch's
115
+ * symmetric check). Callers should only invoke this for pixels that already
116
+ * failed the colour-tolerance test.
117
+ *
118
+ * `width`/`height` bound the compared region (the overlap); `actualWidth` and
119
+ * `expectedWidth` are each buffer's own row width for byte indexing, which
120
+ * differ from the overlap only on a dimension mismatch.
121
+ */
122
+ export function isAntialiased(actual, expected, x, y, actualWidth, expectedWidth, width, height) {
123
+ return (antialiased(actual, x, y, width, height, actualWidth, expected, expectedWidth) ||
124
+ antialiased(expected, x, y, width, height, expectedWidth, actual, actualWidth));
125
+ }
126
+ //# sourceMappingURL=antialias.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"antialias.js","sourceRoot":"","sources":["../../../src/lib/visual/antialias.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Internal codec boundary for visual testing.
3
+ *
4
+ * All PNG-library-specific code lives behind this interface so the rest of the
5
+ * visual pipeline works on normalized, decoded RGBA pixels and never sees the
6
+ * concrete codec (currently pngjs). Keeping the seam narrow means a future codec
7
+ * can be evaluated without touching the comparison, diff, or retry code, and no
8
+ * codec type is ever exposed on the public API.
9
+ */
10
+ /** A decoded image normalized to a fresh 8-bit RGBA byte view. */
11
+ export interface DecodedImage {
12
+ width: number;
13
+ height: number;
14
+ /** Row-major RGBA, exactly `width * height * 4` bytes. */
15
+ data: Uint8Array;
16
+ }
17
+ /** Minimal decode/encode contract implemented by {@link pngjsCodec}. */
18
+ export interface PngCodec {
19
+ /** Decode a compressed PNG to normalized 8-bit RGBA. */
20
+ decode(buffer: Uint8Array): Promise<DecodedImage>;
21
+ /** Encode normalized 8-bit RGBA back to a compressed PNG. */
22
+ encode(image: DecodedImage): Promise<Buffer>;
23
+ }
24
+ //# sourceMappingURL=codec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../../src/lib/visual/codec.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,kEAAkE;AAClE,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,wEAAwE;AACxE,MAAM,WAAW,QAAQ;IACvB,wDAAwD;IACxD,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAClD,6DAA6D;IAC7D,MAAM,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9C"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Internal codec boundary for visual testing.
3
+ *
4
+ * All PNG-library-specific code lives behind this interface so the rest of the
5
+ * visual pipeline works on normalized, decoded RGBA pixels and never sees the
6
+ * concrete codec (currently pngjs). Keeping the seam narrow means a future codec
7
+ * can be evaluated without touching the comparison, diff, or retry code, and no
8
+ * codec type is ever exposed on the public API.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.js","sourceRoot":"","sources":["../../../src/lib/visual/codec.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Per-channel comparison and threshold policy over decoded RGBA images.
3
+ *
4
+ * This is small, dependency-free code over fixed-length arrays — deliberately
5
+ * owned rather than delegated, unlike the PNG parser. The same loop both counts
6
+ * differences (normal retries) and, when handed an optional diff output buffer,
7
+ * paints the diagnostic image (final failure only), so the two can never
8
+ * disagree about which pixels differ.
9
+ */
10
+ import type { DecodedImage } from './codec.js';
11
+ import { type ScreenshotCompareOptions, type VisualComparisonResult } from './types.js';
12
+ /** Options after validation and default resolution. */
13
+ export interface ResolvedCompareOptions {
14
+ pixelTolerance: number;
15
+ maxDiffPixels: number | undefined;
16
+ maxDiffPercentage: number | undefined;
17
+ ignoreAntialiasing: boolean;
18
+ maxImagePixels: number;
19
+ maxInputBytes: number;
20
+ }
21
+ /** Validate and default the comparison options. Never clamps — bad input throws. */
22
+ export declare function resolveCompareOptions(options?: ScreenshotCompareOptions): ResolvedCompareOptions;
23
+ /**
24
+ * Compare two decoded images. Counts `diffPixels` / `ignoredAntialiasPixels`
25
+ * and, when `output` (a union-sized RGBA buffer) is supplied, paints the diff.
26
+ *
27
+ * Argument order is `(actual, expected)` — see the note in `./types`.
28
+ */
29
+ export declare function compareDecoded(actual: DecodedImage, expected: DecodedImage, opts: ResolvedCompareOptions, output?: Uint8Array): VisualComparisonResult;
30
+ /**
31
+ * Compare two compressed PNG buffers without disk access, browser capture,
32
+ * retries, or throwing on a normal mismatch. Applies the same byte/pixel input
33
+ * limits as the retrying assertion.
34
+ *
35
+ * Argument order is `(actual, expected)` — see the note in `./types`.
36
+ */
37
+ export declare function compareScreenshots(actual: Buffer, expected: Buffer, options?: ScreenshotCompareOptions): Promise<VisualComparisonResult>;
38
+ //# sourceMappingURL=compare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../../../src/lib/visual/compare.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK/C,OAAO,EAGL,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC5B,MAAM,YAAY,CAAC;AASpB,uDAAuD;AACvD,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB;AAUD,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,wBAA6B,GAAG,sBAAsB,CAgDpG;AAiBD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,sBAAsB,EAC5B,MAAM,CAAC,EAAE,UAAU,GAClB,sBAAsB,CA2FxB;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,sBAAsB,CAAC,CA2BjC"}
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Per-channel comparison and threshold policy over decoded RGBA images.
3
+ *
4
+ * This is small, dependency-free code over fixed-length arrays — deliberately
5
+ * owned rather than delegated, unlike the PNG parser. The same loop both counts
6
+ * differences (normal retries) and, when handed an optional diff output buffer,
7
+ * paints the diagnostic image (final failure only), so the two can never
8
+ * disagree about which pixels differ.
9
+ */
10
+ import { CraftdriverError, ErrorCode } from '../errors.js';
11
+ import { pngjsCodec } from './pngjsCodec.js';
12
+ import { validatePngHeaderAndSize } from './pngHeader.js';
13
+ import { isAntialiased } from './antialias.js';
14
+ import { blendOverWhite, rgb2y, visibleRgb } from './pixelMath.js';
15
+ import { DEFAULT_MAX_IMAGE_PIXELS, DEFAULT_MAX_INPUT_BYTES, } from './types.js';
16
+ /** Diagnostic diff colours. */
17
+ const RED = [255, 0, 0, 255];
18
+ const YELLOW = [255, 255, 0, 255];
19
+ const MAGENTA = [255, 0, 255, 255];
20
+ /** How much of the actual image bleeds through as dimmed grayscale context. */
21
+ const GRAY_ALPHA = 0.1;
22
+ function invalid(message, detail) {
23
+ throw new CraftdriverError(ErrorCode.INVALID_ARGUMENT, message, detail ? { detail } : undefined);
24
+ }
25
+ function requireInteger(value, name) {
26
+ if (!Number.isInteger(value))
27
+ invalid(`${name} must be an integer, got ${value}.`, { [name]: value });
28
+ }
29
+ /** Validate and default the comparison options. Never clamps — bad input throws. */
30
+ export function resolveCompareOptions(options = {}) {
31
+ const pixelTolerance = options.pixelTolerance ?? 0;
32
+ requireInteger(pixelTolerance, 'pixelTolerance');
33
+ if (pixelTolerance < 0 || pixelTolerance > 255) {
34
+ invalid(`pixelTolerance must be within 0..255, got ${pixelTolerance}.`, { pixelTolerance });
35
+ }
36
+ let maxDiffPixels;
37
+ if (options.maxDiffPixels !== undefined) {
38
+ requireInteger(options.maxDiffPixels, 'maxDiffPixels');
39
+ if (options.maxDiffPixels < 0) {
40
+ invalid(`maxDiffPixels must be >= 0, got ${options.maxDiffPixels}.`, { maxDiffPixels: options.maxDiffPixels });
41
+ }
42
+ maxDiffPixels = options.maxDiffPixels;
43
+ }
44
+ let maxDiffPercentage;
45
+ if (options.maxDiffPercentage !== undefined) {
46
+ if (!Number.isFinite(options.maxDiffPercentage) || options.maxDiffPercentage < 0 || options.maxDiffPercentage > 100) {
47
+ invalid(`maxDiffPercentage must be within 0..100, got ${options.maxDiffPercentage}.`, {
48
+ maxDiffPercentage: options.maxDiffPercentage,
49
+ });
50
+ }
51
+ maxDiffPercentage = options.maxDiffPercentage;
52
+ }
53
+ const maxImagePixels = options.maxImagePixels ?? DEFAULT_MAX_IMAGE_PIXELS;
54
+ requireInteger(maxImagePixels, 'maxImagePixels');
55
+ if (maxImagePixels < 1)
56
+ invalid(`maxImagePixels must be >= 1, got ${maxImagePixels}.`, { maxImagePixels });
57
+ const maxInputBytes = options.maxInputBytes ?? DEFAULT_MAX_INPUT_BYTES;
58
+ requireInteger(maxInputBytes, 'maxInputBytes');
59
+ if (maxInputBytes < 1)
60
+ invalid(`maxInputBytes must be >= 1, got ${maxInputBytes}.`, { maxInputBytes });
61
+ if (options.ignoreAntialiasing !== undefined && typeof options.ignoreAntialiasing !== 'boolean') {
62
+ // A JSON/JavaScript caller passing "false" (a truthy string) must not
63
+ // silently enable AA ignoring and hide regressions.
64
+ invalid(`ignoreAntialiasing must be a boolean, got ${typeof options.ignoreAntialiasing}.`);
65
+ }
66
+ return {
67
+ pixelTolerance,
68
+ maxDiffPixels,
69
+ maxDiffPercentage,
70
+ ignoreAntialiasing: options.ignoreAntialiasing ?? false,
71
+ maxImagePixels,
72
+ maxInputBytes,
73
+ };
74
+ }
75
+ function draw(output, pos, rgba) {
76
+ output[pos] = rgba[0];
77
+ output[pos + 1] = rgba[1];
78
+ output[pos + 2] = rgba[2];
79
+ output[pos + 3] = rgba[3];
80
+ }
81
+ /** Dimmed grayscale of the actual pixel — context in the diff artifact. */
82
+ function drawContext(output, outPos, actual, srcPos) {
83
+ const a = actual[srcPos + 3];
84
+ const [r, g, b] = [0, 1, 2].map((i) => actual[srcPos + i]);
85
+ const val = blendOverWhite(rgb2y(r, g, b), GRAY_ALPHA * a);
86
+ draw(output, outPos, [val, val, val, 255]);
87
+ }
88
+ /**
89
+ * Compare two decoded images. Counts `diffPixels` / `ignoredAntialiasPixels`
90
+ * and, when `output` (a union-sized RGBA buffer) is supplied, paints the diff.
91
+ *
92
+ * Argument order is `(actual, expected)` — see the note in `./types`.
93
+ */
94
+ export function compareDecoded(actual, expected, opts, output) {
95
+ const dimensionMismatch = actual.width !== expected.width || actual.height !== expected.height;
96
+ // Diff canvas is the bounding box; both images are anchored at (0, 0).
97
+ const canvasWidth = Math.max(actual.width, expected.width);
98
+ const canvasHeight = Math.max(actual.height, expected.height);
99
+ const overlapWidth = Math.min(actual.width, expected.width);
100
+ const overlapHeight = Math.min(actual.height, expected.height);
101
+ // Counts/percentage are over the *union* of the two top-left rectangles —
102
+ // the bounding-box corner present in neither image is excluded.
103
+ const totalPixels = actual.width * actual.height +
104
+ expected.width * expected.height -
105
+ overlapWidth * overlapHeight;
106
+ const va = [0, 0, 0];
107
+ const ve = [0, 0, 0];
108
+ const tol = opts.pixelTolerance;
109
+ let diffPixels = 0;
110
+ let ignoredAntialiasPixels = 0;
111
+ for (let y = 0; y < canvasHeight; y++) {
112
+ for (let x = 0; x < canvasWidth; x++) {
113
+ const outPos = (y * canvasWidth + x) * 4;
114
+ const inActual = x < actual.width && y < actual.height;
115
+ const inExpected = x < expected.width && y < expected.height;
116
+ // Present in neither image (the bounding-box corner): leave it
117
+ // transparent in the diff and don't count it.
118
+ if (!inActual && !inExpected)
119
+ continue;
120
+ if (!(inActual && inExpected)) {
121
+ // Present in only one image (dimension mismatch): always a difference.
122
+ diffPixels++;
123
+ if (output)
124
+ draw(output, outPos, MAGENTA);
125
+ continue;
126
+ }
127
+ const aPos = (y * actual.width + x) * 4;
128
+ const ePos = (y * expected.width + x) * 4;
129
+ visibleRgb(actual.data, aPos, va);
130
+ visibleRgb(expected.data, ePos, ve);
131
+ const equal = Math.abs(va[0] - ve[0]) <= tol &&
132
+ Math.abs(va[1] - ve[1]) <= tol &&
133
+ Math.abs(va[2] - ve[2]) <= tol;
134
+ if (equal) {
135
+ if (output)
136
+ drawContext(output, outPos, actual.data, aPos);
137
+ continue;
138
+ }
139
+ if (opts.ignoreAntialiasing &&
140
+ isAntialiased(actual.data, expected.data, x, y, actual.width, expected.width, overlapWidth, overlapHeight)) {
141
+ ignoredAntialiasPixels++;
142
+ if (output)
143
+ draw(output, outPos, YELLOW);
144
+ continue;
145
+ }
146
+ diffPixels++;
147
+ if (output)
148
+ draw(output, outPos, RED);
149
+ }
150
+ }
151
+ const diffPercentage = totalPixels === 0 ? 0 : (diffPixels / totalPixels) * 100;
152
+ let matches;
153
+ if (dimensionMismatch) {
154
+ matches = false;
155
+ }
156
+ else if (opts.maxDiffPixels === undefined && opts.maxDiffPercentage === undefined) {
157
+ matches = diffPixels === 0;
158
+ }
159
+ else {
160
+ matches =
161
+ (opts.maxDiffPixels === undefined || diffPixels <= opts.maxDiffPixels) &&
162
+ (opts.maxDiffPercentage === undefined || diffPercentage <= opts.maxDiffPercentage);
163
+ }
164
+ return {
165
+ matches,
166
+ diffPixels,
167
+ diffPercentage,
168
+ ignoredAntialiasPixels,
169
+ expectedWidth: expected.width,
170
+ expectedHeight: expected.height,
171
+ actualWidth: actual.width,
172
+ actualHeight: actual.height,
173
+ dimensionMismatch,
174
+ };
175
+ }
176
+ /**
177
+ * Compare two compressed PNG buffers without disk access, browser capture,
178
+ * retries, or throwing on a normal mismatch. Applies the same byte/pixel input
179
+ * limits as the retrying assertion.
180
+ *
181
+ * Argument order is `(actual, expected)` — see the note in `./types`.
182
+ */
183
+ export async function compareScreenshots(actual, expected, options) {
184
+ const opts = resolveCompareOptions(options);
185
+ const limits = { maxImagePixels: opts.maxImagePixels, maxInputBytes: opts.maxInputBytes };
186
+ const { width, height } = validatePngHeaderAndSize(expected, limits, 'baseline');
187
+ validatePngHeaderAndSize(actual, limits, 'screenshot');
188
+ // Fast path: identical compressed bytes necessarily mean identical pixels, so
189
+ // there is nothing to decode. Mirrors the retrying assertion's fast path.
190
+ if (actual.length === expected.length && actual.equals(expected)) {
191
+ return {
192
+ matches: true,
193
+ diffPixels: 0,
194
+ diffPercentage: 0,
195
+ ignoredAntialiasPixels: 0,
196
+ expectedWidth: width,
197
+ expectedHeight: height,
198
+ actualWidth: width,
199
+ actualHeight: height,
200
+ dimensionMismatch: false,
201
+ };
202
+ }
203
+ const [actualImage, expectedImage] = await Promise.all([
204
+ pngjsCodec.decode(actual),
205
+ pngjsCodec.decode(expected),
206
+ ]);
207
+ return compareDecoded(actualImage, expectedImage, opts);
208
+ }
209
+ //# sourceMappingURL=compare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare.js","sourceRoot":"","sources":["../../../src/lib/visual/compare.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Lazy diff painting. Allocated and run exactly once, only after a visual
3
+ * assertion has finally failed — never during retries. Reuses the comparison
4
+ * loop in `./compare` with an output buffer so the painted diff and the counted
5
+ * result use identical pixel semantics.
6
+ */
7
+ import type { DecodedImage } from './codec.js';
8
+ import { type ResolvedCompareOptions } from './compare.js';
9
+ /**
10
+ * Produce a diagnostic diff image sized to the union of both inputs (top-left
11
+ * aligned). Unchanged pixels appear as dimmed grayscale actual content,
12
+ * counted differences as red, ignored anti-aliased pixels as yellow, and areas
13
+ * present in only one image (dimension mismatch) as magenta.
14
+ *
15
+ * Argument order is `(actual, expected)` — see the note in `./types`.
16
+ */
17
+ export declare function createDiff(actual: DecodedImage, expected: DecodedImage, opts: ResolvedCompareOptions): DecodedImage;
18
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/lib/visual/diff.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAkB,KAAK,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAE3E;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,sBAAsB,GAC3B,YAAY,CAMd"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Lazy diff painting. Allocated and run exactly once, only after a visual
3
+ * assertion has finally failed — never during retries. Reuses the comparison
4
+ * loop in `./compare` with an output buffer so the painted diff and the counted
5
+ * result use identical pixel semantics.
6
+ */
7
+ import { compareDecoded } from './compare.js';
8
+ /**
9
+ * Produce a diagnostic diff image sized to the union of both inputs (top-left
10
+ * aligned). Unchanged pixels appear as dimmed grayscale actual content,
11
+ * counted differences as red, ignored anti-aliased pixels as yellow, and areas
12
+ * present in only one image (dimension mismatch) as magenta.
13
+ *
14
+ * Argument order is `(actual, expected)` — see the note in `./types`.
15
+ */
16
+ export function createDiff(actual, expected, opts) {
17
+ const width = Math.max(actual.width, expected.width);
18
+ const height = Math.max(actual.height, expected.height);
19
+ const data = new Uint8Array(width * height * 4);
20
+ compareDecoded(actual, expected, opts, data);
21
+ return { width, height, data };
22
+ }
23
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/lib/visual/diff.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,cAAc,EAA+B,MAAM,cAAc,CAAC;AAE3E;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CACxB,MAAoB,EACpB,QAAsB,EACtB,IAA4B;IAE5B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC;IAChD,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACjC,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The retrying visual assertion: read the baseline once, then poll the browser
3
+ * until a screenshot matches or the monotonic deadline expires.
4
+ *
5
+ * The hot path is deliberately lazy. An exact byte match costs one screenshot
6
+ * plus a `Buffer.equals` and never decodes. A static mismatch decodes the
7
+ * expected and actual images once each, then subsequent polls only re-capture
8
+ * and compare compressed bytes. Only changing content pays a decode per retry.
9
+ * The diff image is allocated and encoded exactly once, after the final failure.
10
+ *
11
+ * Baselines are managed for the caller, WebdriverIO-style:
12
+ * - Missing baseline (ENOENT): capture until two consecutive frames settle,
13
+ * write it, pass. This is the default — no flag required.
14
+ * - Present but differs, with `update`: capture as usual and, only if the page
15
+ * never settles into a match, overwrite the baseline with the final actual
16
+ * and pass. A page that settles back into a match passes without rewriting.
17
+ * A present-but-corrupt baseline, and any non-ENOENT read error, stay hard
18
+ * configuration errors even under `update` — they are never overwritten.
19
+ *
20
+ * Every baseline write is atomic — the PNG is written to a temp file in the same
21
+ * directory and renamed into place — so an interrupted run cannot corrupt a
22
+ * committed baseline (this matters most under `update`, which replaces one).
23
+ *
24
+ * Timing (`now`) and delays (`sleep`) are injectable so retry behaviour can be
25
+ * driven deterministically in tests without wall-clock waits.
26
+ */
27
+ import type { PngCodec } from './codec.js';
28
+ import type { ExpectScreenshotOptions, ScreenshotMatchResult } from './types.js';
29
+ /** Capture one screenshot, bounding any internal visibility wait by `remainingMs`. */
30
+ export type CaptureFn = (remainingMs: number) => Promise<Buffer>;
31
+ export interface RunExpectScreenshotDeps {
32
+ expectedPath: string;
33
+ options: ExpectScreenshotOptions;
34
+ /** The browser's live default timeout, used when `options.timeout` is unset. */
35
+ defaultTimeout: number;
36
+ capture: CaptureFn;
37
+ /**
38
+ * When true, a baseline that is present but never matches is overwritten with
39
+ * the final actual instead of throwing. Missing-baseline creation is always on
40
+ * and does not depend on this flag. Driven by
41
+ * {@link shouldUpdateVisualBaselines} from the environment. Default false.
42
+ */
43
+ update?: boolean;
44
+ readFile?: (path: string) => Promise<Buffer>;
45
+ writeFile?: (path: string, data: Buffer) => Promise<void>;
46
+ rename?: (from: string, to: string) => Promise<void>;
47
+ unlink?: (path: string) => Promise<void>;
48
+ mkdir?: (dir: string, opts: {
49
+ recursive: true;
50
+ }) => Promise<unknown>;
51
+ /** Human-readable one-liner reported when a baseline is created or updated. */
52
+ report?: (message: string) => void;
53
+ now?: () => number;
54
+ sleep?: (ms: number) => Promise<void>;
55
+ codec?: PngCodec;
56
+ }
57
+ /**
58
+ * Strictly interpret the `CRAFTDRIVER_UPDATE_VISUAL_BASELINES` environment
59
+ * variable. Unset / empty / `false` → off; `true` → on (trimmed,
60
+ * case-insensitive). Anything else throws `INVALID_ARGUMENT` rather than being
61
+ * silently coerced — this flag mutates files on disk, so a typo must fail loud.
62
+ */
63
+ export declare function shouldUpdateVisualBaselines(raw: string | undefined): boolean;
64
+ export declare function runExpectScreenshot(deps: RunExpectScreenshotDeps): Promise<ScreenshotMatchResult>;
65
+ //# sourceMappingURL=expectScreenshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expectScreenshot.d.ts","sourceRoot":"","sources":["../../../src/lib/visual/expectScreenshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAcH,OAAO,KAAK,EAAgB,QAAQ,EAAE,MAAM,YAAY,CAAC;AAMzD,OAAO,KAAK,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEjF,sFAAsF;AACtF,MAAM,MAAM,SAAS,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEjE,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,uBAAuB,CAAC;IACjC,gFAAgF;IAChF,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,SAAS,CAAC;IACnB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,SAAS,EAAE,IAAI,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrE,+EAA+E;IAC/E,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,KAAK,CAAC,EAAE,QAAQ,CAAC;CAClB;AAqBD;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAS5E;AAsDD,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA8LvG"}