@ingcreators/annot-mcp 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,57 +1,57 @@
1
- import { SHARED_DEFS as K, BBOX_ANNOTATION_SCHEMA as Z, bboxAnnotationsToSvg as I, BBOX_REDACT_REGION_SCHEMA as Q, createAnnotator as tt } from "@ingcreators/annot-annotator";
2
- import { BBOX_ANNOTATION_SCHEMA as Ee, BBOX_REDACT_REGION_SCHEMA as xe, arrowBetween as Le, bboxAnnotationsToSvg as Pe, rectForBoundingBox as Ae, textAt as Oe } from "@ingcreators/annot-annotator";
3
- import { loadImage as T, createCanvas as _ } from "@napi-rs/canvas";
4
- import et from "pixelmatch";
5
- import { readFile as rt, writeFile as $ } from "node:fs/promises";
6
- import { isAbsolute as w } from "node:path";
7
- import { Server as ot } from "@modelcontextprotocol/sdk/server/index.js";
8
- import { ListToolsRequestSchema as nt, CallToolRequestSchema as it } from "@modelcontextprotocol/sdk/types.js";
9
- import { StdioServerTransport as at } from "@modelcontextprotocol/sdk/server/stdio.js";
10
- const st = { width: 1280, height: 800, deviceScaleFactor: 1 }, ct = "load";
11
- async function k(t, e) {
12
- const r = { ...st, ...e.viewport }, o = e.waitFor ?? ct, i = e.fullPage ?? !1, a = await t.acquire();
13
- let n, s = !1;
14
- const c = () => {
15
- s || (s = !0, t.release());
1
+ import { SHARED_DEFS as te, DEFAULT_ENCODE_OPTIONS as oe, decodeAndEncodeImage as re, BBOX_ANNOTATION_SCHEMA as ne, bboxAnnotationsToSvg as U, BBOX_REDACT_REGION_SCHEMA as se, createAnnotator as ie } from "@ingcreators/annot-annotator";
2
+ import { BBOX_ANNOTATION_SCHEMA as At, BBOX_REDACT_REGION_SCHEMA as Tt, arrowBetween as Rt, bboxAnnotationsToSvg as It, rectForBoundingBox as _t, textAt as Ct } from "@ingcreators/annot-annotator";
3
+ import { loadImage as C, createCanvas as F } from "@napi-rs/canvas";
4
+ import ae from "pixelmatch";
5
+ import { readFile as ce, writeFile as O } from "node:fs/promises";
6
+ import { isAbsolute as b } from "node:path";
7
+ import { Server as de } from "@modelcontextprotocol/sdk/server/index.js";
8
+ import { ListToolsRequestSchema as le, CallToolRequestSchema as ue } from "@modelcontextprotocol/sdk/types.js";
9
+ import { StdioServerTransport as he } from "@modelcontextprotocol/sdk/server/stdio.js";
10
+ const fe = { width: 1280, height: 800, deviceScaleFactor: 1 }, pe = "load";
11
+ async function W(e, t) {
12
+ const o = { ...fe, ...t.viewport }, n = t.waitFor ?? pe, s = t.fullPage ?? !1, c = await e.acquire();
13
+ let r, a = !1;
14
+ const i = () => {
15
+ a || (a = !0, e.release());
16
16
  };
17
17
  try {
18
- n = await a.newContext({
19
- viewport: { width: r.width, height: r.height },
20
- deviceScaleFactor: r.deviceScaleFactor
18
+ r = await c.newContext({
19
+ viewport: { width: o.width, height: o.height },
20
+ deviceScaleFactor: o.deviceScaleFactor
21
21
  });
22
- const u = await n.newPage();
23
- await u.goto(e.url, { waitUntil: o });
24
- const l = await u.screenshot({ fullPage: i, type: "png" }), h = new Uint8Array(l.buffer, l.byteOffset, l.byteLength), R = n;
25
- return { pngBytes: h, handle: {
26
- page: u,
22
+ const d = await r.newPage();
23
+ await d.goto(t.url, { waitUntil: n });
24
+ const l = await d.screenshot({ fullPage: s, type: "png" }), v = new Uint8Array(l.buffer, l.byteOffset, l.byteLength), u = r;
25
+ return { pngBytes: v, handle: {
26
+ page: d,
27
27
  async close() {
28
- if (!s)
28
+ if (!a)
29
29
  try {
30
- await R.close();
30
+ await u.close();
31
31
  } finally {
32
- c();
32
+ i();
33
33
  }
34
34
  }
35
35
  } };
36
- } catch (u) {
37
- if (n)
36
+ } catch (d) {
37
+ if (r)
38
38
  try {
39
- await n.close();
39
+ await r.close();
40
40
  } catch {
41
41
  }
42
- throw c(), u;
42
+ throw i(), d;
43
43
  }
44
44
  }
45
- const ut = 3e4;
46
- class lt {
45
+ const me = 3e4;
46
+ class ge {
47
+ #s;
47
48
  #i;
48
- #a;
49
- #t;
50
- #o;
51
- #e = 0;
49
+ #e;
52
50
  #r;
53
- constructor(e, r = {}) {
54
- this.#i = e, this.#a = r.idleTimeoutMs ?? ut;
51
+ #t = 0;
52
+ #o;
53
+ constructor(t, o = {}) {
54
+ this.#s = t, this.#i = o.idleTimeoutMs ?? me;
55
55
  }
56
56
  /**
57
57
  * Acquire a browser instance. The pool launches lazily on the
@@ -64,9 +64,9 @@ class lt {
64
64
  * accurately.
65
65
  */
66
66
  async acquire() {
67
- return this.#n(), this.#e += 1, this.#t ? this.#t : (this.#o || (this.#o = this.#i.launch().then((e) => (this.#t = e, this.#o = void 0, e)).catch((e) => {
68
- throw this.#o = void 0, this.#e = Math.max(0, this.#e - 1), e;
69
- })), this.#o);
67
+ return this.#n(), this.#t += 1, this.#e ? this.#e : (this.#r || (this.#r = this.#s.launch().then((t) => (this.#e = t, this.#r = void 0, t)).catch((t) => {
68
+ throw this.#r = void 0, this.#t = Math.max(0, this.#t - 1), t;
69
+ })), this.#r);
70
70
  }
71
71
  /**
72
72
  * Release a previously-acquired browser. Decrements the
@@ -75,7 +75,7 @@ class lt {
75
75
  * instance; otherwise the timer fires and the browser closes.
76
76
  */
77
77
  release() {
78
- this.#e !== 0 && (this.#e -= 1, this.#e === 0 && this.#t && this.#s());
78
+ this.#t !== 0 && (this.#t -= 1, this.#t === 0 && this.#e && this.#a());
79
79
  }
80
80
  /**
81
81
  * Close the pooled browser immediately, regardless of refcount.
@@ -84,239 +84,239 @@ class lt {
84
84
  */
85
85
  async shutdown() {
86
86
  this.#n();
87
- const e = this.#t;
88
- this.#t = void 0, this.#e = 0, e && await e.close();
87
+ const t = this.#e;
88
+ this.#e = void 0, this.#t = 0, t && await t.close();
89
89
  }
90
90
  /** Refcount of outstanding borrows. Exposed for tests / metrics. */
91
91
  get activeBorrows() {
92
- return this.#e;
92
+ return this.#t;
93
93
  }
94
94
  /** Whether a browser is currently launched. Exposed for tests. */
95
95
  get isLaunched() {
96
- return this.#t !== void 0;
96
+ return this.#e !== void 0;
97
97
  }
98
98
  // ─── internals ────────────────────────────────────────────────
99
99
  #n() {
100
- this.#r && (clearTimeout(this.#r), this.#r = void 0);
100
+ this.#o && (clearTimeout(this.#o), this.#o = void 0);
101
101
  }
102
- #s() {
103
- this.#n(), this.#r = setTimeout(() => {
104
- const e = this.#t;
105
- this.#t = void 0, this.#r = void 0, e?.close().catch(() => {
102
+ #a() {
103
+ this.#n(), this.#o = setTimeout(() => {
104
+ const t = this.#e;
105
+ this.#e = void 0, this.#o = void 0, t?.close().catch(() => {
106
106
  });
107
- }, this.#a), this.#r.unref?.();
107
+ }, this.#i), this.#o.unref?.();
108
108
  }
109
109
  }
110
- function dt(t = {}) {
111
- return new lt(
110
+ function ye(e = {}) {
111
+ return new ge(
112
112
  {
113
113
  async launch() {
114
- let e;
114
+ let t;
115
115
  try {
116
- ({ chromium: e } = await import("playwright-core"));
117
- } catch (r) {
118
- throw new C(
116
+ ({ chromium: t } = await import("playwright-core"));
117
+ } catch (o) {
118
+ throw new q(
119
119
  "Failed to load `playwright-core`. Reinstall `@ingcreators/annot-mcp` to restore the dependency.",
120
- r
120
+ o
121
121
  );
122
122
  }
123
123
  try {
124
- return await e.launch({ headless: !0 });
125
- } catch (r) {
126
- throw new C(
124
+ return await t.launch({ headless: !0 });
125
+ } catch (o) {
126
+ throw new q(
127
127
  "Failed to launch Chromium. Run `npx playwright install chromium` to download the runtime, then retry.",
128
- r
128
+ o
129
129
  );
130
130
  }
131
131
  }
132
132
  },
133
- t
133
+ e
134
134
  );
135
135
  }
136
- class C extends Error {
136
+ class q extends Error {
137
137
  cause;
138
- constructor(e, r) {
139
- super(e), this.name = "ChromiumUnavailableError", this.cause = r;
138
+ constructor(t, o) {
139
+ super(t), this.name = "ChromiumUnavailableError", this.cause = o;
140
140
  }
141
141
  }
142
- class F extends Error {
142
+ class N extends Error {
143
143
  locator;
144
- constructor(e, r) {
145
- super(r), this.name = "LocatorResolutionError", this.locator = e;
144
+ constructor(t, o) {
145
+ super(o), this.name = "LocatorResolutionError", this.locator = t;
146
146
  }
147
147
  }
148
- async function f(t, e) {
149
- const r = await t.locator(e).boundingBox();
150
- if (!r)
151
- throw new F(
152
- e,
153
- `Locator "${e}" resolved to no visible element. Check the selector matches at least one element and the element is inside the captured viewport.`
148
+ async function f(e, t) {
149
+ const o = await e.locator(t).boundingBox();
150
+ if (!o)
151
+ throw new N(
152
+ t,
153
+ `Locator "${t}" resolved to no visible element. Check the selector matches at least one element and the element is inside the captured viewport.`
154
154
  );
155
- return r;
155
+ return o;
156
156
  }
157
- async function ft(t, e) {
158
- switch (e.type) {
157
+ async function we(e, t) {
158
+ switch (t.type) {
159
159
  case "rect": {
160
- const r = e.bbox ?? await f(t, p(e.locator));
161
- return { ...m(e), type: "rect", bbox: r };
160
+ const o = t.bbox ?? await f(e, m(t.locator));
161
+ return { ...g(t), type: "rect", bbox: o };
162
162
  }
163
163
  case "circle": {
164
- if (e.center !== void 0 && e.radius !== void 0)
164
+ if (t.center !== void 0 && t.radius !== void 0)
165
165
  return {
166
- ...m(e),
166
+ ...g(t),
167
167
  type: "circle",
168
- center: e.center,
169
- radius: e.radius
168
+ center: t.center,
169
+ radius: t.radius
170
170
  };
171
- const r = await f(t, p(e.locator));
171
+ const o = await f(e, m(t.locator));
172
172
  return {
173
- ...m(e),
173
+ ...g(t),
174
174
  type: "circle",
175
- center: P(r),
176
- radius: Math.min(r.width, r.height) / 2
175
+ center: T(o),
176
+ radius: Math.min(o.width, o.height) / 2
177
177
  };
178
178
  }
179
179
  case "arrow": {
180
- const r = e.from ?? P(await f(t, p(e.fromLocator))), o = e.to ?? P(await f(t, p(e.toLocator)));
180
+ const o = t.from ?? T(await f(e, m(t.fromLocator))), n = t.to ?? T(await f(e, m(t.toLocator)));
181
181
  return {
182
- ...m(e),
182
+ ...g(t),
183
183
  type: "arrow",
184
- from: r,
185
- to: o
184
+ from: o,
185
+ to: n
186
186
  };
187
187
  }
188
188
  case "text": {
189
- const r = e.at ?? mt(
190
- await f(t, p(e.locator)),
191
- e.fontSize
192
- ), o = {
193
- ...m(e),
189
+ const o = t.at ?? $e(
190
+ await f(e, m(t.locator)),
191
+ t.fontSize
192
+ ), n = {
193
+ ...g(t),
194
194
  type: "text",
195
- at: r,
196
- content: e.content
195
+ at: o,
196
+ content: t.content
197
197
  };
198
- return e.fontSize !== void 0 && (o.fontSize = e.fontSize), e.anchor !== void 0 && (o.anchor = e.anchor), o;
198
+ return t.fontSize !== void 0 && (n.fontSize = t.fontSize), t.anchor !== void 0 && (n.anchor = t.anchor), n;
199
199
  }
200
200
  case "callout": {
201
- const r = e.at ?? await pt(t, e.atLocator), o = e.targetBbox ?? await f(t, p(e.targetLocator));
201
+ const o = t.at ?? await ve(e, t.atLocator), n = t.targetBbox ?? await f(e, m(t.targetLocator));
202
202
  return {
203
- ...m(e),
203
+ ...g(t),
204
204
  type: "callout",
205
- at: r,
206
- targetBbox: o,
207
- content: e.content
205
+ at: o,
206
+ targetBbox: n,
207
+ content: t.content
208
208
  };
209
209
  }
210
210
  case "raw":
211
- return e;
211
+ return t;
212
212
  }
213
213
  }
214
- async function ht(t, e) {
215
- const r = [];
216
- for (const o of e)
217
- r.push(await ft(t, o));
218
- return r;
214
+ async function be(e, t) {
215
+ const o = [];
216
+ for (const n of t)
217
+ o.push(await we(e, n));
218
+ return o;
219
219
  }
220
- async function pt(t, e) {
221
- if (!e)
222
- throw new F(
220
+ async function ve(e, t) {
221
+ if (!t)
222
+ throw new N(
223
223
  "<callout.at>",
224
224
  "callout annotations require either `at` or `atLocator`."
225
225
  );
226
- const r = await f(t, e);
227
- return P(r);
226
+ const o = await f(e, t);
227
+ return T(o);
228
228
  }
229
- function P(t) {
230
- return { x: t.x + t.width / 2, y: t.y + t.height / 2 };
229
+ function T(e) {
230
+ return { x: e.x + e.width / 2, y: e.y + e.height / 2 };
231
231
  }
232
- function mt(t, e) {
233
- const r = (e ?? 14) + 2;
234
- return { x: t.x, y: Math.max(0, t.y - r) };
232
+ function $e(e, t) {
233
+ const o = (t ?? 14) + 2;
234
+ return { x: e.x, y: Math.max(0, e.y - o) };
235
235
  }
236
- function p(t) {
237
- if (t === void 0)
238
- throw new F(
236
+ function m(e) {
237
+ if (e === void 0)
238
+ throw new N(
239
239
  "<missing>",
240
240
  "Internal error: annotation passed schema validation without a locator or bbox. This is a bug."
241
241
  );
242
- return t;
242
+ return e;
243
243
  }
244
- function m(t) {
245
- if (t.type === "raw")
244
+ function g(e) {
245
+ if (e.type === "raw")
246
246
  return {};
247
- const e = {};
248
- return t.intent !== void 0 && (e.intent = t.intent), t.stroke !== void 0 && (e.stroke = t.stroke), t.strokeWidth !== void 0 && (e.strokeWidth = t.strokeWidth), t.fill !== void 0 && (e.fill = t.fill), t.color !== void 0 && (e.color = t.color), e;
247
+ const t = {};
248
+ return e.intent !== void 0 && (t.intent = e.intent), e.stroke !== void 0 && (t.stroke = e.stroke), e.strokeWidth !== void 0 && (t.strokeWidth = e.strokeWidth), e.fill !== void 0 && (t.fill = e.fill), e.color !== void 0 && (t.color = e.color), t;
249
249
  }
250
- const gt = 4;
251
- function yt(t, e, r) {
252
- const o = new Uint8Array(e * r), i = [];
253
- for (let a = 0; a < r; a++)
254
- for (let n = 0; n < e; n++) {
255
- const s = a * e + n;
256
- if (o[s] || !G(t, s)) continue;
257
- const c = wt(t, o, n, a, e, r);
258
- c.count >= gt && i.push({
259
- x: c.minX,
260
- y: c.minY,
261
- width: c.maxX - c.minX + 1,
262
- height: c.maxY - c.minY + 1
250
+ const Ee = 4;
251
+ function xe(e, t, o) {
252
+ const n = new Uint8Array(t * o), s = [];
253
+ for (let c = 0; c < o; c++)
254
+ for (let r = 0; r < t; r++) {
255
+ const a = c * t + r;
256
+ if (n[a] || !X(e, a)) continue;
257
+ const i = Oe(e, n, r, c, t, o);
258
+ i.count >= Ee && s.push({
259
+ x: i.minX,
260
+ y: i.minY,
261
+ width: i.maxX - i.minX + 1,
262
+ height: i.maxY - i.minY + 1
263
263
  });
264
264
  }
265
- return i;
265
+ return s;
266
266
  }
267
- function G(t, e) {
268
- return t[e * 4 + 3] > 0;
267
+ function X(e, t) {
268
+ return e[t * 4 + 3] > 0;
269
269
  }
270
- function wt(t, e, r, o, i, a) {
271
- const n = {
270
+ function Oe(e, t, o, n, s, c) {
271
+ const r = {
272
272
  count: 0,
273
- minX: r,
274
- minY: o,
275
- maxX: r,
276
- maxY: o
277
- }, s = [r, o];
278
- for (; s.length > 0; ) {
279
- const c = s.pop(), u = s.pop();
280
- if (u < 0 || u >= i || c < 0 || c >= a) continue;
281
- const l = c * i + u;
282
- e[l] || G(t, l) && (e[l] = 1, n.count += 1, u < n.minX && (n.minX = u), c < n.minY && (n.minY = c), u > n.maxX && (n.maxX = u), c > n.maxY && (n.maxY = c), s.push(u + 1, c), s.push(u - 1, c), s.push(u, c + 1), s.push(u, c - 1));
273
+ minX: o,
274
+ minY: n,
275
+ maxX: o,
276
+ maxY: n
277
+ }, a = [o, n];
278
+ for (; a.length > 0; ) {
279
+ const i = a.pop(), d = a.pop();
280
+ if (d < 0 || d >= s || i < 0 || i >= c) continue;
281
+ const l = i * s + d;
282
+ t[l] || X(e, l) && (t[l] = 1, r.count += 1, d < r.minX && (r.minX = d), i < r.minY && (r.minY = i), d > r.maxX && (r.maxX = d), i > r.maxY && (r.maxY = i), a.push(d + 1, i), a.push(d - 1, i), a.push(d, i + 1), a.push(d, i - 1));
283
283
  }
284
- return n;
284
+ return r;
285
285
  }
286
- class bt extends Error {
287
- constructor(e, r) {
286
+ class Pe extends Error {
287
+ constructor(t, o) {
288
288
  super(
289
- `Cannot compare screenshots of different dimensions: before is ${e.width}×${e.height}, after is ${r.width}×${r.height}.`
289
+ `Cannot compare screenshots of different dimensions: before is ${t.width}×${t.height}, after is ${o.width}×${o.height}.`
290
290
  ), this.name = "DimensionMismatchError";
291
291
  }
292
292
  }
293
- async function vt(t, e, r = {}) {
294
- const [o, i] = await Promise.all([
295
- T(Buffer.from(t)),
296
- T(Buffer.from(e))
293
+ async function Se(e, t, o = {}) {
294
+ const [n, s] = await Promise.all([
295
+ C(Buffer.from(e)),
296
+ C(Buffer.from(t))
297
297
  ]);
298
- if (o.width !== i.width || o.height !== i.height)
299
- throw new bt(
300
- { width: o.width, height: o.height },
301
- { width: i.width, height: i.height }
298
+ if (n.width !== s.width || n.height !== s.height)
299
+ throw new Pe(
300
+ { width: n.width, height: n.height },
301
+ { width: s.width, height: s.height }
302
302
  );
303
- const { width: a, height: n } = o, s = N(o, a, n), c = N(i, a, n), u = new Uint8Array(a * n * 4), l = et(s, c, u, a, n, {
304
- threshold: r.threshold ?? 0.1,
303
+ const { width: c, height: r } = n, a = k(n, c, r), i = k(s, c, r), d = new Uint8Array(c * r * 4), l = ae(a, i, d, c, r, {
304
+ threshold: o.threshold ?? 0.1,
305
305
  includeAA: !1,
306
306
  diffMask: !0
307
- }), h = yt(u, a, n);
308
- return { mismatchedPixels: l, regions: h, width: a, height: n };
307
+ }), v = xe(d, c, r);
308
+ return { mismatchedPixels: l, regions: v, width: c, height: r };
309
309
  }
310
- function N(t, e, r) {
311
- const i = _(e, r).getContext("2d");
312
- i.drawImage(t, 0, 0);
313
- const a = i.getImageData(0, 0, e, r).data;
314
- return new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
310
+ function k(e, t, o) {
311
+ const s = F(t, o).getContext("2d");
312
+ s.drawImage(e, 0, 0);
313
+ const c = s.getImageData(0, 0, t, o).data;
314
+ return new Uint8Array(c.buffer, c.byteOffset, c.byteLength);
315
315
  }
316
- const O = {
317
- ...K,
316
+ const I = {
317
+ ...te,
318
318
  Locator: { type: "string", minLength: 1 }
319
- }, $t = {
319
+ }, Le = {
320
320
  type: "object",
321
321
  required: ["type"],
322
322
  additionalProperties: !1,
@@ -331,7 +331,7 @@ const O = {
331
331
  color: { type: "string" }
332
332
  },
333
333
  anyOf: [{ required: ["bbox"] }, { required: ["locator"] }]
334
- }, Et = {
334
+ }, Ae = {
335
335
  type: "object",
336
336
  required: ["type"],
337
337
  additionalProperties: !1,
@@ -347,7 +347,7 @@ const O = {
347
347
  color: { type: "string" }
348
348
  },
349
349
  anyOf: [{ required: ["center", "radius"] }, { required: ["locator"] }]
350
- }, xt = {
350
+ }, Te = {
351
351
  type: "object",
352
352
  required: ["type"],
353
353
  additionalProperties: !1,
@@ -366,7 +366,7 @@ const O = {
366
366
  { anyOf: [{ required: ["from"] }, { required: ["fromLocator"] }] },
367
367
  { anyOf: [{ required: ["to"] }, { required: ["toLocator"] }] }
368
368
  ]
369
- }, Lt = {
369
+ }, Re = {
370
370
  type: "object",
371
371
  required: ["type", "content"],
372
372
  additionalProperties: !1,
@@ -381,7 +381,7 @@ const O = {
381
381
  color: { type: "string" }
382
382
  },
383
383
  anyOf: [{ required: ["at"] }, { required: ["locator"] }]
384
- }, Pt = {
384
+ }, Ie = {
385
385
  type: "object",
386
386
  required: ["type", "content"],
387
387
  additionalProperties: !1,
@@ -400,7 +400,7 @@ const O = {
400
400
  { anyOf: [{ required: ["at"] }, { required: ["atLocator"] }] },
401
401
  { anyOf: [{ required: ["targetBbox"] }, { required: ["targetLocator"] }] }
402
402
  ]
403
- }, At = {
403
+ }, _e = {
404
404
  type: "object",
405
405
  required: ["type", "svgFragment"],
406
406
  additionalProperties: !1,
@@ -408,9 +408,40 @@ const O = {
408
408
  type: { const: "raw" },
409
409
  svgFragment: { type: "string" }
410
410
  }
411
- }, Ot = {
412
- oneOf: [$t, Et, xt, Lt, Pt, At]
413
- }, Rt = {
411
+ }, Ce = {
412
+ oneOf: [Le, Ae, Te, Re, Ie, _e]
413
+ }, P = {
414
+ type: "object",
415
+ additionalProperties: !1,
416
+ properties: {
417
+ format: {
418
+ type: "string",
419
+ enum: ["smart", "png", "jpeg"],
420
+ description: "Encoding strategy. `smart` (default) picks PNG-8 for UI-heavy content and PNG-32 / JPEG for photo-heavy content per `smartFallback`. `png` forces PNG-32 (lossless). `jpeg` forces JPEG at `jpegPercent` quality."
421
+ },
422
+ saveSizePreset: {
423
+ type: "string",
424
+ enum: ["light", "standard", "highQuality", "original"],
425
+ description: "Max-width cap. `light` = 1280px, `standard` = 1920px (default), `highQuality` = 2560px, `original` = no resize. Aspect-preserving; never upscales."
426
+ },
427
+ smartFallback: {
428
+ type: "string",
429
+ enum: ["png", "jpeg"],
430
+ description: "Fallback format used by smart mode when the image is photo-heavy. Default `png`."
431
+ },
432
+ smartColorThreshold: {
433
+ type: "integer",
434
+ minimum: 1,
435
+ description: "Unique-colour count above which smart mode treats the image as photo-heavy. Default 15000."
436
+ },
437
+ jpegPercent: {
438
+ type: "integer",
439
+ minimum: 60,
440
+ maximum: 100,
441
+ description: "JPEG quality 60–100. Default 92."
442
+ }
443
+ }
444
+ }, Ue = {
414
445
  type: "object",
415
446
  additionalProperties: !1,
416
447
  properties: {
@@ -420,125 +451,144 @@ const O = {
420
451
  color: { type: "string" }
421
452
  },
422
453
  anyOf: [{ required: ["bbox"] }, { required: ["locator"] }]
423
- }, B = [137, 80, 78, 71, 13, 10, 26, 10], E = 12, St = "IHDR", Tt = 16, It = 20, U = 24;
424
- class v extends Error {
425
- constructor(e) {
426
- super(e), this.name = "InvalidPngError";
454
+ }, j = [137, 80, 78, 71, 13, 10, 26, 10], L = 12, Fe = "IHDR", Ne = 16, Be = 20, G = 24;
455
+ class x extends Error {
456
+ constructor(t) {
457
+ super(t), this.name = "InvalidPngError";
427
458
  }
428
459
  }
429
- function M(t) {
430
- if (t.byteLength < U)
431
- throw new v(
432
- `Expected at least ${U} bytes for a PNG header, got ${t.byteLength}.`
460
+ function B(e) {
461
+ if (e.byteLength < G)
462
+ throw new x(
463
+ `Expected at least ${G} bytes for a PNG header, got ${e.byteLength}.`
433
464
  );
434
- for (let a = 0; a < B.length; a++)
435
- if (t[a] !== B[a])
436
- throw new v(
465
+ for (let c = 0; c < j.length; c++)
466
+ if (e[c] !== j[c])
467
+ throw new x(
437
468
  "Input does not start with the PNG signature (89 50 4E 47 0D 0A 1A 0A). Confirm the input is a PNG — JPEG / WebP / other formats are not supported in v1."
438
469
  );
439
- const e = new DataView(t.buffer, t.byteOffset, t.byteLength), r = String.fromCharCode(
440
- t[E],
441
- t[E + 1],
442
- t[E + 2],
443
- t[E + 3]
470
+ const t = new DataView(e.buffer, e.byteOffset, e.byteLength), o = String.fromCharCode(
471
+ e[L],
472
+ e[L + 1],
473
+ e[L + 2],
474
+ e[L + 3]
444
475
  );
445
- if (r !== St)
446
- throw new v(
447
- `Expected IHDR chunk after PNG signature, found "${r}". The file may be a corrupt or non-standard PNG.`
476
+ if (o !== Fe)
477
+ throw new x(
478
+ `Expected IHDR chunk after PNG signature, found "${o}". The file may be a corrupt or non-standard PNG.`
448
479
  );
449
- const o = e.getUint32(Tt, !1), i = e.getUint32(It, !1);
450
- if (o === 0 || i === 0)
451
- throw new v(`PNG dimensions ${o}×${i} include a zero axis.`);
452
- return { width: o, height: i };
480
+ const n = t.getUint32(Ne, !1), s = t.getUint32(Be, !1);
481
+ if (n === 0 || s === 0)
482
+ throw new x(`PNG dimensions ${n}×${s} include a zero axis.`);
483
+ return { width: n, height: s };
453
484
  }
454
- class y extends Error {
455
- constructor(e) {
456
- super(e), this.name = "InvalidImageInputError";
485
+ class w extends Error {
486
+ constructor(t) {
487
+ super(t), this.name = "InvalidImageInputError";
457
488
  }
458
489
  }
459
- const _t = "data:", Ft = /^data:image\/png;base64,/i;
460
- async function A(t) {
461
- if (typeof t != "string" || t.length === 0)
462
- throw new y(
490
+ const De = "data:", qe = /^data:image\/png;base64,/i;
491
+ async function R(e) {
492
+ if (typeof e != "string" || e.length === 0)
493
+ throw new w(
463
494
  "`image` must be a non-empty string (data URL or absolute filesystem path)."
464
495
  );
465
- if (t.startsWith(_t))
466
- return Ct(t);
467
- if (!w(t))
468
- throw new y(
469
- `Filesystem path "${t}" is not absolute. Pass an absolute path so resolution doesn't depend on the MCP server's working directory.`
496
+ if (e.startsWith(De))
497
+ return ke(e);
498
+ if (!b(e))
499
+ throw new w(
500
+ `Filesystem path "${e}" is not absolute. Pass an absolute path so resolution doesn't depend on the MCP server's working directory.`
470
501
  );
471
- return Nt(t);
502
+ return je(e);
472
503
  }
473
- function Ct(t) {
474
- if (!Ft.test(t))
475
- throw new y(
504
+ function ke(e) {
505
+ if (!qe.test(e))
506
+ throw new w(
476
507
  "Only `data:image/png;base64,...` URLs are supported. JPEG / WebP / SVG data URLs are not accepted in v1."
477
508
  );
478
- const e = t.slice(t.indexOf(",") + 1), r = Bt(e), o = H(r);
479
- return { bytes: r, dataUrl: t, dimensions: o };
509
+ const t = e.slice(e.indexOf(",") + 1), o = Ge(t), n = z(o);
510
+ return { bytes: o, dataUrl: e, dimensions: n };
480
511
  }
481
- async function Nt(t) {
482
- let e;
512
+ async function je(e) {
513
+ let t;
483
514
  try {
484
- const i = await rt(t);
485
- e = new Uint8Array(i.buffer, i.byteOffset, i.byteLength);
486
- } catch (i) {
487
- const a = i instanceof Error ? i.message : String(i);
488
- throw new y(`Failed to read image at "${t}": ${a}`);
515
+ const s = await ce(e);
516
+ t = new Uint8Array(s.buffer, s.byteOffset, s.byteLength);
517
+ } catch (s) {
518
+ const c = s instanceof Error ? s.message : String(s);
519
+ throw new w(`Failed to read image at "${e}": ${c}`);
489
520
  }
490
- const r = H(e), o = `data:image/png;base64,${Ut(e)}`;
491
- return { bytes: e, dataUrl: o, dimensions: r };
521
+ const o = z(t), n = `data:image/png;base64,${Me(t)}`;
522
+ return { bytes: t, dataUrl: n, dimensions: o };
492
523
  }
493
- function H(t) {
524
+ function z(e) {
494
525
  try {
495
- return M(t);
496
- } catch (e) {
497
- throw e instanceof v ? new y(e.message) : e;
526
+ return B(e);
527
+ } catch (t) {
528
+ throw t instanceof x ? new w(t.message) : t;
498
529
  }
499
530
  }
500
- function Bt(t) {
501
- const e = Buffer.from(t, "base64");
502
- return new Uint8Array(e.buffer, e.byteOffset, e.byteLength);
531
+ function Ge(e) {
532
+ const t = Buffer.from(e, "base64");
533
+ return new Uint8Array(t.buffer, t.byteOffset, t.byteLength);
503
534
  }
504
- function Ut(t) {
505
- return Buffer.from(t.buffer, t.byteOffset, t.byteLength).toString("base64");
535
+ function Me(e) {
536
+ return Buffer.from(e.buffer, e.byteOffset, e.byteLength).toString("base64");
506
537
  }
507
- const qt = "solid", Dt = "#000000", q = 16, kt = 12;
508
- async function W(t, e) {
509
- if (e.length === 0)
510
- return t;
511
- const r = await T(Buffer.from(t)), o = _(r.width, r.height), i = o.getContext("2d");
512
- i.drawImage(r, 0, 0);
513
- for (const n of e) {
514
- if (n.bbox.width <= 0 || n.bbox.height <= 0) continue;
515
- switch (n.style ?? qt) {
538
+ const He = "solid", We = "#000000", M = 16, Xe = 12;
539
+ async function Y(e, t) {
540
+ if (t.length === 0)
541
+ return e;
542
+ const o = await C(Buffer.from(e)), n = F(o.width, o.height), s = n.getContext("2d");
543
+ s.drawImage(o, 0, 0);
544
+ for (const r of t) {
545
+ if (r.bbox.width <= 0 || r.bbox.height <= 0) continue;
546
+ switch (r.style ?? He) {
516
547
  case "solid":
517
- Gt(i, n.bbox, n.color ?? Dt);
548
+ ze(s, r.bbox, r.color ?? We);
518
549
  break;
519
550
  case "mosaic":
520
- Mt(i, r, n.bbox);
551
+ Ye(s, o, r.bbox);
521
552
  break;
522
553
  case "blur":
523
- Ht(i, r, n.bbox);
554
+ Ve(s, o, r.bbox);
524
555
  break;
525
556
  }
526
557
  }
527
- const a = o.toBuffer("image/png");
528
- return new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
558
+ const c = n.toBuffer("image/png");
559
+ return new Uint8Array(c.buffer, c.byteOffset, c.byteLength);
529
560
  }
530
- function Gt(t, e, r) {
531
- t.save(), t.fillStyle = r, t.fillRect(e.x, e.y, e.width, e.height), t.restore();
561
+ function ze(e, t, o) {
562
+ e.save(), e.fillStyle = o, e.fillRect(t.x, t.y, t.width, t.height), e.restore();
532
563
  }
533
- function Mt(t, e, r) {
534
- const o = Math.max(1, Math.round(r.width / q)), i = Math.max(1, Math.round(r.height / q)), a = _(o, i), n = a.getContext("2d");
535
- n.imageSmoothingEnabled = !1, n.drawImage(e, r.x, r.y, r.width, r.height, 0, 0, o, i), t.save(), t.imageSmoothingEnabled = !1, t.drawImage(a, 0, 0, o, i, r.x, r.y, r.width, r.height), t.restore();
564
+ function Ye(e, t, o) {
565
+ const n = Math.max(1, Math.round(o.width / M)), s = Math.max(1, Math.round(o.height / M)), c = F(n, s), r = c.getContext("2d");
566
+ r.imageSmoothingEnabled = !1, r.drawImage(t, o.x, o.y, o.width, o.height, 0, 0, n, s), e.save(), e.imageSmoothingEnabled = !1, e.drawImage(c, 0, 0, n, s, o.x, o.y, o.width, o.height), e.restore();
536
567
  }
537
- function Ht(t, e, r) {
538
- t.save(), t.beginPath(), t.rect(r.x, r.y, r.width, r.height), t.clip(), t.filter = `blur(${kt}px)`, t.drawImage(e, 0, 0), t.restore();
568
+ function Ve(e, t, o) {
569
+ e.save(), e.beginPath(), e.rect(o.x, o.y, o.width, o.height), e.clip(), e.filter = `blur(${Xe}px)`, e.drawImage(t, 0, 0), e.restore();
539
570
  }
540
- const j = "annot_annotate_screenshot", Wt = {
541
- name: j,
571
+ async function S(e, t, o) {
572
+ if (!o || Object.keys(o).length === 0)
573
+ return {
574
+ bytes: e,
575
+ mimeType: "image/png",
576
+ chosen: "png",
577
+ width: t.width,
578
+ height: t.height
579
+ };
580
+ const n = { ...oe, ...o }, s = await re(e, n);
581
+ return {
582
+ bytes: s.bytes,
583
+ mimeType: s.chosen === "jpeg" ? "image/jpeg" : "image/png",
584
+ chosen: s.chosen,
585
+ width: s.width,
586
+ height: s.height,
587
+ ...s.reason ? { reason: s.reason } : {}
588
+ };
589
+ }
590
+ const V = "annot_annotate_screenshot", Je = {
591
+ name: V,
542
592
  description: "Overlay annotations (rectangles, circles, arrows, callouts, text) on a PNG screenshot. Annotation positions are specified as bounding boxes or points; pair with `annot_annotate_url` if you want locator-driven positioning. Returns the annotated PNG inline unless `output` is specified, in which case the PNG is written to that absolute path.",
543
593
  inputSchema: {
544
594
  type: "object",
@@ -557,76 +607,92 @@ const j = "annot_annotate_screenshot", Wt = {
557
607
  output: {
558
608
  type: "string",
559
609
  description: "Optional absolute filesystem path. When set, the annotated PNG is written here and the tool returns a text confirmation; otherwise the PNG bytes are returned inline."
610
+ },
611
+ encode: {
612
+ $ref: "#/$defs/EncodeOptions",
613
+ description: 'Optional encoder settings. When set, the output PNG-32 is decoded and re-encoded per `format` / `saveSizePreset` for size savings — `format: "smart"` + `saveSizePreset: "standard"` gives ~50–80% byte reduction typical for UI screenshots.'
560
614
  }
561
615
  },
562
616
  $defs: {
563
- ...O,
564
- BboxAnnotation: Z
617
+ ...I,
618
+ BboxAnnotation: ne,
619
+ EncodeOptions: P
565
620
  }
566
621
  }
567
622
  };
568
- async function jt(t, e) {
623
+ async function Qe(e, t) {
569
624
  try {
570
- const r = Xt(t), o = await A(r.image), i = I(r.annotations), a = e.annotator.toPng({
571
- originalDataUrl: o.dataUrl,
572
- annotationsSvg: i,
573
- width: o.dimensions.width,
574
- height: o.dimensions.height
575
- });
576
- return r.output ? (await $(r.output, a), {
577
- content: [
578
- {
579
- type: "text",
580
- text: `Wrote ${a.byteLength}-byte annotated PNG to ${r.output} (${o.dimensions.width}×${o.dimensions.height}, ${r.annotations.length} annotation${r.annotations.length === 1 ? "" : "s"}).`
581
- }
582
- ]
583
- }) : {
625
+ const o = Ke(e), n = await R(o.image), s = U(o.annotations), c = t.annotator.toPng({
626
+ originalDataUrl: n.dataUrl,
627
+ annotationsSvg: s,
628
+ width: n.dimensions.width,
629
+ height: n.dimensions.height
630
+ }), r = await S(c, n.dimensions, o.encode);
631
+ if (o.output) {
632
+ await O(o.output, r.bytes);
633
+ const a = r.reason ? `, reason: ${r.reason}` : "";
634
+ return {
635
+ content: [
636
+ {
637
+ type: "text",
638
+ text: `Wrote ${r.bytes.byteLength}-byte ${r.chosen.toUpperCase()} to ${o.output} (${r.width}×${r.height}, ${o.annotations.length} annotation${o.annotations.length === 1 ? "" : "s"}${a}).`
639
+ }
640
+ ]
641
+ };
642
+ }
643
+ return {
584
644
  content: [
585
645
  {
586
646
  type: "image",
587
- data: zt(a),
588
- mimeType: "image/png"
647
+ data: et(r.bytes),
648
+ mimeType: r.mimeType
589
649
  }
590
650
  ]
591
651
  };
592
- } catch (r) {
593
- return Yt(r);
652
+ } catch (o) {
653
+ return Ze(o);
594
654
  }
595
655
  }
596
- function Xt(t) {
597
- if (typeof t.image != "string")
598
- throw new y("`image` is required and must be a string.");
599
- if (!Array.isArray(t.annotations))
600
- throw new S("`annotations` is required and must be an array.");
601
- const e = t.annotations;
602
- let r;
603
- if (t.output !== void 0) {
604
- if (typeof t.output != "string")
605
- throw new S("`output` must be a string when provided.");
606
- if (!w(t.output))
607
- throw new S(
608
- `\`output\` path "${t.output}" must be absolute so the file lands at a predictable location.`
656
+ function Ke(e) {
657
+ if (typeof e.image != "string")
658
+ throw new w("`image` is required and must be a string.");
659
+ if (!Array.isArray(e.annotations))
660
+ throw new A("`annotations` is required and must be an array.");
661
+ const t = e.annotations;
662
+ let o;
663
+ if (e.output !== void 0) {
664
+ if (typeof e.output != "string")
665
+ throw new A("`output` must be a string when provided.");
666
+ if (!b(e.output))
667
+ throw new A(
668
+ `\`output\` path "${e.output}" must be absolute so the file lands at a predictable location.`
609
669
  );
610
- r = t.output;
670
+ o = e.output;
671
+ }
672
+ let n;
673
+ if (e.encode !== void 0) {
674
+ if (typeof e.encode != "object" || e.encode === null)
675
+ throw new A("`encode` must be an object when provided.");
676
+ n = e.encode;
611
677
  }
612
- return { image: t.image, annotations: e, output: r };
678
+ return { image: e.image, annotations: t, output: o, encode: n };
613
679
  }
614
- class S extends Error {
615
- constructor(e) {
616
- super(e), this.name = "InvalidToolInputError";
680
+ class A extends Error {
681
+ constructor(t) {
682
+ super(t), this.name = "InvalidToolInputError";
617
683
  }
618
684
  }
619
- function Yt(t) {
685
+ function Ze(e) {
620
686
  return {
621
- content: [{ type: "text", text: t instanceof Error ? `${t.name}: ${t.message}` : `Unknown error: ${String(t)}` }],
687
+ content: [{ type: "text", text: e instanceof Error ? `${e.name}: ${e.message}` : `Unknown error: ${String(e)}` }],
622
688
  isError: !0
623
689
  };
624
690
  }
625
- function zt(t) {
626
- return Buffer.from(t.buffer, t.byteOffset, t.byteLength).toString("base64");
691
+ function et(e) {
692
+ return Buffer.from(e.buffer, e.byteOffset, e.byteLength).toString("base64");
627
693
  }
628
- const X = "annot_annotate_url", Vt = {
629
- name: X,
694
+ const J = "annot_annotate_url", tt = {
695
+ name: J,
630
696
  description: 'Open a URL in a headless browser, capture a screenshot, and overlay annotations whose positions are specified as Playwright locator strings (`button:has-text("Submit")`, `[data-testid="email"]`, `role=button[name="Sign in"]`) or bounding boxes. Returns the annotated PNG inline unless `output` is specified.',
631
697
  inputSchema: {
632
698
  type: "object",
@@ -666,104 +732,121 @@ const X = "annot_annotate_url", Vt = {
666
732
  output: {
667
733
  type: "string",
668
734
  description: "Optional absolute filesystem path. When set, the annotated PNG is written here and the tool returns a text confirmation."
735
+ },
736
+ encode: {
737
+ $ref: "#/$defs/EncodeOptions",
738
+ description: "Optional encoder settings (`format` / `saveSizePreset` / `jpegPercent`). Set to shrink the output for ingestion into issue trackers / docs."
669
739
  }
670
740
  },
671
741
  $defs: {
672
- ...O,
673
- LocatorAnnotation: Ot
742
+ ...I,
743
+ LocatorAnnotation: Ce,
744
+ EncodeOptions: P
674
745
  }
675
746
  }
676
747
  };
677
- class b extends Error {
678
- constructor(e) {
679
- super(e), this.name = "InvalidAnnotateUrlInputError";
748
+ class y extends Error {
749
+ constructor(t) {
750
+ super(t), this.name = "InvalidAnnotateUrlInputError";
680
751
  }
681
752
  }
682
- async function Jt(t, e) {
753
+ async function ot(e, t) {
683
754
  try {
684
- const r = Kt(t), o = await k(e.pool, {
685
- url: r.url,
686
- viewport: r.viewport,
687
- fullPage: r.fullPage,
688
- waitFor: r.waitFor
755
+ const o = rt(e), n = await W(t.pool, {
756
+ url: o.url,
757
+ viewport: o.viewport,
758
+ fullPage: o.fullPage,
759
+ waitFor: o.waitFor
689
760
  });
690
- let i;
761
+ let s;
691
762
  try {
692
- i = await ht(
693
- o.handle.page,
694
- r.annotations
763
+ s = await be(
764
+ n.handle.page,
765
+ o.annotations
695
766
  );
696
767
  } finally {
697
- await o.handle.close();
768
+ await n.handle.close();
698
769
  }
699
- const a = M(o.pngBytes), n = I(i), s = e.annotator.toPng({
700
- originalDataUrl: `data:image/png;base64,${D(o.pngBytes)}`,
701
- annotationsSvg: n,
702
- width: a.width,
703
- height: a.height
704
- });
705
- return r.output ? (await $(r.output, s), {
706
- content: [
707
- {
708
- type: "text",
709
- text: `Wrote ${s.byteLength}-byte annotated PNG to ${r.output} (${a.width}×${a.height}, ${r.annotations.length} annotation${r.annotations.length === 1 ? "" : "s"}, captured from ${r.url}).`
710
- }
711
- ]
712
- }) : {
770
+ const c = B(n.pngBytes), r = U(s), a = t.annotator.toPng({
771
+ originalDataUrl: `data:image/png;base64,${H(n.pngBytes)}`,
772
+ annotationsSvg: r,
773
+ width: c.width,
774
+ height: c.height
775
+ }), i = await S(a, c, o.encode);
776
+ if (o.output) {
777
+ await O(o.output, i.bytes);
778
+ const d = i.reason ? `, reason: ${i.reason}` : "";
779
+ return {
780
+ content: [
781
+ {
782
+ type: "text",
783
+ text: `Wrote ${i.bytes.byteLength}-byte ${i.chosen.toUpperCase()} to ${o.output} (${i.width}×${i.height}, ${o.annotations.length} annotation${o.annotations.length === 1 ? "" : "s"}, captured from ${o.url}${d}).`
784
+ }
785
+ ]
786
+ };
787
+ }
788
+ return {
713
789
  content: [
714
790
  {
715
791
  type: "image",
716
- data: D(s),
717
- mimeType: "image/png"
792
+ data: H(i.bytes),
793
+ mimeType: i.mimeType
718
794
  }
719
795
  ]
720
796
  };
721
- } catch (r) {
722
- return Zt(r);
797
+ } catch (o) {
798
+ return nt(o);
723
799
  }
724
800
  }
725
- function Kt(t) {
726
- if (typeof t.url != "string" || t.url.length === 0)
727
- throw new b("`url` is required and must be a non-empty string.");
728
- if (!Array.isArray(t.annotations))
729
- throw new b("`annotations` is required and must be an array.");
730
- const e = t.annotations;
731
- let r;
732
- if (t.viewport !== void 0) {
733
- if (typeof t.viewport != "object" || t.viewport === null)
734
- throw new b("`viewport` must be an object when provided.");
735
- const n = t.viewport, s = typeof n.width == "number" ? n.width : 1280, c = typeof n.height == "number" ? n.height : 800, u = typeof n.deviceScaleFactor == "number" ? n.deviceScaleFactor : 1;
736
- r = { width: s, height: c, deviceScaleFactor: u };
801
+ function rt(e) {
802
+ if (typeof e.url != "string" || e.url.length === 0)
803
+ throw new y("`url` is required and must be a non-empty string.");
804
+ if (!Array.isArray(e.annotations))
805
+ throw new y("`annotations` is required and must be an array.");
806
+ const t = e.annotations;
807
+ let o;
808
+ if (e.viewport !== void 0) {
809
+ if (typeof e.viewport != "object" || e.viewport === null)
810
+ throw new y("`viewport` must be an object when provided.");
811
+ const a = e.viewport, i = typeof a.width == "number" ? a.width : 1280, d = typeof a.height == "number" ? a.height : 800, l = typeof a.deviceScaleFactor == "number" ? a.deviceScaleFactor : 1;
812
+ o = { width: i, height: d, deviceScaleFactor: l };
737
813
  }
738
- const o = t.fullPage === !0, i = t.waitFor === "domcontentloaded" || t.waitFor === "networkidle" ? t.waitFor : "load";
739
- let a;
740
- if (t.output !== void 0) {
741
- if (typeof t.output != "string")
742
- throw new b("`output` must be a string when provided.");
743
- if (!w(t.output))
744
- throw new b(`\`output\` path "${t.output}" must be absolute.`);
745
- a = t.output;
814
+ const n = e.fullPage === !0, s = e.waitFor === "domcontentloaded" || e.waitFor === "networkidle" ? e.waitFor : "load";
815
+ let c;
816
+ if (e.output !== void 0) {
817
+ if (typeof e.output != "string")
818
+ throw new y("`output` must be a string when provided.");
819
+ if (!b(e.output))
820
+ throw new y(`\`output\` path "${e.output}" must be absolute.`);
821
+ c = e.output;
822
+ }
823
+ let r;
824
+ if (e.encode !== void 0) {
825
+ if (typeof e.encode != "object" || e.encode === null)
826
+ throw new y("`encode` must be an object when provided.");
827
+ r = e.encode;
746
828
  }
747
829
  return {
748
- url: t.url,
749
- annotations: e,
750
- viewport: r,
751
- fullPage: o,
752
- waitFor: i,
753
- output: a
830
+ url: e.url,
831
+ annotations: t,
832
+ viewport: o,
833
+ fullPage: n,
834
+ waitFor: s,
835
+ output: c,
836
+ encode: r
754
837
  };
755
838
  }
756
- function Zt(t) {
839
+ function nt(e) {
757
840
  return {
758
- content: [{ type: "text", text: t instanceof Error ? `${t.name}: ${t.message}` : `Unknown error: ${String(t)}` }],
841
+ content: [{ type: "text", text: e instanceof Error ? `${e.name}: ${e.message}` : `Unknown error: ${String(e)}` }],
759
842
  isError: !0
760
843
  };
761
844
  }
762
- function D(t) {
763
- return Buffer.from(t.buffer, t.byteOffset, t.byteLength).toString("base64");
845
+ function H(e) {
846
+ return Buffer.from(e.buffer, e.byteOffset, e.byteLength).toString("base64");
764
847
  }
765
- const Y = "annot_compare_screenshots", Qt = {
766
- name: Y,
848
+ const Q = "annot_compare_screenshots", st = {
849
+ name: Q,
767
850
  description: "Compare two screenshots (must have identical dimensions) and return a PNG of the `after` image with changed regions highlighted as red rectangles. Useful for visual-diff PR review.",
768
851
  inputSchema: {
769
852
  type: "object",
@@ -790,69 +873,88 @@ const Y = "annot_compare_screenshots", Qt = {
790
873
  default: !1,
791
874
  description: "When true, append a text content block listing the changed-region bboxes alongside the annotated PNG."
792
875
  },
793
- output: { type: "string" }
876
+ output: { type: "string" },
877
+ encode: { $ref: "#/$defs/EncodeOptions" }
878
+ },
879
+ $defs: {
880
+ EncodeOptions: P
794
881
  }
795
882
  }
796
883
  };
797
- class x extends Error {
798
- constructor(e) {
799
- super(e), this.name = "InvalidCompareInputError";
884
+ class $ extends Error {
885
+ constructor(t) {
886
+ super(t), this.name = "InvalidCompareInputError";
800
887
  }
801
888
  }
802
- async function te(t, e) {
889
+ async function it(e, t) {
803
890
  try {
804
- if (typeof t.before != "string")
805
- throw new x("`before` is required and must be a string.");
806
- if (typeof t.after != "string")
807
- throw new x("`after` is required and must be a string.");
808
- const r = typeof t.threshold == "number" ? t.threshold : 0.1, o = t.includeChangeList === !0;
809
- let i;
810
- if (t.output !== void 0) {
811
- if (typeof t.output != "string")
812
- throw new x("`output` must be a string when provided.");
813
- if (!w(t.output))
814
- throw new x(`\`output\` path "${t.output}" must be absolute.`);
815
- i = t.output;
891
+ if (typeof e.before != "string")
892
+ throw new $("`before` is required and must be a string.");
893
+ if (typeof e.after != "string")
894
+ throw new $("`after` is required and must be a string.");
895
+ const o = typeof e.threshold == "number" ? e.threshold : 0.1, n = e.includeChangeList === !0;
896
+ let s;
897
+ if (e.output !== void 0) {
898
+ if (typeof e.output != "string")
899
+ throw new $("`output` must be a string when provided.");
900
+ if (!b(e.output))
901
+ throw new $(`\`output\` path "${e.output}" must be absolute.`);
902
+ s = e.output;
816
903
  }
817
- const [a, n] = await Promise.all([
818
- A(t.before),
819
- A(t.after)
820
- ]), s = await vt(a.bytes, n.bytes, { threshold: r }), c = s.regions.map((d) => ({
904
+ let c;
905
+ if (e.encode !== void 0) {
906
+ if (typeof e.encode != "object" || e.encode === null)
907
+ throw new $("`encode` must be an object when provided.");
908
+ c = e.encode;
909
+ }
910
+ const [r, a] = await Promise.all([
911
+ R(e.before),
912
+ R(e.after)
913
+ ]), i = await Se(r.bytes, a.bytes, { threshold: o }), d = i.regions.map((h) => ({
821
914
  type: "rect",
822
- bbox: d,
915
+ bbox: h,
823
916
  intent: "warning"
824
- })), u = I(c), l = e.annotator.toPng({
825
- originalDataUrl: n.dataUrl,
826
- annotationsSvg: u,
827
- width: s.width,
828
- height: s.height
829
- });
830
- if (i)
831
- return await $(i, l), { content: [{ type: "text", text: `Wrote ${l.byteLength}-byte diff-annotated PNG to ${i} (${s.width}×${s.height}, ${s.regions.length} changed region${s.regions.length === 1 ? "" : "s"}, ${s.mismatchedPixels} mismatched pixel${s.mismatchedPixels === 1 ? "" : "s"}).` }] };
832
- const h = {
917
+ })), l = U(d), v = t.annotator.toPng({
918
+ originalDataUrl: a.dataUrl,
919
+ annotationsSvg: l,
920
+ width: i.width,
921
+ height: i.height
922
+ }), u = await S(
923
+ v,
924
+ { width: i.width, height: i.height },
925
+ c
926
+ );
927
+ if (s) {
928
+ await O(s, u.bytes);
929
+ const h = u.reason ? `, reason: ${u.reason}` : "";
930
+ return { content: [{ type: "text", text: `Wrote ${u.bytes.byteLength}-byte diff-annotated ${u.chosen.toUpperCase()} to ${s} (${u.width}×${u.height}, ${i.regions.length} changed region${i.regions.length === 1 ? "" : "s"}, ${i.mismatchedPixels} mismatched pixel${i.mismatchedPixels === 1 ? "" : "s"}${h}).` }] };
931
+ }
932
+ const _ = {
833
933
  type: "image",
834
- data: Buffer.from(l.buffer, l.byteOffset, l.byteLength).toString(
835
- "base64"
836
- ),
837
- mimeType: "image/png"
934
+ data: Buffer.from(
935
+ u.bytes.buffer,
936
+ u.bytes.byteOffset,
937
+ u.bytes.byteLength
938
+ ).toString("base64"),
939
+ mimeType: u.mimeType
838
940
  };
839
- if (!o)
840
- return { content: [h] };
841
- const R = `${s.regions.length} changed region${s.regions.length === 1 ? "" : "s"}, ${s.mismatchedPixels} mismatched pixel${s.mismatchedPixels === 1 ? "" : "s"}:
842
- ` + s.regions.map((d, J) => ` [${J + 1}] x=${d.x} y=${d.y} w=${d.width} h=${d.height}`).join(`
941
+ if (!n)
942
+ return { content: [_] };
943
+ const ee = `${i.regions.length} changed region${i.regions.length === 1 ? "" : "s"}, ${i.mismatchedPixels} mismatched pixel${i.mismatchedPixels === 1 ? "" : "s"}:
944
+ ` + i.regions.map((h, D) => ` [${D + 1}] x=${h.x} y=${h.y} w=${h.width} h=${h.height}`).join(`
843
945
  `);
844
946
  return {
845
- content: [h, { type: "text", text: R }]
947
+ content: [_, { type: "text", text: ee }]
846
948
  };
847
- } catch (r) {
949
+ } catch (o) {
848
950
  return {
849
- content: [{ type: "text", text: r instanceof Error ? `${r.name}: ${r.message}` : `Unknown error: ${String(r)}` }],
951
+ content: [{ type: "text", text: o instanceof Error ? `${o.name}: ${o.message}` : `Unknown error: ${String(o)}` }],
850
952
  isError: !0
851
953
  };
852
954
  }
853
955
  }
854
- const z = "annot_redact_screenshot", ee = {
855
- name: z,
956
+ const K = "annot_redact_screenshot", at = {
957
+ name: K,
856
958
  description: "Destructively burn redactions (solid / mosaic / blur) into a PNG screenshot. The original pixels under each region are irrecoverably replaced. Returns the redacted PNG inline unless `output` is specified.",
857
959
  inputSchema: {
858
960
  type: "object",
@@ -867,64 +969,80 @@ const z = "annot_redact_screenshot", ee = {
867
969
  type: "array",
868
970
  items: { $ref: "#/$defs/BboxRedactRegion" }
869
971
  },
870
- output: { type: "string" }
972
+ output: { type: "string" },
973
+ encode: {
974
+ $ref: "#/$defs/EncodeOptions",
975
+ description: "Optional encoder settings applied after the redactions are burned in. Useful when the redacted screenshot is destined for an issue tracker / docs and size matters."
976
+ }
871
977
  },
872
978
  $defs: {
873
- ...O,
874
- BboxRedactRegion: Q
979
+ ...I,
980
+ BboxRedactRegion: se,
981
+ EncodeOptions: P
875
982
  }
876
983
  }
877
984
  };
878
- class L extends Error {
879
- constructor(e) {
880
- super(e), this.name = "InvalidRedactInputError";
985
+ class E extends Error {
986
+ constructor(t) {
987
+ super(t), this.name = "InvalidRedactInputError";
881
988
  }
882
989
  }
883
- async function re(t) {
990
+ async function ct(e) {
884
991
  try {
885
- if (typeof t.image != "string")
886
- throw new L("`image` is required and must be a string.");
887
- if (!Array.isArray(t.regions))
888
- throw new L("`regions` is required and must be an array.");
889
- const e = t.regions;
890
- let r;
891
- if (t.output !== void 0) {
892
- if (typeof t.output != "string")
893
- throw new L("`output` must be a string when provided.");
894
- if (!w(t.output))
895
- throw new L(`\`output\` path "${t.output}" must be absolute.`);
896
- r = t.output;
992
+ if (typeof e.image != "string")
993
+ throw new E("`image` is required and must be a string.");
994
+ if (!Array.isArray(e.regions))
995
+ throw new E("`regions` is required and must be an array.");
996
+ const t = e.regions;
997
+ let o;
998
+ if (e.output !== void 0) {
999
+ if (typeof e.output != "string")
1000
+ throw new E("`output` must be a string when provided.");
1001
+ if (!b(e.output))
1002
+ throw new E(`\`output\` path "${e.output}" must be absolute.`);
1003
+ o = e.output;
897
1004
  }
898
- const o = await A(t.image), i = await W(o.bytes, e);
899
- return r ? (await $(r, i), {
900
- content: [
901
- {
902
- type: "text",
903
- text: `Wrote ${i.byteLength}-byte redacted PNG to ${r} (${o.dimensions.width}×${o.dimensions.height}, ${e.length} region${e.length === 1 ? "" : "s"}).`
904
- }
905
- ]
906
- }) : {
1005
+ let n;
1006
+ if (e.encode !== void 0) {
1007
+ if (typeof e.encode != "object" || e.encode === null)
1008
+ throw new E("`encode` must be an object when provided.");
1009
+ n = e.encode;
1010
+ }
1011
+ const s = await R(e.image), c = await Y(s.bytes, t), r = await S(c, s.dimensions, n);
1012
+ if (o) {
1013
+ await O(o, r.bytes);
1014
+ const a = r.reason ? `, reason: ${r.reason}` : "";
1015
+ return {
1016
+ content: [
1017
+ {
1018
+ type: "text",
1019
+ text: `Wrote ${r.bytes.byteLength}-byte redacted ${r.chosen.toUpperCase()} to ${o} (${r.width}×${r.height}, ${t.length} region${t.length === 1 ? "" : "s"}${a}).`
1020
+ }
1021
+ ]
1022
+ };
1023
+ }
1024
+ return {
907
1025
  content: [
908
1026
  {
909
1027
  type: "image",
910
1028
  data: Buffer.from(
911
- i.buffer,
912
- i.byteOffset,
913
- i.byteLength
1029
+ r.bytes.buffer,
1030
+ r.bytes.byteOffset,
1031
+ r.bytes.byteLength
914
1032
  ).toString("base64"),
915
- mimeType: "image/png"
1033
+ mimeType: r.mimeType
916
1034
  }
917
1035
  ]
918
1036
  };
919
- } catch (e) {
1037
+ } catch (t) {
920
1038
  return {
921
- content: [{ type: "text", text: e instanceof Error ? `${e.name}: ${e.message}` : `Unknown error: ${String(e)}` }],
1039
+ content: [{ type: "text", text: t instanceof Error ? `${t.name}: ${t.message}` : `Unknown error: ${String(t)}` }],
922
1040
  isError: !0
923
1041
  };
924
1042
  }
925
1043
  }
926
- const V = "annot_redact_url", oe = {
927
- name: V,
1044
+ const Z = "annot_redact_url", dt = {
1045
+ name: Z,
928
1046
  description: "Open a URL in a headless browser, capture a screenshot, and destructively burn redactions over regions identified by locator strings or bboxes. Returns the redacted PNG inline unless `output` is specified.",
929
1047
  inputSchema: {
930
1048
  type: "object",
@@ -951,186 +1069,199 @@ const V = "annot_redact_url", oe = {
951
1069
  enum: ["load", "domcontentloaded", "networkidle"],
952
1070
  default: "load"
953
1071
  },
954
- output: { type: "string" }
1072
+ output: { type: "string" },
1073
+ encode: { $ref: "#/$defs/EncodeOptions" }
955
1074
  },
956
1075
  $defs: {
957
- ...O,
958
- LocatorRedactRegion: Rt
1076
+ ...I,
1077
+ LocatorRedactRegion: Ue,
1078
+ EncodeOptions: P
959
1079
  }
960
1080
  }
961
1081
  };
962
- class g extends Error {
963
- constructor(e) {
964
- super(e), this.name = "InvalidRedactUrlInputError";
1082
+ class p extends Error {
1083
+ constructor(t) {
1084
+ super(t), this.name = "InvalidRedactUrlInputError";
965
1085
  }
966
1086
  }
967
- async function ne(t, e) {
1087
+ async function lt(e, t) {
968
1088
  try {
969
- const r = ie(t), o = await k(e.pool, {
970
- url: r.url,
971
- viewport: r.viewport,
972
- fullPage: r.fullPage,
973
- waitFor: r.waitFor
1089
+ const o = ut(e), n = await W(t.pool, {
1090
+ url: o.url,
1091
+ viewport: o.viewport,
1092
+ fullPage: o.fullPage,
1093
+ waitFor: o.waitFor
974
1094
  });
975
- let i;
1095
+ let s;
976
1096
  try {
977
- i = [];
978
- for (const n of r.regions) {
979
- const c = { bbox: await ae(o.handle.page, n) };
980
- n.style !== void 0 && (c.style = n.style), n.color !== void 0 && (c.color = n.color), i.push(c);
1097
+ s = [];
1098
+ for (const i of o.regions) {
1099
+ const l = { bbox: await ht(n.handle.page, i) };
1100
+ i.style !== void 0 && (l.style = i.style), i.color !== void 0 && (l.color = i.color), s.push(l);
981
1101
  }
982
1102
  } finally {
983
- await o.handle.close();
1103
+ await n.handle.close();
984
1104
  }
985
- const a = await W(o.pngBytes, i);
986
- return r.output ? (await $(r.output, a), {
987
- content: [
988
- {
989
- type: "text",
990
- text: `Wrote ${a.byteLength}-byte redacted PNG to ${r.output} (${r.regions.length} region${r.regions.length === 1 ? "" : "s"}, captured from ${r.url}).`
991
- }
992
- ]
993
- }) : {
1105
+ const c = await Y(n.pngBytes, s), r = B(n.pngBytes), a = await S(c, r, o.encode);
1106
+ if (o.output) {
1107
+ await O(o.output, a.bytes);
1108
+ const i = a.reason ? `, reason: ${a.reason}` : "";
1109
+ return {
1110
+ content: [
1111
+ {
1112
+ type: "text",
1113
+ text: `Wrote ${a.bytes.byteLength}-byte redacted ${a.chosen.toUpperCase()} to ${o.output} (${a.width}×${a.height}, ${o.regions.length} region${o.regions.length === 1 ? "" : "s"}, captured from ${o.url}${i}).`
1114
+ }
1115
+ ]
1116
+ };
1117
+ }
1118
+ return {
994
1119
  content: [
995
1120
  {
996
1121
  type: "image",
997
1122
  data: Buffer.from(
998
- a.buffer,
999
- a.byteOffset,
1000
- a.byteLength
1123
+ a.bytes.buffer,
1124
+ a.bytes.byteOffset,
1125
+ a.bytes.byteLength
1001
1126
  ).toString("base64"),
1002
- mimeType: "image/png"
1127
+ mimeType: a.mimeType
1003
1128
  }
1004
1129
  ]
1005
1130
  };
1006
- } catch (r) {
1131
+ } catch (o) {
1007
1132
  return {
1008
- content: [{ type: "text", text: r instanceof Error ? `${r.name}: ${r.message}` : `Unknown error: ${String(r)}` }],
1133
+ content: [{ type: "text", text: o instanceof Error ? `${o.name}: ${o.message}` : `Unknown error: ${String(o)}` }],
1009
1134
  isError: !0
1010
1135
  };
1011
1136
  }
1012
1137
  }
1013
- function ie(t) {
1014
- if (typeof t.url != "string" || t.url.length === 0)
1015
- throw new g("`url` is required and must be a non-empty string.");
1016
- if (!Array.isArray(t.regions))
1017
- throw new g("`regions` is required and must be an array.");
1018
- const e = t.regions;
1019
- let r;
1020
- if (t.viewport !== void 0) {
1021
- if (typeof t.viewport != "object" || t.viewport === null)
1022
- throw new g("`viewport` must be an object when provided.");
1023
- const n = t.viewport, s = typeof n.width == "number" ? n.width : 1280, c = typeof n.height == "number" ? n.height : 800, u = typeof n.deviceScaleFactor == "number" ? n.deviceScaleFactor : 1;
1024
- r = { width: s, height: c, deviceScaleFactor: u };
1138
+ function ut(e) {
1139
+ if (typeof e.url != "string" || e.url.length === 0)
1140
+ throw new p("`url` is required and must be a non-empty string.");
1141
+ if (!Array.isArray(e.regions))
1142
+ throw new p("`regions` is required and must be an array.");
1143
+ const t = e.regions;
1144
+ let o;
1145
+ if (e.viewport !== void 0) {
1146
+ if (typeof e.viewport != "object" || e.viewport === null)
1147
+ throw new p("`viewport` must be an object when provided.");
1148
+ const a = e.viewport, i = typeof a.width == "number" ? a.width : 1280, d = typeof a.height == "number" ? a.height : 800, l = typeof a.deviceScaleFactor == "number" ? a.deviceScaleFactor : 1;
1149
+ o = { width: i, height: d, deviceScaleFactor: l };
1025
1150
  }
1026
- const o = t.fullPage === !0, i = t.waitFor === "domcontentloaded" || t.waitFor === "networkidle" ? t.waitFor : "load";
1027
- let a;
1028
- if (t.output !== void 0) {
1029
- if (typeof t.output != "string")
1030
- throw new g("`output` must be a string when provided.");
1031
- if (!w(t.output))
1032
- throw new g(`\`output\` path "${t.output}" must be absolute.`);
1033
- a = t.output;
1151
+ const n = e.fullPage === !0, s = e.waitFor === "domcontentloaded" || e.waitFor === "networkidle" ? e.waitFor : "load";
1152
+ let c;
1153
+ if (e.output !== void 0) {
1154
+ if (typeof e.output != "string")
1155
+ throw new p("`output` must be a string when provided.");
1156
+ if (!b(e.output))
1157
+ throw new p(`\`output\` path "${e.output}" must be absolute.`);
1158
+ c = e.output;
1034
1159
  }
1035
- return { url: t.url, regions: e, viewport: r, fullPage: o, waitFor: i, output: a };
1160
+ let r;
1161
+ if (e.encode !== void 0) {
1162
+ if (typeof e.encode != "object" || e.encode === null)
1163
+ throw new p("`encode` must be an object when provided.");
1164
+ r = e.encode;
1165
+ }
1166
+ return { url: e.url, regions: t, viewport: o, fullPage: n, waitFor: s, output: c, encode: r };
1036
1167
  }
1037
- async function ae(t, e) {
1038
- if (e.bbox !== void 0) return e.bbox;
1039
- if (e.locator !== void 0) return f(t, e.locator);
1040
- throw new g("redact region requires either `bbox` or `locator`.");
1168
+ async function ht(e, t) {
1169
+ if (t.bbox !== void 0) return t.bbox;
1170
+ if (t.locator !== void 0) return f(e, t.locator);
1171
+ throw new p("redact region requires either `bbox` or `locator`.");
1041
1172
  }
1042
- const se = "annot-mcp", ce = "0.1.0", ue = [
1043
- Wt,
1044
- Vt,
1045
- ee,
1046
- oe,
1047
- Qt
1173
+ const ft = "annot-mcp", pt = "0.1.0", mt = [
1174
+ Je,
1175
+ tt,
1176
+ at,
1177
+ dt,
1178
+ st
1048
1179
  ];
1049
- function le(t = {}) {
1050
- const e = new ot(
1180
+ function gt(e = {}) {
1181
+ const t = new de(
1051
1182
  {
1052
- name: se,
1053
- version: t.version ?? ce
1183
+ name: ft,
1184
+ version: e.version ?? pt
1054
1185
  },
1055
1186
  {
1056
1187
  capabilities: {
1057
1188
  tools: {}
1058
1189
  }
1059
1190
  }
1060
- ), r = t.annotator ?? tt(t.annotatorOptions ?? {}), o = t.pool ?? dt();
1061
- return e.setRequestHandler(nt, async () => ({ tools: ue })), e.setRequestHandler(it, async (i) => {
1062
- const { name: a, arguments: n } = i.params;
1063
- let s;
1064
- switch (a) {
1065
- case j:
1066
- s = await jt(n ?? {}, { annotator: r });
1191
+ ), o = e.annotator ?? ie(e.annotatorOptions ?? {}), n = e.pool ?? ye();
1192
+ return t.setRequestHandler(le, async () => ({ tools: mt })), t.setRequestHandler(ue, async (s) => {
1193
+ const { name: c, arguments: r } = s.params;
1194
+ let a;
1195
+ switch (c) {
1196
+ case V:
1197
+ a = await Qe(r ?? {}, { annotator: o });
1067
1198
  break;
1068
- case X:
1069
- s = await Jt(n ?? {}, { annotator: r, pool: o });
1199
+ case J:
1200
+ a = await ot(r ?? {}, { annotator: o, pool: n });
1070
1201
  break;
1071
- case z:
1072
- s = await re(n ?? {});
1202
+ case K:
1203
+ a = await ct(r ?? {});
1073
1204
  break;
1074
- case V:
1075
- s = await ne(n ?? {}, { pool: o });
1205
+ case Z:
1206
+ a = await lt(r ?? {}, { pool: n });
1076
1207
  break;
1077
- case Y:
1078
- s = await te(n ?? {}, { annotator: r });
1208
+ case Q:
1209
+ a = await it(r ?? {}, { annotator: o });
1079
1210
  break;
1080
1211
  default:
1081
- s = {
1082
- content: [{ type: "text", text: `Unknown tool: ${a}` }],
1212
+ a = {
1213
+ content: [{ type: "text", text: `Unknown tool: ${c}` }],
1083
1214
  isError: !0
1084
1215
  };
1085
1216
  }
1086
- return s;
1087
- }), e;
1217
+ return a;
1218
+ }), t;
1088
1219
  }
1089
- async function be() {
1090
- const t = le(), e = new at();
1091
- await t.connect(e);
1220
+ async function Pt() {
1221
+ const e = gt(), t = new he();
1222
+ await e.connect(t);
1092
1223
  }
1093
1224
  export {
1094
- j as ANNOTATE_SCREENSHOT_TOOL_NAME,
1095
- X as ANNOTATE_URL_TOOL_NAME,
1096
- Ee as BBOX_ANNOTATION_SCHEMA,
1097
- xe as BBOX_REDACT_REGION_SCHEMA,
1098
- lt as BrowserPool,
1099
- Y as COMPARE_SCREENSHOTS_TOOL_NAME,
1100
- C as ChromiumUnavailableError,
1101
- bt as DimensionMismatchError,
1102
- y as InvalidImageInputError,
1103
- v as InvalidPngError,
1104
- Ot as LOCATOR_ANNOTATION_SCHEMA,
1105
- Rt as LOCATOR_REDACT_REGION_SCHEMA,
1106
- F as LocatorResolutionError,
1107
- z as REDACT_SCREENSHOT_TOOL_NAME,
1108
- V as REDACT_URL_TOOL_NAME,
1109
- O as SHARED_DEFS,
1110
- yt as aggregateDiffRegions,
1111
- Wt as annotateScreenshotTool,
1112
- Vt as annotateUrlTool,
1113
- Le as arrowBetween,
1114
- Pe as bboxAnnotationsToSvg,
1115
- W as burnRedactions,
1116
- k as capturePage,
1117
- Qt as compareScreenshotsTool,
1118
- dt as createChromiumPool,
1119
- le as createServer,
1120
- vt as diffScreenshots,
1121
- jt as handleAnnotateScreenshot,
1122
- Jt as handleAnnotateUrl,
1123
- te as handleCompareScreenshots,
1124
- re as handleRedactScreenshot,
1125
- ne as handleRedactUrl,
1126
- M as readPngDimensions,
1127
- Ae as rectForBoundingBox,
1128
- ee as redactScreenshotTool,
1129
- oe as redactUrlTool,
1130
- A as resolveImageInput,
1225
+ V as ANNOTATE_SCREENSHOT_TOOL_NAME,
1226
+ J as ANNOTATE_URL_TOOL_NAME,
1227
+ At as BBOX_ANNOTATION_SCHEMA,
1228
+ Tt as BBOX_REDACT_REGION_SCHEMA,
1229
+ ge as BrowserPool,
1230
+ Q as COMPARE_SCREENSHOTS_TOOL_NAME,
1231
+ q as ChromiumUnavailableError,
1232
+ Pe as DimensionMismatchError,
1233
+ w as InvalidImageInputError,
1234
+ x as InvalidPngError,
1235
+ Ce as LOCATOR_ANNOTATION_SCHEMA,
1236
+ Ue as LOCATOR_REDACT_REGION_SCHEMA,
1237
+ N as LocatorResolutionError,
1238
+ K as REDACT_SCREENSHOT_TOOL_NAME,
1239
+ Z as REDACT_URL_TOOL_NAME,
1240
+ I as SHARED_DEFS,
1241
+ xe as aggregateDiffRegions,
1242
+ Je as annotateScreenshotTool,
1243
+ tt as annotateUrlTool,
1244
+ Rt as arrowBetween,
1245
+ It as bboxAnnotationsToSvg,
1246
+ Y as burnRedactions,
1247
+ W as capturePage,
1248
+ st as compareScreenshotsTool,
1249
+ ye as createChromiumPool,
1250
+ gt as createServer,
1251
+ Se as diffScreenshots,
1252
+ Qe as handleAnnotateScreenshot,
1253
+ ot as handleAnnotateUrl,
1254
+ it as handleCompareScreenshots,
1255
+ ct as handleRedactScreenshot,
1256
+ lt as handleRedactUrl,
1257
+ B as readPngDimensions,
1258
+ _t as rectForBoundingBox,
1259
+ at as redactScreenshotTool,
1260
+ dt as redactUrlTool,
1261
+ R as resolveImageInput,
1131
1262
  f as resolveLocator,
1132
- ft as resolveLocatorAnnotation,
1133
- ht as resolveLocatorAnnotations,
1134
- be as runStdioServer,
1135
- Oe as textAt
1263
+ we as resolveLocatorAnnotation,
1264
+ be as resolveLocatorAnnotations,
1265
+ Pt as runStdioServer,
1266
+ Ct as textAt
1136
1267
  };