@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/CHANGELOG.md +46 -0
- package/dist/dsl/schema.d.ts +32 -0
- package/dist/index.js +725 -594
- package/dist/io/encode-output.d.ts +29 -0
- package/dist/tools/annotate-screenshot.d.ts +37 -0
- package/dist/tools/annotate-url.d.ts +37 -0
- package/dist/tools/compare-screenshots.d.ts +38 -0
- package/dist/tools/redact-screenshot.d.ts +37 -0
- package/dist/tools/redact-url.d.ts +36 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
import { SHARED_DEFS as
|
|
2
|
-
import { BBOX_ANNOTATION_SCHEMA as
|
|
3
|
-
import { loadImage as
|
|
4
|
-
import
|
|
5
|
-
import { readFile as
|
|
6
|
-
import { isAbsolute as
|
|
7
|
-
import { Server as
|
|
8
|
-
import { ListToolsRequestSchema as
|
|
9
|
-
import { StdioServerTransport as
|
|
10
|
-
const
|
|
11
|
-
async function
|
|
12
|
-
const
|
|
13
|
-
let
|
|
14
|
-
const
|
|
15
|
-
|
|
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
|
-
|
|
19
|
-
viewport: { width:
|
|
20
|
-
deviceScaleFactor:
|
|
18
|
+
r = await c.newContext({
|
|
19
|
+
viewport: { width: o.width, height: o.height },
|
|
20
|
+
deviceScaleFactor: o.deviceScaleFactor
|
|
21
21
|
});
|
|
22
|
-
const
|
|
23
|
-
await
|
|
24
|
-
const l = await
|
|
25
|
-
return { pngBytes:
|
|
26
|
-
page:
|
|
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 (!
|
|
28
|
+
if (!a)
|
|
29
29
|
try {
|
|
30
|
-
await
|
|
30
|
+
await u.close();
|
|
31
31
|
} finally {
|
|
32
|
-
|
|
32
|
+
i();
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
} };
|
|
36
|
-
} catch (
|
|
37
|
-
if (
|
|
36
|
+
} catch (d) {
|
|
37
|
+
if (r)
|
|
38
38
|
try {
|
|
39
|
-
await
|
|
39
|
+
await r.close();
|
|
40
40
|
} catch {
|
|
41
41
|
}
|
|
42
|
-
throw
|
|
42
|
+
throw i(), d;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
const
|
|
46
|
-
class
|
|
45
|
+
const me = 3e4;
|
|
46
|
+
class ge {
|
|
47
|
+
#s;
|
|
47
48
|
#i;
|
|
48
|
-
#
|
|
49
|
-
#t;
|
|
50
|
-
#o;
|
|
51
|
-
#e = 0;
|
|
49
|
+
#e;
|
|
52
50
|
#r;
|
|
53
|
-
|
|
54
|
-
|
|
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.#
|
|
68
|
-
throw this.#
|
|
69
|
-
})), this.#
|
|
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.#
|
|
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
|
|
88
|
-
this.#
|
|
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.#
|
|
92
|
+
return this.#t;
|
|
93
93
|
}
|
|
94
94
|
/** Whether a browser is currently launched. Exposed for tests. */
|
|
95
95
|
get isLaunched() {
|
|
96
|
-
return this.#
|
|
96
|
+
return this.#e !== void 0;
|
|
97
97
|
}
|
|
98
98
|
// ─── internals ────────────────────────────────────────────────
|
|
99
99
|
#n() {
|
|
100
|
-
this.#
|
|
100
|
+
this.#o && (clearTimeout(this.#o), this.#o = void 0);
|
|
101
101
|
}
|
|
102
|
-
#
|
|
103
|
-
this.#n(), this.#
|
|
104
|
-
const
|
|
105
|
-
this.#
|
|
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.#
|
|
107
|
+
}, this.#i), this.#o.unref?.();
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
-
function
|
|
111
|
-
return new
|
|
110
|
+
function ye(e = {}) {
|
|
111
|
+
return new ge(
|
|
112
112
|
{
|
|
113
113
|
async launch() {
|
|
114
|
-
let
|
|
114
|
+
let t;
|
|
115
115
|
try {
|
|
116
|
-
({ chromium:
|
|
117
|
-
} catch (
|
|
118
|
-
throw new
|
|
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
|
-
|
|
120
|
+
o
|
|
121
121
|
);
|
|
122
122
|
}
|
|
123
123
|
try {
|
|
124
|
-
return await
|
|
125
|
-
} catch (
|
|
126
|
-
throw new
|
|
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
|
-
|
|
128
|
+
o
|
|
129
129
|
);
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
},
|
|
133
|
-
|
|
133
|
+
e
|
|
134
134
|
);
|
|
135
135
|
}
|
|
136
|
-
class
|
|
136
|
+
class q extends Error {
|
|
137
137
|
cause;
|
|
138
|
-
constructor(
|
|
139
|
-
super(
|
|
138
|
+
constructor(t, o) {
|
|
139
|
+
super(t), this.name = "ChromiumUnavailableError", this.cause = o;
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
-
class
|
|
142
|
+
class N extends Error {
|
|
143
143
|
locator;
|
|
144
|
-
constructor(
|
|
145
|
-
super(
|
|
144
|
+
constructor(t, o) {
|
|
145
|
+
super(o), this.name = "LocatorResolutionError", this.locator = t;
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
-
async function f(
|
|
149
|
-
const
|
|
150
|
-
if (!
|
|
151
|
-
throw new
|
|
152
|
-
|
|
153
|
-
`Locator "${
|
|
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
|
|
155
|
+
return o;
|
|
156
156
|
}
|
|
157
|
-
async function
|
|
158
|
-
switch (
|
|
157
|
+
async function we(e, t) {
|
|
158
|
+
switch (t.type) {
|
|
159
159
|
case "rect": {
|
|
160
|
-
const
|
|
161
|
-
return { ...
|
|
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 (
|
|
164
|
+
if (t.center !== void 0 && t.radius !== void 0)
|
|
165
165
|
return {
|
|
166
|
-
...
|
|
166
|
+
...g(t),
|
|
167
167
|
type: "circle",
|
|
168
|
-
center:
|
|
169
|
-
radius:
|
|
168
|
+
center: t.center,
|
|
169
|
+
radius: t.radius
|
|
170
170
|
};
|
|
171
|
-
const
|
|
171
|
+
const o = await f(e, m(t.locator));
|
|
172
172
|
return {
|
|
173
|
-
...
|
|
173
|
+
...g(t),
|
|
174
174
|
type: "circle",
|
|
175
|
-
center:
|
|
176
|
-
radius: Math.min(
|
|
175
|
+
center: T(o),
|
|
176
|
+
radius: Math.min(o.width, o.height) / 2
|
|
177
177
|
};
|
|
178
178
|
}
|
|
179
179
|
case "arrow": {
|
|
180
|
-
const
|
|
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
|
-
...
|
|
182
|
+
...g(t),
|
|
183
183
|
type: "arrow",
|
|
184
|
-
from:
|
|
185
|
-
to:
|
|
184
|
+
from: o,
|
|
185
|
+
to: n
|
|
186
186
|
};
|
|
187
187
|
}
|
|
188
188
|
case "text": {
|
|
189
|
-
const
|
|
190
|
-
await f(
|
|
191
|
-
|
|
192
|
-
),
|
|
193
|
-
...
|
|
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:
|
|
196
|
-
content:
|
|
195
|
+
at: o,
|
|
196
|
+
content: t.content
|
|
197
197
|
};
|
|
198
|
-
return
|
|
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
|
|
201
|
+
const o = t.at ?? await ve(e, t.atLocator), n = t.targetBbox ?? await f(e, m(t.targetLocator));
|
|
202
202
|
return {
|
|
203
|
-
...
|
|
203
|
+
...g(t),
|
|
204
204
|
type: "callout",
|
|
205
|
-
at:
|
|
206
|
-
targetBbox:
|
|
207
|
-
content:
|
|
205
|
+
at: o,
|
|
206
|
+
targetBbox: n,
|
|
207
|
+
content: t.content
|
|
208
208
|
};
|
|
209
209
|
}
|
|
210
210
|
case "raw":
|
|
211
|
-
return
|
|
211
|
+
return t;
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
|
-
async function
|
|
215
|
-
const
|
|
216
|
-
for (const
|
|
217
|
-
|
|
218
|
-
return
|
|
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
|
|
221
|
-
if (!
|
|
222
|
-
throw new
|
|
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
|
|
227
|
-
return
|
|
226
|
+
const o = await f(e, t);
|
|
227
|
+
return T(o);
|
|
228
228
|
}
|
|
229
|
-
function
|
|
230
|
-
return { x:
|
|
229
|
+
function T(e) {
|
|
230
|
+
return { x: e.x + e.width / 2, y: e.y + e.height / 2 };
|
|
231
231
|
}
|
|
232
|
-
function
|
|
233
|
-
const
|
|
234
|
-
return { x:
|
|
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
|
|
237
|
-
if (
|
|
238
|
-
throw new
|
|
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
|
|
242
|
+
return e;
|
|
243
243
|
}
|
|
244
|
-
function
|
|
245
|
-
if (
|
|
244
|
+
function g(e) {
|
|
245
|
+
if (e.type === "raw")
|
|
246
246
|
return {};
|
|
247
|
-
const
|
|
248
|
-
return
|
|
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
|
|
251
|
-
function
|
|
252
|
-
const
|
|
253
|
-
for (let
|
|
254
|
-
for (let
|
|
255
|
-
const
|
|
256
|
-
if (
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
x:
|
|
260
|
-
y:
|
|
261
|
-
width:
|
|
262
|
-
height:
|
|
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
|
|
265
|
+
return s;
|
|
266
266
|
}
|
|
267
|
-
function
|
|
268
|
-
return t
|
|
267
|
+
function X(e, t) {
|
|
268
|
+
return e[t * 4 + 3] > 0;
|
|
269
269
|
}
|
|
270
|
-
function
|
|
271
|
-
const
|
|
270
|
+
function Oe(e, t, o, n, s, c) {
|
|
271
|
+
const r = {
|
|
272
272
|
count: 0,
|
|
273
|
-
minX:
|
|
274
|
-
minY:
|
|
275
|
-
maxX:
|
|
276
|
-
maxY:
|
|
277
|
-
},
|
|
278
|
-
for (;
|
|
279
|
-
const
|
|
280
|
-
if (
|
|
281
|
-
const l =
|
|
282
|
-
|
|
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
|
|
284
|
+
return r;
|
|
285
285
|
}
|
|
286
|
-
class
|
|
287
|
-
constructor(
|
|
286
|
+
class Pe extends Error {
|
|
287
|
+
constructor(t, o) {
|
|
288
288
|
super(
|
|
289
|
-
`Cannot compare screenshots of different dimensions: before is ${
|
|
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
|
|
294
|
-
const [
|
|
295
|
-
|
|
296
|
-
|
|
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 (
|
|
299
|
-
throw new
|
|
300
|
-
{ width:
|
|
301
|
-
{ width:
|
|
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:
|
|
304
|
-
threshold:
|
|
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
|
-
}),
|
|
308
|
-
return { mismatchedPixels: l, regions:
|
|
307
|
+
}), v = xe(d, c, r);
|
|
308
|
+
return { mismatchedPixels: l, regions: v, width: c, height: r };
|
|
309
309
|
}
|
|
310
|
-
function
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
const
|
|
314
|
-
return new Uint8Array(
|
|
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
|
|
317
|
-
...
|
|
316
|
+
const I = {
|
|
317
|
+
...te,
|
|
318
318
|
Locator: { type: "string", minLength: 1 }
|
|
319
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
412
|
-
oneOf: [
|
|
413
|
-
},
|
|
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
|
-
},
|
|
424
|
-
class
|
|
425
|
-
constructor(
|
|
426
|
-
super(
|
|
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
|
|
430
|
-
if (
|
|
431
|
-
throw new
|
|
432
|
-
`Expected at least ${
|
|
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
|
|
435
|
-
if (
|
|
436
|
-
throw new
|
|
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
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
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 (
|
|
446
|
-
throw new
|
|
447
|
-
`Expected IHDR chunk after PNG signature, found "${
|
|
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
|
|
450
|
-
if (
|
|
451
|
-
throw new
|
|
452
|
-
return { width:
|
|
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
|
|
455
|
-
constructor(
|
|
456
|
-
super(
|
|
485
|
+
class w extends Error {
|
|
486
|
+
constructor(t) {
|
|
487
|
+
super(t), this.name = "InvalidImageInputError";
|
|
457
488
|
}
|
|
458
489
|
}
|
|
459
|
-
const
|
|
460
|
-
async function
|
|
461
|
-
if (typeof
|
|
462
|
-
throw new
|
|
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 (
|
|
466
|
-
return
|
|
467
|
-
if (!
|
|
468
|
-
throw new
|
|
469
|
-
`Filesystem path "${
|
|
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
|
|
502
|
+
return je(e);
|
|
472
503
|
}
|
|
473
|
-
function
|
|
474
|
-
if (!
|
|
475
|
-
throw new
|
|
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
|
|
479
|
-
return { bytes:
|
|
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
|
|
482
|
-
let
|
|
512
|
+
async function je(e) {
|
|
513
|
+
let t;
|
|
483
514
|
try {
|
|
484
|
-
const
|
|
485
|
-
|
|
486
|
-
} catch (
|
|
487
|
-
const
|
|
488
|
-
throw new
|
|
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
|
|
491
|
-
return { bytes:
|
|
521
|
+
const o = z(t), n = `data:image/png;base64,${Me(t)}`;
|
|
522
|
+
return { bytes: t, dataUrl: n, dimensions: o };
|
|
492
523
|
}
|
|
493
|
-
function
|
|
524
|
+
function z(e) {
|
|
494
525
|
try {
|
|
495
|
-
return
|
|
496
|
-
} catch (
|
|
497
|
-
throw
|
|
526
|
+
return B(e);
|
|
527
|
+
} catch (t) {
|
|
528
|
+
throw t instanceof x ? new w(t.message) : t;
|
|
498
529
|
}
|
|
499
530
|
}
|
|
500
|
-
function
|
|
501
|
-
const
|
|
502
|
-
return new Uint8Array(
|
|
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
|
|
505
|
-
return Buffer.from(
|
|
535
|
+
function Me(e) {
|
|
536
|
+
return Buffer.from(e.buffer, e.byteOffset, e.byteLength).toString("base64");
|
|
506
537
|
}
|
|
507
|
-
const
|
|
508
|
-
async function
|
|
509
|
-
if (
|
|
510
|
-
return
|
|
511
|
-
const
|
|
512
|
-
|
|
513
|
-
for (const
|
|
514
|
-
if (
|
|
515
|
-
switch (
|
|
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
|
-
|
|
548
|
+
ze(s, r.bbox, r.color ?? We);
|
|
518
549
|
break;
|
|
519
550
|
case "mosaic":
|
|
520
|
-
|
|
551
|
+
Ye(s, o, r.bbox);
|
|
521
552
|
break;
|
|
522
553
|
case "blur":
|
|
523
|
-
|
|
554
|
+
Ve(s, o, r.bbox);
|
|
524
555
|
break;
|
|
525
556
|
}
|
|
526
557
|
}
|
|
527
|
-
const
|
|
528
|
-
return new Uint8Array(
|
|
558
|
+
const c = n.toBuffer("image/png");
|
|
559
|
+
return new Uint8Array(c.buffer, c.byteOffset, c.byteLength);
|
|
529
560
|
}
|
|
530
|
-
function
|
|
531
|
-
|
|
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
|
|
534
|
-
const
|
|
535
|
-
|
|
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
|
|
538
|
-
|
|
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
|
-
|
|
541
|
-
|
|
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
|
-
...
|
|
564
|
-
BboxAnnotation:
|
|
617
|
+
...I,
|
|
618
|
+
BboxAnnotation: ne,
|
|
619
|
+
EncodeOptions: P
|
|
565
620
|
}
|
|
566
621
|
}
|
|
567
622
|
};
|
|
568
|
-
async function
|
|
623
|
+
async function Qe(e, t) {
|
|
569
624
|
try {
|
|
570
|
-
const
|
|
571
|
-
originalDataUrl:
|
|
572
|
-
annotationsSvg:
|
|
573
|
-
width:
|
|
574
|
-
height:
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
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:
|
|
588
|
-
mimeType:
|
|
647
|
+
data: et(r.bytes),
|
|
648
|
+
mimeType: r.mimeType
|
|
589
649
|
}
|
|
590
650
|
]
|
|
591
651
|
};
|
|
592
|
-
} catch (
|
|
593
|
-
return
|
|
652
|
+
} catch (o) {
|
|
653
|
+
return Ze(o);
|
|
594
654
|
}
|
|
595
655
|
}
|
|
596
|
-
function
|
|
597
|
-
if (typeof
|
|
598
|
-
throw new
|
|
599
|
-
if (!Array.isArray(
|
|
600
|
-
throw new
|
|
601
|
-
const
|
|
602
|
-
let
|
|
603
|
-
if (
|
|
604
|
-
if (typeof
|
|
605
|
-
throw new
|
|
606
|
-
if (!
|
|
607
|
-
throw new
|
|
608
|
-
`\`output\` path "${
|
|
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
|
-
|
|
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:
|
|
678
|
+
return { image: e.image, annotations: t, output: o, encode: n };
|
|
613
679
|
}
|
|
614
|
-
class
|
|
615
|
-
constructor(
|
|
616
|
-
super(
|
|
680
|
+
class A extends Error {
|
|
681
|
+
constructor(t) {
|
|
682
|
+
super(t), this.name = "InvalidToolInputError";
|
|
617
683
|
}
|
|
618
684
|
}
|
|
619
|
-
function
|
|
685
|
+
function Ze(e) {
|
|
620
686
|
return {
|
|
621
|
-
content: [{ type: "text", text:
|
|
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
|
|
626
|
-
return Buffer.from(
|
|
691
|
+
function et(e) {
|
|
692
|
+
return Buffer.from(e.buffer, e.byteOffset, e.byteLength).toString("base64");
|
|
627
693
|
}
|
|
628
|
-
const
|
|
629
|
-
name:
|
|
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
|
-
...
|
|
673
|
-
LocatorAnnotation:
|
|
742
|
+
...I,
|
|
743
|
+
LocatorAnnotation: Ce,
|
|
744
|
+
EncodeOptions: P
|
|
674
745
|
}
|
|
675
746
|
}
|
|
676
747
|
};
|
|
677
|
-
class
|
|
678
|
-
constructor(
|
|
679
|
-
super(
|
|
748
|
+
class y extends Error {
|
|
749
|
+
constructor(t) {
|
|
750
|
+
super(t), this.name = "InvalidAnnotateUrlInputError";
|
|
680
751
|
}
|
|
681
752
|
}
|
|
682
|
-
async function
|
|
753
|
+
async function ot(e, t) {
|
|
683
754
|
try {
|
|
684
|
-
const
|
|
685
|
-
url:
|
|
686
|
-
viewport:
|
|
687
|
-
fullPage:
|
|
688
|
-
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
|
|
761
|
+
let s;
|
|
691
762
|
try {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
763
|
+
s = await be(
|
|
764
|
+
n.handle.page,
|
|
765
|
+
o.annotations
|
|
695
766
|
);
|
|
696
767
|
} finally {
|
|
697
|
-
await
|
|
768
|
+
await n.handle.close();
|
|
698
769
|
}
|
|
699
|
-
const
|
|
700
|
-
originalDataUrl: `data:image/png;base64,${
|
|
701
|
-
annotationsSvg:
|
|
702
|
-
width:
|
|
703
|
-
height:
|
|
704
|
-
});
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
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:
|
|
717
|
-
mimeType:
|
|
792
|
+
data: H(i.bytes),
|
|
793
|
+
mimeType: i.mimeType
|
|
718
794
|
}
|
|
719
795
|
]
|
|
720
796
|
};
|
|
721
|
-
} catch (
|
|
722
|
-
return
|
|
797
|
+
} catch (o) {
|
|
798
|
+
return nt(o);
|
|
723
799
|
}
|
|
724
800
|
}
|
|
725
|
-
function
|
|
726
|
-
if (typeof
|
|
727
|
-
throw new
|
|
728
|
-
if (!Array.isArray(
|
|
729
|
-
throw new
|
|
730
|
-
const
|
|
731
|
-
let
|
|
732
|
-
if (
|
|
733
|
-
if (typeof
|
|
734
|
-
throw new
|
|
735
|
-
const
|
|
736
|
-
|
|
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
|
|
739
|
-
let
|
|
740
|
-
if (
|
|
741
|
-
if (typeof
|
|
742
|
-
throw new
|
|
743
|
-
if (!
|
|
744
|
-
throw new
|
|
745
|
-
|
|
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:
|
|
749
|
-
annotations:
|
|
750
|
-
viewport:
|
|
751
|
-
fullPage:
|
|
752
|
-
waitFor:
|
|
753
|
-
output:
|
|
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
|
|
839
|
+
function nt(e) {
|
|
757
840
|
return {
|
|
758
|
-
content: [{ type: "text", text:
|
|
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
|
|
763
|
-
return Buffer.from(
|
|
845
|
+
function H(e) {
|
|
846
|
+
return Buffer.from(e.buffer, e.byteOffset, e.byteLength).toString("base64");
|
|
764
847
|
}
|
|
765
|
-
const
|
|
766
|
-
name:
|
|
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
|
|
798
|
-
constructor(
|
|
799
|
-
super(
|
|
884
|
+
class $ extends Error {
|
|
885
|
+
constructor(t) {
|
|
886
|
+
super(t), this.name = "InvalidCompareInputError";
|
|
800
887
|
}
|
|
801
888
|
}
|
|
802
|
-
async function
|
|
889
|
+
async function it(e, t) {
|
|
803
890
|
try {
|
|
804
|
-
if (typeof
|
|
805
|
-
throw new
|
|
806
|
-
if (typeof
|
|
807
|
-
throw new
|
|
808
|
-
const
|
|
809
|
-
let
|
|
810
|
-
if (
|
|
811
|
-
if (typeof
|
|
812
|
-
throw new
|
|
813
|
-
if (!
|
|
814
|
-
throw new
|
|
815
|
-
|
|
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
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
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:
|
|
915
|
+
bbox: h,
|
|
823
916
|
intent: "warning"
|
|
824
|
-
})),
|
|
825
|
-
originalDataUrl:
|
|
826
|
-
annotationsSvg:
|
|
827
|
-
width:
|
|
828
|
-
height:
|
|
829
|
-
})
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
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(
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
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 (!
|
|
840
|
-
return { content: [
|
|
841
|
-
const
|
|
842
|
-
` +
|
|
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: [
|
|
947
|
+
content: [_, { type: "text", text: ee }]
|
|
846
948
|
};
|
|
847
|
-
} catch (
|
|
949
|
+
} catch (o) {
|
|
848
950
|
return {
|
|
849
|
-
content: [{ type: "text", text:
|
|
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
|
|
855
|
-
name:
|
|
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
|
-
...
|
|
874
|
-
BboxRedactRegion:
|
|
979
|
+
...I,
|
|
980
|
+
BboxRedactRegion: se,
|
|
981
|
+
EncodeOptions: P
|
|
875
982
|
}
|
|
876
983
|
}
|
|
877
984
|
};
|
|
878
|
-
class
|
|
879
|
-
constructor(
|
|
880
|
-
super(
|
|
985
|
+
class E extends Error {
|
|
986
|
+
constructor(t) {
|
|
987
|
+
super(t), this.name = "InvalidRedactInputError";
|
|
881
988
|
}
|
|
882
989
|
}
|
|
883
|
-
async function
|
|
990
|
+
async function ct(e) {
|
|
884
991
|
try {
|
|
885
|
-
if (typeof
|
|
886
|
-
throw new
|
|
887
|
-
if (!Array.isArray(
|
|
888
|
-
throw new
|
|
889
|
-
const
|
|
890
|
-
let
|
|
891
|
-
if (
|
|
892
|
-
if (typeof
|
|
893
|
-
throw new
|
|
894
|
-
if (!
|
|
895
|
-
throw new
|
|
896
|
-
|
|
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
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
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
|
-
|
|
912
|
-
|
|
913
|
-
|
|
1029
|
+
r.bytes.buffer,
|
|
1030
|
+
r.bytes.byteOffset,
|
|
1031
|
+
r.bytes.byteLength
|
|
914
1032
|
).toString("base64"),
|
|
915
|
-
mimeType:
|
|
1033
|
+
mimeType: r.mimeType
|
|
916
1034
|
}
|
|
917
1035
|
]
|
|
918
1036
|
};
|
|
919
|
-
} catch (
|
|
1037
|
+
} catch (t) {
|
|
920
1038
|
return {
|
|
921
|
-
content: [{ type: "text", text:
|
|
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
|
|
927
|
-
name:
|
|
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
|
-
...
|
|
958
|
-
LocatorRedactRegion:
|
|
1076
|
+
...I,
|
|
1077
|
+
LocatorRedactRegion: Ue,
|
|
1078
|
+
EncodeOptions: P
|
|
959
1079
|
}
|
|
960
1080
|
}
|
|
961
1081
|
};
|
|
962
|
-
class
|
|
963
|
-
constructor(
|
|
964
|
-
super(
|
|
1082
|
+
class p extends Error {
|
|
1083
|
+
constructor(t) {
|
|
1084
|
+
super(t), this.name = "InvalidRedactUrlInputError";
|
|
965
1085
|
}
|
|
966
1086
|
}
|
|
967
|
-
async function
|
|
1087
|
+
async function lt(e, t) {
|
|
968
1088
|
try {
|
|
969
|
-
const
|
|
970
|
-
url:
|
|
971
|
-
viewport:
|
|
972
|
-
fullPage:
|
|
973
|
-
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
|
|
1095
|
+
let s;
|
|
976
1096
|
try {
|
|
977
|
-
|
|
978
|
-
for (const
|
|
979
|
-
const
|
|
980
|
-
|
|
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
|
|
1103
|
+
await n.handle.close();
|
|
984
1104
|
}
|
|
985
|
-
const
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
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:
|
|
1127
|
+
mimeType: a.mimeType
|
|
1003
1128
|
}
|
|
1004
1129
|
]
|
|
1005
1130
|
};
|
|
1006
|
-
} catch (
|
|
1131
|
+
} catch (o) {
|
|
1007
1132
|
return {
|
|
1008
|
-
content: [{ type: "text", text:
|
|
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
|
|
1014
|
-
if (typeof
|
|
1015
|
-
throw new
|
|
1016
|
-
if (!Array.isArray(
|
|
1017
|
-
throw new
|
|
1018
|
-
const
|
|
1019
|
-
let
|
|
1020
|
-
if (
|
|
1021
|
-
if (typeof
|
|
1022
|
-
throw new
|
|
1023
|
-
const
|
|
1024
|
-
|
|
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
|
|
1027
|
-
let
|
|
1028
|
-
if (
|
|
1029
|
-
if (typeof
|
|
1030
|
-
throw new
|
|
1031
|
-
if (!
|
|
1032
|
-
throw new
|
|
1033
|
-
|
|
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
|
-
|
|
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
|
|
1038
|
-
if (
|
|
1039
|
-
if (
|
|
1040
|
-
throw new
|
|
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
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1173
|
+
const ft = "annot-mcp", pt = "0.1.0", mt = [
|
|
1174
|
+
Je,
|
|
1175
|
+
tt,
|
|
1176
|
+
at,
|
|
1177
|
+
dt,
|
|
1178
|
+
st
|
|
1048
1179
|
];
|
|
1049
|
-
function
|
|
1050
|
-
const
|
|
1180
|
+
function gt(e = {}) {
|
|
1181
|
+
const t = new de(
|
|
1051
1182
|
{
|
|
1052
|
-
name:
|
|
1053
|
-
version:
|
|
1183
|
+
name: ft,
|
|
1184
|
+
version: e.version ?? pt
|
|
1054
1185
|
},
|
|
1055
1186
|
{
|
|
1056
1187
|
capabilities: {
|
|
1057
1188
|
tools: {}
|
|
1058
1189
|
}
|
|
1059
1190
|
}
|
|
1060
|
-
),
|
|
1061
|
-
return
|
|
1062
|
-
const { name:
|
|
1063
|
-
let
|
|
1064
|
-
switch (
|
|
1065
|
-
case
|
|
1066
|
-
|
|
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
|
|
1069
|
-
|
|
1199
|
+
case J:
|
|
1200
|
+
a = await ot(r ?? {}, { annotator: o, pool: n });
|
|
1070
1201
|
break;
|
|
1071
|
-
case
|
|
1072
|
-
|
|
1202
|
+
case K:
|
|
1203
|
+
a = await ct(r ?? {});
|
|
1073
1204
|
break;
|
|
1074
|
-
case
|
|
1075
|
-
|
|
1205
|
+
case Z:
|
|
1206
|
+
a = await lt(r ?? {}, { pool: n });
|
|
1076
1207
|
break;
|
|
1077
|
-
case
|
|
1078
|
-
|
|
1208
|
+
case Q:
|
|
1209
|
+
a = await it(r ?? {}, { annotator: o });
|
|
1079
1210
|
break;
|
|
1080
1211
|
default:
|
|
1081
|
-
|
|
1082
|
-
content: [{ type: "text", text: `Unknown tool: ${
|
|
1212
|
+
a = {
|
|
1213
|
+
content: [{ type: "text", text: `Unknown tool: ${c}` }],
|
|
1083
1214
|
isError: !0
|
|
1084
1215
|
};
|
|
1085
1216
|
}
|
|
1086
|
-
return
|
|
1087
|
-
}),
|
|
1217
|
+
return a;
|
|
1218
|
+
}), t;
|
|
1088
1219
|
}
|
|
1089
|
-
async function
|
|
1090
|
-
const
|
|
1091
|
-
await
|
|
1220
|
+
async function Pt() {
|
|
1221
|
+
const e = gt(), t = new he();
|
|
1222
|
+
await e.connect(t);
|
|
1092
1223
|
}
|
|
1093
1224
|
export {
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
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
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1263
|
+
we as resolveLocatorAnnotation,
|
|
1264
|
+
be as resolveLocatorAnnotations,
|
|
1265
|
+
Pt as runStdioServer,
|
|
1266
|
+
Ct as textAt
|
|
1136
1267
|
};
|