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