@ingcreators/annot-mcp 0.3.0 → 0.3.2
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 +197 -0
- package/dist/compare/aggregate.d.ts +1 -6
- package/dist/compare/diff.d.ts +1 -30
- package/dist/index.d.ts +1 -1
- package/dist/index.js +198 -302
- package/dist/redact/burn.d.ts +1 -14
- package/dist/tools/annotate-screenshot.d.ts +68 -0
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { BBOX_ANNOTATION_SCHEMA as e, BBOX_REDACT_REGION_SCHEMA as t, DEFAULT_ENCODE_OPTIONS as n,
|
|
2
|
-
import {
|
|
3
|
-
import ee from "pixelmatch";
|
|
4
|
-
import { readFile as te, writeFile as p } from "node:fs/promises";
|
|
1
|
+
import { BBOX_ANNOTATION_SCHEMA as e, BBOX_REDACT_REGION_SCHEMA as t, DEFAULT_ENCODE_OPTIONS as n, DimensionMismatchError as r, SHARED_DEFS as i, aggregateDiffRegions as a, arrowBetween as o, bboxAnnotationsToSvg as s, bboxAnnotationsToSvg as c, burnRedactions as l, burnRegions as u, createAnnotator as d, decodeAndEncodeImage as f, diffScreenshots as ee, rectForBoundingBox as te, textAt as ne } from "@ingcreators/annot-annotator";
|
|
2
|
+
import { readFile as re, writeFile as p } from "node:fs/promises";
|
|
5
3
|
import { isAbsolute as m } from "node:path";
|
|
6
|
-
import { Server as
|
|
7
|
-
import { CallToolRequestSchema as
|
|
8
|
-
import { detectDrift as
|
|
4
|
+
import { Server as ie } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
|
+
import { CallToolRequestSchema as ae, ListToolsRequestSchema as oe } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
+
import { detectDrift as se, lintableScreens as ce, parseMdxFile as h, parseSnapshot as g } from "@ingcreators/annot-product-docs";
|
|
9
7
|
import { StdioServerTransport as le } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10
8
|
//#region src/browser/capture.ts
|
|
11
9
|
var ue = {
|
|
@@ -13,7 +11,7 @@ var ue = {
|
|
|
13
11
|
height: 800,
|
|
14
12
|
deviceScaleFactor: 1
|
|
15
13
|
}, de = "load";
|
|
16
|
-
async function
|
|
14
|
+
async function _(e, t) {
|
|
17
15
|
let n = {
|
|
18
16
|
...ue,
|
|
19
17
|
...t.viewport
|
|
@@ -56,7 +54,7 @@ async function h(e, t) {
|
|
|
56
54
|
}
|
|
57
55
|
//#endregion
|
|
58
56
|
//#region src/browser/pool.ts
|
|
59
|
-
var fe = 3e4,
|
|
57
|
+
var fe = 3e4, v = class {
|
|
60
58
|
#e;
|
|
61
59
|
#t;
|
|
62
60
|
#n;
|
|
@@ -96,73 +94,73 @@ var fe = 3e4, g = class {
|
|
|
96
94
|
}
|
|
97
95
|
};
|
|
98
96
|
function pe(e = {}) {
|
|
99
|
-
return new
|
|
97
|
+
return new v({ async launch() {
|
|
100
98
|
let e;
|
|
101
99
|
try {
|
|
102
100
|
({chromium: e} = await import("playwright-core"));
|
|
103
101
|
} catch (e) {
|
|
104
|
-
throw new
|
|
102
|
+
throw new y("Failed to load `playwright-core`. Reinstall `@ingcreators/annot-mcp` to restore the dependency.", e);
|
|
105
103
|
}
|
|
106
104
|
try {
|
|
107
105
|
return await e.launch({ headless: !0 });
|
|
108
106
|
} catch (e) {
|
|
109
|
-
throw new
|
|
107
|
+
throw new y("Failed to launch Chromium. Run `npx playwright install chromium` to download the runtime, then retry.", e);
|
|
110
108
|
}
|
|
111
109
|
} }, e);
|
|
112
110
|
}
|
|
113
|
-
var
|
|
111
|
+
var y = class extends Error {
|
|
114
112
|
cause;
|
|
115
113
|
constructor(e, t) {
|
|
116
114
|
super(e), this.name = "ChromiumUnavailableError", this.cause = t;
|
|
117
115
|
}
|
|
118
|
-
},
|
|
116
|
+
}, b = class extends Error {
|
|
119
117
|
locator;
|
|
120
118
|
constructor(e, t) {
|
|
121
119
|
super(t), this.name = "LocatorResolutionError", this.locator = e;
|
|
122
120
|
}
|
|
123
121
|
};
|
|
124
|
-
async function
|
|
122
|
+
async function x(e, t) {
|
|
125
123
|
let n = await e.locator(t).boundingBox();
|
|
126
|
-
if (!n) throw new
|
|
124
|
+
if (!n) throw new b(t, `Locator "${t}" resolved to no visible element. Check the selector matches at least one element and the element is inside the captured viewport.`);
|
|
127
125
|
return n;
|
|
128
126
|
}
|
|
129
127
|
async function me(e, t) {
|
|
130
128
|
switch (t.type) {
|
|
131
129
|
case "rect": {
|
|
132
|
-
let n = t.bbox ?? await
|
|
130
|
+
let n = t.bbox ?? await x(e, C(t.locator));
|
|
133
131
|
return {
|
|
134
|
-
...
|
|
132
|
+
...w(t),
|
|
135
133
|
type: "rect",
|
|
136
134
|
bbox: n
|
|
137
135
|
};
|
|
138
136
|
}
|
|
139
137
|
case "circle": {
|
|
140
138
|
if (t.center !== void 0 && t.radius !== void 0) return {
|
|
141
|
-
...
|
|
139
|
+
...w(t),
|
|
142
140
|
type: "circle",
|
|
143
141
|
center: t.center,
|
|
144
142
|
radius: t.radius
|
|
145
143
|
};
|
|
146
|
-
let n = await
|
|
144
|
+
let n = await x(e, C(t.locator));
|
|
147
145
|
return {
|
|
148
|
-
...
|
|
146
|
+
...w(t),
|
|
149
147
|
type: "circle",
|
|
150
|
-
center:
|
|
148
|
+
center: S(n),
|
|
151
149
|
radius: Math.min(n.width, n.height) / 2
|
|
152
150
|
};
|
|
153
151
|
}
|
|
154
152
|
case "arrow": {
|
|
155
|
-
let n = t.from ??
|
|
153
|
+
let n = t.from ?? S(await x(e, C(t.fromLocator))), r = t.to ?? S(await x(e, C(t.toLocator)));
|
|
156
154
|
return {
|
|
157
|
-
...
|
|
155
|
+
...w(t),
|
|
158
156
|
type: "arrow",
|
|
159
157
|
from: n,
|
|
160
158
|
to: r
|
|
161
159
|
};
|
|
162
160
|
}
|
|
163
161
|
case "text": {
|
|
164
|
-
let n = t.at ?? _e(await
|
|
165
|
-
...
|
|
162
|
+
let n = t.at ?? _e(await x(e, C(t.locator)), t.fontSize), r = {
|
|
163
|
+
...w(t),
|
|
166
164
|
type: "text",
|
|
167
165
|
at: n,
|
|
168
166
|
content: t.content
|
|
@@ -170,9 +168,9 @@ async function me(e, t) {
|
|
|
170
168
|
return t.fontSize !== void 0 && (r.fontSize = t.fontSize), t.anchor !== void 0 && (r.anchor = t.anchor), r;
|
|
171
169
|
}
|
|
172
170
|
case "callout": {
|
|
173
|
-
let n = t.at ?? await ge(e, t.atLocator), r = t.targetBbox ?? await
|
|
171
|
+
let n = t.at ?? await ge(e, t.atLocator), r = t.targetBbox ?? await x(e, C(t.targetLocator));
|
|
174
172
|
return {
|
|
175
|
-
...
|
|
173
|
+
...w(t),
|
|
176
174
|
type: "callout",
|
|
177
175
|
at: n,
|
|
178
176
|
targetBbox: r,
|
|
@@ -188,10 +186,10 @@ async function he(e, t) {
|
|
|
188
186
|
return n;
|
|
189
187
|
}
|
|
190
188
|
async function ge(e, t) {
|
|
191
|
-
if (!t) throw new
|
|
192
|
-
return
|
|
189
|
+
if (!t) throw new b("<callout.at>", "callout annotations require either `at` or `atLocator`.");
|
|
190
|
+
return S(await x(e, t));
|
|
193
191
|
}
|
|
194
|
-
function
|
|
192
|
+
function S(e) {
|
|
195
193
|
return {
|
|
196
194
|
x: e.x + e.width / 2,
|
|
197
195
|
y: e.y + e.height / 2
|
|
@@ -204,95 +202,24 @@ function _e(e, t) {
|
|
|
204
202
|
y: Math.max(0, e.y - n)
|
|
205
203
|
};
|
|
206
204
|
}
|
|
207
|
-
function
|
|
208
|
-
if (e === void 0) throw new
|
|
205
|
+
function C(e) {
|
|
206
|
+
if (e === void 0) throw new b("<missing>", "Internal error: annotation passed schema validation without a locator or bbox. This is a bug.");
|
|
209
207
|
return e;
|
|
210
208
|
}
|
|
211
|
-
function
|
|
209
|
+
function w(e) {
|
|
212
210
|
if (e.type === "raw") return {};
|
|
213
211
|
let t = {};
|
|
214
212
|
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;
|
|
215
213
|
}
|
|
216
214
|
//#endregion
|
|
217
|
-
//#region src/compare/aggregate.ts
|
|
218
|
-
var ve = 4;
|
|
219
|
-
function ye(e, t, n) {
|
|
220
|
-
let r = new Uint8Array(t * n), i = [];
|
|
221
|
-
for (let a = 0; a < n; a++) for (let o = 0; o < t; o++) {
|
|
222
|
-
let s = a * t + o;
|
|
223
|
-
if (r[s] || !be(e, s)) continue;
|
|
224
|
-
let c = xe(e, r, o, a, t, n);
|
|
225
|
-
c.count >= ve && i.push({
|
|
226
|
-
x: c.minX,
|
|
227
|
-
y: c.minY,
|
|
228
|
-
width: c.maxX - c.minX + 1,
|
|
229
|
-
height: c.maxY - c.minY + 1
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
return i;
|
|
233
|
-
}
|
|
234
|
-
function be(e, t) {
|
|
235
|
-
return e[t * 4 + 3] > 0;
|
|
236
|
-
}
|
|
237
|
-
function xe(e, t, n, r, i, a) {
|
|
238
|
-
let o = {
|
|
239
|
-
count: 0,
|
|
240
|
-
minX: n,
|
|
241
|
-
minY: r,
|
|
242
|
-
maxX: n,
|
|
243
|
-
maxY: r
|
|
244
|
-
}, s = [n, r];
|
|
245
|
-
for (; s.length > 0;) {
|
|
246
|
-
let n = s.pop(), r = s.pop();
|
|
247
|
-
if (r < 0 || r >= i || n < 0 || n >= a) continue;
|
|
248
|
-
let c = n * i + r;
|
|
249
|
-
t[c] || be(e, c) && (t[c] = 1, o.count += 1, r < o.minX && (o.minX = r), n < o.minY && (o.minY = n), r > o.maxX && (o.maxX = r), n > o.maxY && (o.maxY = n), s.push(r + 1, n), s.push(r - 1, n), s.push(r, n + 1), s.push(r, n - 1));
|
|
250
|
-
}
|
|
251
|
-
return o;
|
|
252
|
-
}
|
|
253
|
-
//#endregion
|
|
254
|
-
//#region src/compare/diff.ts
|
|
255
|
-
var Se = class extends Error {
|
|
256
|
-
constructor(e, t) {
|
|
257
|
-
super(`Cannot compare screenshots of different dimensions: before is ${e.width}×${e.height}, after is ${t.width}×${t.height}.`), this.name = "DimensionMismatchError";
|
|
258
|
-
}
|
|
259
|
-
};
|
|
260
|
-
async function C(e, t, n = {}) {
|
|
261
|
-
let [r, i] = await Promise.all([f(Buffer.from(e)), f(Buffer.from(t))]);
|
|
262
|
-
if (r.width !== i.width || r.height !== i.height) throw new Se({
|
|
263
|
-
width: r.width,
|
|
264
|
-
height: r.height
|
|
265
|
-
}, {
|
|
266
|
-
width: i.width,
|
|
267
|
-
height: i.height
|
|
268
|
-
});
|
|
269
|
-
let { width: a, height: o } = r, s = w(r, a, o), c = w(i, a, o), l = new Uint8Array(a * o * 4);
|
|
270
|
-
return {
|
|
271
|
-
mismatchedPixels: ee(s, c, l, a, o, {
|
|
272
|
-
threshold: n.threshold ?? .1,
|
|
273
|
-
includeAA: !1,
|
|
274
|
-
diffMask: !0
|
|
275
|
-
}),
|
|
276
|
-
regions: ye(l, a, o),
|
|
277
|
-
width: a,
|
|
278
|
-
height: o
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
function w(e, t, n) {
|
|
282
|
-
let r = d(t, n).getContext("2d");
|
|
283
|
-
r.drawImage(e, 0, 0);
|
|
284
|
-
let i = r.getImageData(0, 0, t, n).data;
|
|
285
|
-
return new Uint8Array(i.buffer, i.byteOffset, i.byteLength);
|
|
286
|
-
}
|
|
287
|
-
//#endregion
|
|
288
215
|
//#region src/dsl/schema.ts
|
|
289
216
|
var T = {
|
|
290
|
-
...
|
|
217
|
+
...i,
|
|
291
218
|
Locator: {
|
|
292
219
|
type: "string",
|
|
293
220
|
minLength: 1
|
|
294
221
|
}
|
|
295
|
-
},
|
|
222
|
+
}, ve = { oneOf: [
|
|
296
223
|
{
|
|
297
224
|
type: "object",
|
|
298
225
|
required: ["type"],
|
|
@@ -407,7 +334,7 @@ var T = {
|
|
|
407
334
|
svgFragment: { type: "string" }
|
|
408
335
|
}
|
|
409
336
|
}
|
|
410
|
-
] },
|
|
337
|
+
] }, E = {
|
|
411
338
|
type: "object",
|
|
412
339
|
additionalProperties: !1,
|
|
413
340
|
properties: {
|
|
@@ -447,7 +374,7 @@ var T = {
|
|
|
447
374
|
description: "JPEG quality 60–100. Default 92."
|
|
448
375
|
}
|
|
449
376
|
}
|
|
450
|
-
},
|
|
377
|
+
}, D = {
|
|
451
378
|
type: "object",
|
|
452
379
|
additionalProperties: !1,
|
|
453
380
|
properties: {
|
|
@@ -464,7 +391,7 @@ var T = {
|
|
|
464
391
|
color: { type: "string" }
|
|
465
392
|
},
|
|
466
393
|
anyOf: [{ required: ["bbox"] }, { required: ["locator"] }]
|
|
467
|
-
},
|
|
394
|
+
}, O = [
|
|
468
395
|
137,
|
|
469
396
|
80,
|
|
470
397
|
78,
|
|
@@ -473,18 +400,18 @@ var T = {
|
|
|
473
400
|
10,
|
|
474
401
|
26,
|
|
475
402
|
10
|
|
476
|
-
],
|
|
403
|
+
], ye = 12, be = "IHDR", xe = 16, Se = 20, k = 24, A = class extends Error {
|
|
477
404
|
constructor(e) {
|
|
478
405
|
super(e), this.name = "InvalidPngError";
|
|
479
406
|
}
|
|
480
407
|
};
|
|
481
|
-
function
|
|
482
|
-
if (e.byteLength <
|
|
483
|
-
for (let t = 0; t <
|
|
484
|
-
let t = new DataView(e.buffer, e.byteOffset, e.byteLength), n = String.fromCharCode(e[
|
|
485
|
-
if (n !==
|
|
486
|
-
let r = t.getUint32(
|
|
487
|
-
if (r === 0 || i === 0) throw new
|
|
408
|
+
function j(e) {
|
|
409
|
+
if (e.byteLength < k) throw new A(`Expected at least ${k} bytes for a PNG header, got ${e.byteLength}.`);
|
|
410
|
+
for (let t = 0; t < O.length; t++) if (e[t] !== O[t]) throw new A("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.");
|
|
411
|
+
let t = new DataView(e.buffer, e.byteOffset, e.byteLength), n = String.fromCharCode(e[ye], e[13], e[14], e[15]);
|
|
412
|
+
if (n !== be) throw new A(`Expected IHDR chunk after PNG signature, found "${n}". The file may be a corrupt or non-standard PNG.`);
|
|
413
|
+
let r = t.getUint32(xe, !1), i = t.getUint32(Se, !1);
|
|
414
|
+
if (r === 0 || i === 0) throw new A(`PNG dimensions ${r}×${i} include a zero axis.`);
|
|
488
415
|
return {
|
|
489
416
|
width: r,
|
|
490
417
|
height: i
|
|
@@ -492,89 +419,58 @@ function A(e) {
|
|
|
492
419
|
}
|
|
493
420
|
//#endregion
|
|
494
421
|
//#region src/io/read-image.ts
|
|
495
|
-
var
|
|
422
|
+
var M = class extends Error {
|
|
496
423
|
constructor(e) {
|
|
497
424
|
super(e), this.name = "InvalidImageInputError";
|
|
498
425
|
}
|
|
499
|
-
},
|
|
500
|
-
async function
|
|
501
|
-
if (typeof e != "string" || e.length === 0) throw new
|
|
502
|
-
if (e.startsWith(
|
|
503
|
-
if (!m(e)) throw new
|
|
504
|
-
return
|
|
426
|
+
}, Ce = "data:", we = /^data:image\/png;base64,/i;
|
|
427
|
+
async function N(e) {
|
|
428
|
+
if (typeof e != "string" || e.length === 0) throw new M("`image` must be a non-empty string (data URL or absolute filesystem path).");
|
|
429
|
+
if (e.startsWith(Ce)) return Te(e);
|
|
430
|
+
if (!m(e)) throw new M(`Filesystem path "${e}" is not absolute. Pass an absolute path so resolution doesn't depend on the MCP server's working directory.`);
|
|
431
|
+
return Ee(e);
|
|
505
432
|
}
|
|
506
|
-
function
|
|
507
|
-
if (!
|
|
508
|
-
let t =
|
|
433
|
+
function Te(e) {
|
|
434
|
+
if (!we.test(e)) throw new M("Only `data:image/png;base64,...` URLs are supported. JPEG / WebP / SVG data URLs are not accepted in v1.");
|
|
435
|
+
let t = De(e.slice(e.indexOf(",") + 1));
|
|
509
436
|
return {
|
|
510
437
|
bytes: t,
|
|
511
438
|
dataUrl: e,
|
|
512
|
-
dimensions:
|
|
439
|
+
dimensions: P(t)
|
|
513
440
|
};
|
|
514
441
|
}
|
|
515
|
-
async function
|
|
442
|
+
async function Ee(e) {
|
|
516
443
|
let t;
|
|
517
444
|
try {
|
|
518
|
-
let n = await
|
|
445
|
+
let n = await re(e);
|
|
519
446
|
t = new Uint8Array(n.buffer, n.byteOffset, n.byteLength);
|
|
520
447
|
} catch (t) {
|
|
521
|
-
throw new
|
|
448
|
+
throw new M(`Failed to read image at "${e}": ${t instanceof Error ? t.message : String(t)}`);
|
|
522
449
|
}
|
|
523
|
-
let n =
|
|
450
|
+
let n = P(t), r = `data:image/png;base64,${Oe(t)}`;
|
|
524
451
|
return {
|
|
525
452
|
bytes: t,
|
|
526
453
|
dataUrl: r,
|
|
527
454
|
dimensions: n
|
|
528
455
|
};
|
|
529
456
|
}
|
|
530
|
-
function
|
|
457
|
+
function P(e) {
|
|
531
458
|
try {
|
|
532
|
-
return
|
|
459
|
+
return j(e);
|
|
533
460
|
} catch (e) {
|
|
534
|
-
throw e instanceof
|
|
461
|
+
throw e instanceof A ? new M(e.message) : e;
|
|
535
462
|
}
|
|
536
463
|
}
|
|
537
|
-
function
|
|
464
|
+
function De(e) {
|
|
538
465
|
let t = Buffer.from(e, "base64");
|
|
539
466
|
return new Uint8Array(t.buffer, t.byteOffset, t.byteLength);
|
|
540
467
|
}
|
|
541
|
-
function
|
|
468
|
+
function Oe(e) {
|
|
542
469
|
return Buffer.from(e.buffer, e.byteOffset, e.byteLength).toString("base64");
|
|
543
470
|
}
|
|
544
471
|
//#endregion
|
|
545
|
-
//#region src/redact/burn.ts
|
|
546
|
-
var Ie = "solid", Le = "#000000", Re = 16, ze = 12;
|
|
547
|
-
async function N(e, t) {
|
|
548
|
-
if (t.length === 0) return e;
|
|
549
|
-
let n = await f(Buffer.from(e)), r = d(n.width, n.height), i = r.getContext("2d");
|
|
550
|
-
i.drawImage(n, 0, 0);
|
|
551
|
-
for (let e of t) if (!(e.bbox.width <= 0 || e.bbox.height <= 0)) switch (e.style ?? Ie) {
|
|
552
|
-
case "solid":
|
|
553
|
-
Be(i, e.bbox, e.color ?? Le);
|
|
554
|
-
break;
|
|
555
|
-
case "mosaic":
|
|
556
|
-
Ve(i, n, e.bbox);
|
|
557
|
-
break;
|
|
558
|
-
case "blur":
|
|
559
|
-
He(i, n, e.bbox);
|
|
560
|
-
break;
|
|
561
|
-
}
|
|
562
|
-
let a = r.toBuffer("image/png");
|
|
563
|
-
return new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
|
|
564
|
-
}
|
|
565
|
-
function Be(e, t, n) {
|
|
566
|
-
e.save(), e.fillStyle = n, e.fillRect(t.x, t.y, t.width, t.height), e.restore();
|
|
567
|
-
}
|
|
568
|
-
function Ve(e, t, n) {
|
|
569
|
-
let r = Math.max(1, Math.round(n.width / Re)), i = Math.max(1, Math.round(n.height / Re)), a = d(r, i), o = a.getContext("2d");
|
|
570
|
-
o.imageSmoothingEnabled = !1, o.drawImage(t, n.x, n.y, n.width, n.height, 0, 0, r, i), e.save(), e.imageSmoothingEnabled = !1, e.drawImage(a, 0, 0, r, i, n.x, n.y, n.width, n.height), e.restore();
|
|
571
|
-
}
|
|
572
|
-
function He(e, t, n) {
|
|
573
|
-
e.save(), e.beginPath(), e.rect(n.x, n.y, n.width, n.height), e.clip(), e.filter = `blur(${ze}px)`, e.drawImage(t, 0, 0), e.restore();
|
|
574
|
-
}
|
|
575
|
-
//#endregion
|
|
576
472
|
//#region src/io/encode-output.ts
|
|
577
|
-
async function
|
|
473
|
+
async function F(e, t, r) {
|
|
578
474
|
if (!r || Object.keys(r).length === 0) return {
|
|
579
475
|
bytes: e,
|
|
580
476
|
mimeType: "image/png",
|
|
@@ -582,7 +478,7 @@ async function P(e, t, r) {
|
|
|
582
478
|
width: t.width,
|
|
583
479
|
height: t.height
|
|
584
480
|
};
|
|
585
|
-
let i = await
|
|
481
|
+
let i = await f(e, {
|
|
586
482
|
...n,
|
|
587
483
|
...r
|
|
588
484
|
});
|
|
@@ -597,8 +493,8 @@ async function P(e, t, r) {
|
|
|
597
493
|
}
|
|
598
494
|
//#endregion
|
|
599
495
|
//#region src/tools/annotate-screenshot.ts
|
|
600
|
-
var
|
|
601
|
-
name:
|
|
496
|
+
var I = "annot_annotate_screenshot", L = {
|
|
497
|
+
name: I,
|
|
602
498
|
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.",
|
|
603
499
|
inputSchema: {
|
|
604
500
|
type: "object",
|
|
@@ -626,13 +522,13 @@ var F = "annot_annotate_screenshot", I = {
|
|
|
626
522
|
$defs: {
|
|
627
523
|
...T,
|
|
628
524
|
BboxAnnotation: e,
|
|
629
|
-
EncodeOptions:
|
|
525
|
+
EncodeOptions: E
|
|
630
526
|
}
|
|
631
527
|
}
|
|
632
528
|
};
|
|
633
|
-
async function
|
|
529
|
+
async function R(e, t) {
|
|
634
530
|
try {
|
|
635
|
-
let n =
|
|
531
|
+
let n = ke(e), r = await N(n.image), i = c(n.annotations), a = await F(t.annotator.toPng({
|
|
636
532
|
originalDataUrl: r.dataUrl,
|
|
637
533
|
annotationsSvg: i,
|
|
638
534
|
width: r.dimensions.width,
|
|
@@ -648,25 +544,25 @@ async function L(e, t) {
|
|
|
648
544
|
}
|
|
649
545
|
return { content: [{
|
|
650
546
|
type: "image",
|
|
651
|
-
data:
|
|
547
|
+
data: je(a.bytes),
|
|
652
548
|
mimeType: a.mimeType
|
|
653
549
|
}] };
|
|
654
550
|
} catch (e) {
|
|
655
|
-
return
|
|
551
|
+
return Ae(e);
|
|
656
552
|
}
|
|
657
553
|
}
|
|
658
|
-
function
|
|
659
|
-
if (typeof e.image != "string") throw new
|
|
660
|
-
if (!Array.isArray(e.annotations)) throw new
|
|
554
|
+
function ke(e) {
|
|
555
|
+
if (typeof e.image != "string") throw new M("`image` is required and must be a string.");
|
|
556
|
+
if (!Array.isArray(e.annotations)) throw new z("`annotations` is required and must be an array.");
|
|
661
557
|
let t = e.annotations, n;
|
|
662
558
|
if (e.output !== void 0) {
|
|
663
|
-
if (typeof e.output != "string") throw new
|
|
664
|
-
if (!m(e.output)) throw new
|
|
559
|
+
if (typeof e.output != "string") throw new z("`output` must be a string when provided.");
|
|
560
|
+
if (!m(e.output)) throw new z(`\`output\` path "${e.output}" must be absolute so the file lands at a predictable location.`);
|
|
665
561
|
n = e.output;
|
|
666
562
|
}
|
|
667
563
|
let r;
|
|
668
564
|
if (e.encode !== void 0) {
|
|
669
|
-
if (typeof e.encode != "object" || e.encode === null) throw new
|
|
565
|
+
if (typeof e.encode != "object" || e.encode === null) throw new z("`encode` must be an object when provided.");
|
|
670
566
|
r = e.encode;
|
|
671
567
|
}
|
|
672
568
|
return {
|
|
@@ -676,12 +572,12 @@ function Ue(e) {
|
|
|
676
572
|
encode: r
|
|
677
573
|
};
|
|
678
574
|
}
|
|
679
|
-
var
|
|
575
|
+
var z = class extends Error {
|
|
680
576
|
constructor(e) {
|
|
681
577
|
super(e), this.name = "InvalidToolInputError";
|
|
682
578
|
}
|
|
683
579
|
};
|
|
684
|
-
function
|
|
580
|
+
function Ae(e) {
|
|
685
581
|
return {
|
|
686
582
|
content: [{
|
|
687
583
|
type: "text",
|
|
@@ -690,13 +586,13 @@ function We(e) {
|
|
|
690
586
|
isError: !0
|
|
691
587
|
};
|
|
692
588
|
}
|
|
693
|
-
function
|
|
589
|
+
function je(e) {
|
|
694
590
|
return Buffer.from(e.buffer, e.byteOffset, e.byteLength).toString("base64");
|
|
695
591
|
}
|
|
696
592
|
//#endregion
|
|
697
593
|
//#region src/tools/annotate-url.ts
|
|
698
|
-
var
|
|
699
|
-
name:
|
|
594
|
+
var B = "annot_annotate_url", Me = {
|
|
595
|
+
name: B,
|
|
700
596
|
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.",
|
|
701
597
|
inputSchema: {
|
|
702
598
|
type: "object",
|
|
@@ -760,8 +656,8 @@ var z = "annot_annotate_url", B = {
|
|
|
760
656
|
},
|
|
761
657
|
$defs: {
|
|
762
658
|
...T,
|
|
763
|
-
LocatorAnnotation:
|
|
764
|
-
EncodeOptions:
|
|
659
|
+
LocatorAnnotation: ve,
|
|
660
|
+
EncodeOptions: E
|
|
765
661
|
}
|
|
766
662
|
}
|
|
767
663
|
}, V = class extends Error {
|
|
@@ -769,9 +665,9 @@ var z = "annot_annotate_url", B = {
|
|
|
769
665
|
super(e), this.name = "InvalidAnnotateUrlInputError";
|
|
770
666
|
}
|
|
771
667
|
};
|
|
772
|
-
async function
|
|
668
|
+
async function Ne(e, t) {
|
|
773
669
|
try {
|
|
774
|
-
let n =
|
|
670
|
+
let n = Pe(e), r = await _(t.pool, {
|
|
775
671
|
url: n.url,
|
|
776
672
|
viewport: n.viewport,
|
|
777
673
|
fullPage: n.fullPage,
|
|
@@ -782,30 +678,30 @@ async function Ke(e, t) {
|
|
|
782
678
|
} finally {
|
|
783
679
|
await r.handle.close();
|
|
784
680
|
}
|
|
785
|
-
let a =
|
|
786
|
-
originalDataUrl: `data:image/png;base64,${
|
|
787
|
-
annotationsSvg:
|
|
681
|
+
let a = j(r.pngBytes), o = c(i), s = await F(t.annotator.toPng({
|
|
682
|
+
originalDataUrl: `data:image/png;base64,${Ie(r.pngBytes)}`,
|
|
683
|
+
annotationsSvg: o,
|
|
788
684
|
width: a.width,
|
|
789
685
|
height: a.height
|
|
790
686
|
}), a, n.encode);
|
|
791
687
|
if (n.output) {
|
|
792
|
-
await p(n.output,
|
|
793
|
-
let e =
|
|
688
|
+
await p(n.output, s.bytes);
|
|
689
|
+
let e = s.reason ? `, reason: ${s.reason}` : "";
|
|
794
690
|
return { content: [{
|
|
795
691
|
type: "text",
|
|
796
|
-
text: `Wrote ${
|
|
692
|
+
text: `Wrote ${s.bytes.byteLength}-byte ${s.chosen.toUpperCase()} to ${n.output} (${s.width}×${s.height}, ${n.annotations.length} annotation${n.annotations.length === 1 ? "" : "s"}, captured from ${n.url}${e}).`
|
|
797
693
|
}] };
|
|
798
694
|
}
|
|
799
695
|
return { content: [{
|
|
800
696
|
type: "image",
|
|
801
|
-
data:
|
|
802
|
-
mimeType:
|
|
697
|
+
data: Ie(s.bytes),
|
|
698
|
+
mimeType: s.mimeType
|
|
803
699
|
}] };
|
|
804
700
|
} catch (e) {
|
|
805
|
-
return
|
|
701
|
+
return Fe(e);
|
|
806
702
|
}
|
|
807
703
|
}
|
|
808
|
-
function
|
|
704
|
+
function Pe(e) {
|
|
809
705
|
if (typeof e.url != "string" || e.url.length === 0) throw new V("`url` is required and must be a non-empty string.");
|
|
810
706
|
if (!Array.isArray(e.annotations)) throw new V("`annotations` is required and must be an array.");
|
|
811
707
|
let t = e.annotations, n;
|
|
@@ -839,7 +735,7 @@ function qe(e) {
|
|
|
839
735
|
encode: o
|
|
840
736
|
};
|
|
841
737
|
}
|
|
842
|
-
function
|
|
738
|
+
function Fe(e) {
|
|
843
739
|
return {
|
|
844
740
|
content: [{
|
|
845
741
|
type: "text",
|
|
@@ -848,21 +744,21 @@ function Je(e) {
|
|
|
848
744
|
isError: !0
|
|
849
745
|
};
|
|
850
746
|
}
|
|
851
|
-
function
|
|
747
|
+
function Ie(e) {
|
|
852
748
|
return Buffer.from(e.buffer, e.byteOffset, e.byteLength).toString("base64");
|
|
853
749
|
}
|
|
854
750
|
//#endregion
|
|
855
751
|
//#region src/browser/aria-snapshot.ts
|
|
856
|
-
var
|
|
752
|
+
var Le = {
|
|
857
753
|
width: 1280,
|
|
858
754
|
height: 800,
|
|
859
755
|
deviceScaleFactor: 1
|
|
860
|
-
},
|
|
756
|
+
}, Re = "load", ze = "body";
|
|
861
757
|
async function H(e, t) {
|
|
862
758
|
let n = {
|
|
863
|
-
...
|
|
759
|
+
...Le,
|
|
864
760
|
...t.viewport
|
|
865
|
-
}, r = t.waitFor ??
|
|
761
|
+
}, r = t.waitFor ?? Re, i = t.rootSelector ?? ze, a = await e.acquire(), o, s = !1, c = () => {
|
|
866
762
|
s || (s = !0, e.release());
|
|
867
763
|
};
|
|
868
764
|
try {
|
|
@@ -889,8 +785,8 @@ async function H(e, t) {
|
|
|
889
785
|
}
|
|
890
786
|
//#endregion
|
|
891
787
|
//#region src/tools/aria-snapshot.ts
|
|
892
|
-
var
|
|
893
|
-
name:
|
|
788
|
+
var Be = "annot_aria_snapshot", Ve = {
|
|
789
|
+
name: Be,
|
|
894
790
|
description: "Open a URL in a headless browser and return Playwright's AI-mode aria-snapshot (YAML format with `[ref=eN]` markers). The same primitive `playwright-mcp` and `playwright-cli` use. Refs are session-local — store `role + name` (not refs) as persistent identifiers across snapshots.",
|
|
895
791
|
inputSchema: {
|
|
896
792
|
type: "object",
|
|
@@ -951,9 +847,9 @@ var $e = "annot_aria_snapshot", et = {
|
|
|
951
847
|
}
|
|
952
848
|
}
|
|
953
849
|
};
|
|
954
|
-
async function
|
|
850
|
+
async function He(e, t) {
|
|
955
851
|
if (typeof e.url != "string" || e.url.length === 0) return U("`url` is required (string).");
|
|
956
|
-
let n =
|
|
852
|
+
let n = Ue(e.viewport), r = We(e.waitFor), i = typeof e.rootSelector == "string" ? e.rootSelector : void 0, a = typeof e.timeout == "number" ? e.timeout : void 0, o = Ge(e.output);
|
|
957
853
|
if (o && !o.ok) return U(o.error);
|
|
958
854
|
let s;
|
|
959
855
|
try {
|
|
@@ -983,7 +879,7 @@ async function tt(e, t) {
|
|
|
983
879
|
text: s.yaml
|
|
984
880
|
}] };
|
|
985
881
|
}
|
|
986
|
-
function
|
|
882
|
+
function Ue(e) {
|
|
987
883
|
if (typeof e != "object" || !e) return;
|
|
988
884
|
let t = e, n = typeof t.width == "number" ? t.width : 1280, r = typeof t.height == "number" ? t.height : 800, i = typeof t.deviceScaleFactor == "number" ? t.deviceScaleFactor : void 0;
|
|
989
885
|
return {
|
|
@@ -992,10 +888,10 @@ function nt(e) {
|
|
|
992
888
|
...i === void 0 ? {} : { deviceScaleFactor: i }
|
|
993
889
|
};
|
|
994
890
|
}
|
|
995
|
-
function
|
|
891
|
+
function We(e) {
|
|
996
892
|
if (e === "load" || e === "domcontentloaded" || e === "networkidle") return e;
|
|
997
893
|
}
|
|
998
|
-
function
|
|
894
|
+
function Ge(e) {
|
|
999
895
|
if (e != null) return typeof e != "string" || e.length === 0 ? {
|
|
1000
896
|
ok: !1,
|
|
1001
897
|
error: "`output` must be a non-empty string when set."
|
|
@@ -1018,7 +914,7 @@ function U(e) {
|
|
|
1018
914
|
}
|
|
1019
915
|
//#endregion
|
|
1020
916
|
//#region src/tools/compare-screenshots.ts
|
|
1021
|
-
var W = "annot_compare_screenshots",
|
|
917
|
+
var W = "annot_compare_screenshots", Ke = {
|
|
1022
918
|
name: W,
|
|
1023
919
|
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.",
|
|
1024
920
|
inputSchema: {
|
|
@@ -1049,14 +945,14 @@ var W = "annot_compare_screenshots", at = {
|
|
|
1049
945
|
output: { type: "string" },
|
|
1050
946
|
encode: { $ref: "#/$defs/EncodeOptions" }
|
|
1051
947
|
},
|
|
1052
|
-
$defs: { EncodeOptions:
|
|
948
|
+
$defs: { EncodeOptions: E }
|
|
1053
949
|
}
|
|
1054
950
|
}, G = class extends Error {
|
|
1055
951
|
constructor(e) {
|
|
1056
952
|
super(e), this.name = "InvalidCompareInputError";
|
|
1057
953
|
}
|
|
1058
954
|
};
|
|
1059
|
-
async function
|
|
955
|
+
async function qe(e, t) {
|
|
1060
956
|
try {
|
|
1061
957
|
if (typeof e.before != "string") throw new G("`before` is required and must be a string.");
|
|
1062
958
|
if (typeof e.after != "string") throw new G("`after` is required and must be a string.");
|
|
@@ -1071,12 +967,12 @@ async function ot(e, t) {
|
|
|
1071
967
|
if (typeof e.encode != "object" || e.encode === null) throw new G("`encode` must be an object when provided.");
|
|
1072
968
|
a = e.encode;
|
|
1073
969
|
}
|
|
1074
|
-
let [
|
|
970
|
+
let [o, s] = await Promise.all([N(e.before), N(e.after)]), l = await ee(o.bytes, s.bytes, { threshold: n }), u = c(l.regions.map((e) => ({
|
|
1075
971
|
type: "rect",
|
|
1076
972
|
bbox: e,
|
|
1077
973
|
intent: "warning"
|
|
1078
|
-
}))), d = await
|
|
1079
|
-
originalDataUrl:
|
|
974
|
+
}))), d = await F(t.annotator.toPng({
|
|
975
|
+
originalDataUrl: s.dataUrl,
|
|
1080
976
|
annotationsSvg: u,
|
|
1081
977
|
width: l.width,
|
|
1082
978
|
height: l.height
|
|
@@ -1113,8 +1009,8 @@ async function ot(e, t) {
|
|
|
1113
1009
|
}
|
|
1114
1010
|
//#endregion
|
|
1115
1011
|
//#region src/tools/draft-screen-spec.ts
|
|
1116
|
-
var
|
|
1117
|
-
name:
|
|
1012
|
+
var Je = "annot_draft_screen_spec", Ye = {
|
|
1013
|
+
name: Je,
|
|
1118
1014
|
description: "Given a URL, propose an `.mdx` skeleton for an annot product-docs screen spec. The tool opens the page in a headless browser, takes a Playwright `aria-snapshot`, and emits an MDX with frontmatter + a `<Screen>` block containing one `<Overlay match={{ role, name }}>` per interactive element. The agent fills in the prose body of each overlay; the structural skeleton is mechanical.",
|
|
1119
1015
|
inputSchema: {
|
|
1120
1016
|
type: "object",
|
|
@@ -1175,7 +1071,7 @@ var st = "annot_draft_screen_spec", ct = {
|
|
|
1175
1071
|
}
|
|
1176
1072
|
}
|
|
1177
1073
|
}
|
|
1178
|
-
},
|
|
1074
|
+
}, Xe = /* @__PURE__ */ new Set([
|
|
1179
1075
|
"button",
|
|
1180
1076
|
"checkbox",
|
|
1181
1077
|
"combobox",
|
|
@@ -1193,20 +1089,20 @@ var st = "annot_draft_screen_spec", ct = {
|
|
|
1193
1089
|
"textbox",
|
|
1194
1090
|
"treeitem"
|
|
1195
1091
|
]);
|
|
1196
|
-
async function
|
|
1092
|
+
async function Ze(e, t) {
|
|
1197
1093
|
if (typeof e.url != "string" || e.url.length === 0) return K("`url` is required (string).");
|
|
1198
1094
|
if (typeof e.id != "string" || e.id.length === 0) return K("`id` is required (string).");
|
|
1199
1095
|
let n = e.id, r = typeof e.title == "string" ? e.title : void 0, i = typeof e.book == "string" ? e.book : void 0, a = (typeof e.screenImageSrc == "string" ? e.screenImageSrc : "./shots/{id}.png").replace(/\{id\}/g, n), o;
|
|
1200
1096
|
try {
|
|
1201
1097
|
o = await H(t.pool, {
|
|
1202
1098
|
url: e.url,
|
|
1203
|
-
viewport:
|
|
1204
|
-
waitFor:
|
|
1099
|
+
viewport: Qe(e.viewport),
|
|
1100
|
+
waitFor: $e(e.waitFor)
|
|
1205
1101
|
});
|
|
1206
1102
|
} catch (e) {
|
|
1207
1103
|
return K(`Failed to capture aria-snapshot: ${e instanceof Error ? e.message : String(e)}`);
|
|
1208
1104
|
}
|
|
1209
|
-
let s =
|
|
1105
|
+
let s = g(o.yaml).filter((e) => Xe.has(e.role)).map((e, t) => `<Overlay match={{ role: ${JSON.stringify(e.role)}, name: ${JSON.stringify(e.name)} }} number={${t + 1}}>
|
|
1210
1106
|
TODO: describe ${e.role} "${e.name}".
|
|
1211
1107
|
</Overlay>`);
|
|
1212
1108
|
return { content: [{
|
|
@@ -1237,7 +1133,7 @@ TODO: describe ${e.role} "${e.name}".
|
|
|
1237
1133
|
].join("\n")}\n`
|
|
1238
1134
|
}] };
|
|
1239
1135
|
}
|
|
1240
|
-
function
|
|
1136
|
+
function Qe(e) {
|
|
1241
1137
|
if (typeof e != "object" || !e) return;
|
|
1242
1138
|
let t = e, n = typeof t.width == "number" ? t.width : 1280, r = typeof t.height == "number" ? t.height : 800, i = typeof t.deviceScaleFactor == "number" ? t.deviceScaleFactor : void 0;
|
|
1243
1139
|
return {
|
|
@@ -1246,7 +1142,7 @@ function dt(e) {
|
|
|
1246
1142
|
...i === void 0 ? {} : { deviceScaleFactor: i }
|
|
1247
1143
|
};
|
|
1248
1144
|
}
|
|
1249
|
-
function
|
|
1145
|
+
function $e(e) {
|
|
1250
1146
|
if (e === "load" || e === "domcontentloaded" || e === "networkidle") return e;
|
|
1251
1147
|
}
|
|
1252
1148
|
function K(e) {
|
|
@@ -1260,8 +1156,8 @@ function K(e) {
|
|
|
1260
1156
|
}
|
|
1261
1157
|
//#endregion
|
|
1262
1158
|
//#region src/tools/propose-drift-fixes.ts
|
|
1263
|
-
var
|
|
1264
|
-
name:
|
|
1159
|
+
var et = "annot_propose_drift_fixes", tt = {
|
|
1160
|
+
name: et,
|
|
1265
1161
|
description: "Given an MDX path + the live URL the screen renders at, run drift detection between the stored `<Overlay match>` keys and the current `aria-snapshot`. Returns a structured Markdown report: one section per finding with the kind / severity / message / suggested fix. The agent reads the report and applies edits via its own patch primitive.",
|
|
1266
1162
|
inputSchema: {
|
|
1267
1163
|
type: "object",
|
|
@@ -1314,12 +1210,12 @@ var pt = "annot_propose_drift_fixes", mt = {
|
|
|
1314
1210
|
}
|
|
1315
1211
|
}
|
|
1316
1212
|
};
|
|
1317
|
-
async function
|
|
1213
|
+
async function nt(e, t) {
|
|
1318
1214
|
if (typeof e.mdxPath != "string" || e.mdxPath.length === 0) return q("`mdxPath` is required (string).");
|
|
1319
1215
|
if (typeof e.url != "string" || e.url.length === 0) return q("`url` is required (string).");
|
|
1320
|
-
let n = typeof e.screenId == "string" ? e.screenId : void 0, r = await
|
|
1216
|
+
let n = typeof e.screenId == "string" ? e.screenId : void 0, r = await h(e.mdxPath);
|
|
1321
1217
|
if (!r) return q(`${e.mdxPath} has no \`annot:\` frontmatter.`);
|
|
1322
|
-
let i =
|
|
1218
|
+
let i = ce(r.screens).filter((e) => !n || e.id === n);
|
|
1323
1219
|
if (i.length === 0) return { content: [{
|
|
1324
1220
|
type: "text",
|
|
1325
1221
|
text: `No lintable screens in ${e.mdxPath}${n ? ` (screenId=${n})` : ""}.`
|
|
@@ -1330,15 +1226,15 @@ async function ht(e, t) {
|
|
|
1330
1226
|
try {
|
|
1331
1227
|
r = await H(t.pool, {
|
|
1332
1228
|
url: e.url,
|
|
1333
|
-
viewport:
|
|
1334
|
-
waitFor:
|
|
1229
|
+
viewport: it(e.viewport),
|
|
1230
|
+
waitFor: at(e.waitFor)
|
|
1335
1231
|
});
|
|
1336
1232
|
} catch (e) {
|
|
1337
1233
|
return q(`Failed to capture aria-snapshot for screen=${n.id}: ${e instanceof Error ? e.message : String(e)}`);
|
|
1338
1234
|
}
|
|
1339
|
-
let i =
|
|
1235
|
+
let i = se({
|
|
1340
1236
|
screen: n,
|
|
1341
|
-
liveSnapshot:
|
|
1237
|
+
liveSnapshot: g(r.yaml)
|
|
1342
1238
|
});
|
|
1343
1239
|
for (let e of i) a.push({
|
|
1344
1240
|
screenId: n.id,
|
|
@@ -1350,16 +1246,16 @@ async function ht(e, t) {
|
|
|
1350
1246
|
text: `No drift detected in ${e.mdxPath} against ${e.url}.`
|
|
1351
1247
|
}] } : { content: [{
|
|
1352
1248
|
type: "text",
|
|
1353
|
-
text:
|
|
1249
|
+
text: rt(e.mdxPath, e.url, a)
|
|
1354
1250
|
}] };
|
|
1355
1251
|
}
|
|
1356
|
-
function
|
|
1252
|
+
function rt(e, t, n) {
|
|
1357
1253
|
let r = [];
|
|
1358
1254
|
r.push(`# Drift report — ${e}`), r.push(""), r.push(`Live URL: ${t}`), r.push(`Findings: ${n.length}`), r.push("");
|
|
1359
1255
|
for (let { screenId: e, finding: t } of n) r.push(`## ${t.severity.toUpperCase()} [${e}] ${t.kind}`), r.push(""), r.push(t.message), t.match && (r.push(""), r.push("Current match key:"), r.push("```ts"), r.push(JSON.stringify(t.match, null, 2)), r.push("```")), t.suggestion && (r.push(""), r.push("Suggested replacement:"), r.push("```ts"), r.push(JSON.stringify(t.suggestion, null, 2)), r.push("```")), r.push("");
|
|
1360
1256
|
return r.join("\n");
|
|
1361
1257
|
}
|
|
1362
|
-
function
|
|
1258
|
+
function it(e) {
|
|
1363
1259
|
if (typeof e != "object" || !e) return;
|
|
1364
1260
|
let t = e, n = typeof t.width == "number" ? t.width : 1280, r = typeof t.height == "number" ? t.height : 800, i = typeof t.deviceScaleFactor == "number" ? t.deviceScaleFactor : void 0;
|
|
1365
1261
|
return {
|
|
@@ -1368,7 +1264,7 @@ function _t(e) {
|
|
|
1368
1264
|
...i === void 0 ? {} : { deviceScaleFactor: i }
|
|
1369
1265
|
};
|
|
1370
1266
|
}
|
|
1371
|
-
function
|
|
1267
|
+
function at(e) {
|
|
1372
1268
|
if (e === "load" || e === "domcontentloaded" || e === "networkidle") return e;
|
|
1373
1269
|
}
|
|
1374
1270
|
function q(e) {
|
|
@@ -1382,7 +1278,7 @@ function q(e) {
|
|
|
1382
1278
|
}
|
|
1383
1279
|
//#endregion
|
|
1384
1280
|
//#region src/tools/redact-screenshot.ts
|
|
1385
|
-
var J = "annot_redact_screenshot",
|
|
1281
|
+
var J = "annot_redact_screenshot", Y = {
|
|
1386
1282
|
name: J,
|
|
1387
1283
|
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.",
|
|
1388
1284
|
inputSchema: {
|
|
@@ -1407,30 +1303,30 @@ var J = "annot_redact_screenshot", yt = {
|
|
|
1407
1303
|
$defs: {
|
|
1408
1304
|
...T,
|
|
1409
1305
|
BboxRedactRegion: t,
|
|
1410
|
-
EncodeOptions:
|
|
1306
|
+
EncodeOptions: E
|
|
1411
1307
|
}
|
|
1412
1308
|
}
|
|
1413
|
-
},
|
|
1309
|
+
}, X = class extends Error {
|
|
1414
1310
|
constructor(e) {
|
|
1415
1311
|
super(e), this.name = "InvalidRedactInputError";
|
|
1416
1312
|
}
|
|
1417
1313
|
};
|
|
1418
|
-
async function
|
|
1314
|
+
async function ot(e) {
|
|
1419
1315
|
try {
|
|
1420
|
-
if (typeof e.image != "string") throw new
|
|
1421
|
-
if (!Array.isArray(e.regions)) throw new
|
|
1316
|
+
if (typeof e.image != "string") throw new X("`image` is required and must be a string.");
|
|
1317
|
+
if (!Array.isArray(e.regions)) throw new X("`regions` is required and must be an array.");
|
|
1422
1318
|
let t = e.regions, n;
|
|
1423
1319
|
if (e.output !== void 0) {
|
|
1424
|
-
if (typeof e.output != "string") throw new
|
|
1425
|
-
if (!m(e.output)) throw new
|
|
1320
|
+
if (typeof e.output != "string") throw new X("`output` must be a string when provided.");
|
|
1321
|
+
if (!m(e.output)) throw new X(`\`output\` path "${e.output}" must be absolute.`);
|
|
1426
1322
|
n = e.output;
|
|
1427
1323
|
}
|
|
1428
1324
|
let r;
|
|
1429
1325
|
if (e.encode !== void 0) {
|
|
1430
|
-
if (typeof e.encode != "object" || e.encode === null) throw new
|
|
1326
|
+
if (typeof e.encode != "object" || e.encode === null) throw new X("`encode` must be an object when provided.");
|
|
1431
1327
|
r = e.encode;
|
|
1432
1328
|
}
|
|
1433
|
-
let i = await
|
|
1329
|
+
let i = await N(e.image), a = await F(await l(i.bytes, t), i.dimensions, r);
|
|
1434
1330
|
if (n) {
|
|
1435
1331
|
await p(n, a.bytes);
|
|
1436
1332
|
let e = a.reason ? `, reason: ${a.reason}` : "";
|
|
@@ -1456,7 +1352,7 @@ async function X(e) {
|
|
|
1456
1352
|
}
|
|
1457
1353
|
//#endregion
|
|
1458
1354
|
//#region src/tools/redact-url.ts
|
|
1459
|
-
var Z = "annot_redact_url",
|
|
1355
|
+
var Z = "annot_redact_url", st = {
|
|
1460
1356
|
name: Z,
|
|
1461
1357
|
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.",
|
|
1462
1358
|
inputSchema: {
|
|
@@ -1511,8 +1407,8 @@ var Z = "annot_redact_url", bt = {
|
|
|
1511
1407
|
},
|
|
1512
1408
|
$defs: {
|
|
1513
1409
|
...T,
|
|
1514
|
-
LocatorRedactRegion:
|
|
1515
|
-
EncodeOptions:
|
|
1410
|
+
LocatorRedactRegion: D,
|
|
1411
|
+
EncodeOptions: E
|
|
1516
1412
|
}
|
|
1517
1413
|
}
|
|
1518
1414
|
}, Q = class extends Error {
|
|
@@ -1520,9 +1416,9 @@ var Z = "annot_redact_url", bt = {
|
|
|
1520
1416
|
super(e), this.name = "InvalidRedactUrlInputError";
|
|
1521
1417
|
}
|
|
1522
1418
|
};
|
|
1523
|
-
async function
|
|
1419
|
+
async function ct(e, t) {
|
|
1524
1420
|
try {
|
|
1525
|
-
let n =
|
|
1421
|
+
let n = lt(e), r = await _(t.pool, {
|
|
1526
1422
|
url: n.url,
|
|
1527
1423
|
viewport: n.viewport,
|
|
1528
1424
|
fullPage: n.fullPage,
|
|
@@ -1531,13 +1427,13 @@ async function xt(e, t) {
|
|
|
1531
1427
|
try {
|
|
1532
1428
|
i = [];
|
|
1533
1429
|
for (let e of n.regions) {
|
|
1534
|
-
let t = { bbox: await
|
|
1430
|
+
let t = { bbox: await ut(r.handle.page, e) };
|
|
1535
1431
|
e.style !== void 0 && (t.style = e.style), e.color !== void 0 && (t.color = e.color), i.push(t);
|
|
1536
1432
|
}
|
|
1537
1433
|
} finally {
|
|
1538
1434
|
await r.handle.close();
|
|
1539
1435
|
}
|
|
1540
|
-
let a = await
|
|
1436
|
+
let a = await F(await l(r.pngBytes, i), j(r.pngBytes), n.encode);
|
|
1541
1437
|
if (n.output) {
|
|
1542
1438
|
await p(n.output, a.bytes);
|
|
1543
1439
|
let e = a.reason ? `, reason: ${a.reason}` : "";
|
|
@@ -1561,7 +1457,7 @@ async function xt(e, t) {
|
|
|
1561
1457
|
};
|
|
1562
1458
|
}
|
|
1563
1459
|
}
|
|
1564
|
-
function
|
|
1460
|
+
function lt(e) {
|
|
1565
1461
|
if (typeof e.url != "string" || e.url.length === 0) throw new Q("`url` is required and must be a non-empty string.");
|
|
1566
1462
|
if (!Array.isArray(e.regions)) throw new Q("`regions` is required and must be an array.");
|
|
1567
1463
|
let t = e.regions, n;
|
|
@@ -1595,15 +1491,15 @@ function St(e) {
|
|
|
1595
1491
|
encode: o
|
|
1596
1492
|
};
|
|
1597
1493
|
}
|
|
1598
|
-
async function
|
|
1494
|
+
async function ut(e, t) {
|
|
1599
1495
|
if (t.bbox !== void 0) return t.bbox;
|
|
1600
|
-
if (t.locator !== void 0) return
|
|
1496
|
+
if (t.locator !== void 0) return x(e, t.locator);
|
|
1601
1497
|
throw new Q("redact region requires either `bbox` or `locator`.");
|
|
1602
1498
|
}
|
|
1603
1499
|
//#endregion
|
|
1604
1500
|
//#region src/tools/translate-screen-spec.ts
|
|
1605
|
-
var
|
|
1606
|
-
name:
|
|
1501
|
+
var dt = "annot_translate_screen_spec", ft = {
|
|
1502
|
+
name: dt,
|
|
1607
1503
|
description: "Given an MDX with `annot:` frontmatter and a target locale (e.g. `en-US` / `ja-JP` / `ko-KR`), emit a structured translation manifest listing every translatable string the agent should localise: frontmatter title / purpose, per-overlay Markdown bodies, per-transition prose. The agent translates the strings via its own LLM call and the host writes the localised MDX.",
|
|
1608
1504
|
inputSchema: {
|
|
1609
1505
|
type: "object",
|
|
@@ -1625,10 +1521,10 @@ var wt = "annot_translate_screen_spec", Tt = {
|
|
|
1625
1521
|
}
|
|
1626
1522
|
}
|
|
1627
1523
|
};
|
|
1628
|
-
async function
|
|
1524
|
+
async function pt(e) {
|
|
1629
1525
|
if (typeof e.mdxPath != "string" || e.mdxPath.length === 0) return $("`mdxPath` is required (string).");
|
|
1630
1526
|
if (typeof e.targetLocale != "string" || e.targetLocale.length === 0) return $("`targetLocale` is required (string).");
|
|
1631
|
-
let t = await
|
|
1527
|
+
let t = await h(e.mdxPath);
|
|
1632
1528
|
if (!t) return $(`${e.mdxPath} has no \`annot:\` frontmatter.`);
|
|
1633
1529
|
let n = [];
|
|
1634
1530
|
t.frontmatter.title && n.push({
|
|
@@ -1692,54 +1588,54 @@ function $(e) {
|
|
|
1692
1588
|
}
|
|
1693
1589
|
//#endregion
|
|
1694
1590
|
//#region src/server.ts
|
|
1695
|
-
var
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1591
|
+
var mt = "annot-mcp", ht = "0.1.0", gt = [
|
|
1592
|
+
L,
|
|
1593
|
+
Me,
|
|
1594
|
+
Y,
|
|
1595
|
+
st,
|
|
1596
|
+
Ke,
|
|
1597
|
+
Ve,
|
|
1598
|
+
Ye,
|
|
1599
|
+
tt,
|
|
1600
|
+
ft
|
|
1705
1601
|
];
|
|
1706
|
-
function
|
|
1707
|
-
let t = new
|
|
1708
|
-
name:
|
|
1709
|
-
version: e.version ??
|
|
1710
|
-
}, { capabilities: { tools: {} } }), n = e.annotator ??
|
|
1711
|
-
return t.setRequestHandler(
|
|
1602
|
+
function _t(e = {}) {
|
|
1603
|
+
let t = new ie({
|
|
1604
|
+
name: mt,
|
|
1605
|
+
version: e.version ?? ht
|
|
1606
|
+
}, { capabilities: { tools: {} } }), n = e.annotator ?? d(e.annotatorOptions ?? {}), r = e.pool ?? pe();
|
|
1607
|
+
return t.setRequestHandler(oe, async () => ({ tools: gt })), t.setRequestHandler(ae, async (e) => {
|
|
1712
1608
|
let { name: t, arguments: i } = e.params, a;
|
|
1713
1609
|
switch (t) {
|
|
1714
|
-
case
|
|
1715
|
-
a = await
|
|
1610
|
+
case I:
|
|
1611
|
+
a = await R(i ?? {}, { annotator: n });
|
|
1716
1612
|
break;
|
|
1717
|
-
case
|
|
1718
|
-
a = await
|
|
1613
|
+
case B:
|
|
1614
|
+
a = await Ne(i ?? {}, {
|
|
1719
1615
|
annotator: n,
|
|
1720
1616
|
pool: r
|
|
1721
1617
|
});
|
|
1722
1618
|
break;
|
|
1723
1619
|
case J:
|
|
1724
|
-
a = await
|
|
1620
|
+
a = await ot(i ?? {});
|
|
1725
1621
|
break;
|
|
1726
1622
|
case Z:
|
|
1727
|
-
a = await
|
|
1623
|
+
a = await ct(i ?? {}, { pool: r });
|
|
1728
1624
|
break;
|
|
1729
1625
|
case W:
|
|
1730
|
-
a = await
|
|
1626
|
+
a = await qe(i ?? {}, { annotator: n });
|
|
1731
1627
|
break;
|
|
1732
|
-
case
|
|
1733
|
-
a = await
|
|
1628
|
+
case Be:
|
|
1629
|
+
a = await He(i ?? {}, { pool: r });
|
|
1734
1630
|
break;
|
|
1735
|
-
case
|
|
1736
|
-
a = await
|
|
1631
|
+
case Je:
|
|
1632
|
+
a = await Ze(i ?? {}, { pool: r });
|
|
1737
1633
|
break;
|
|
1738
|
-
case
|
|
1739
|
-
a = await
|
|
1634
|
+
case et:
|
|
1635
|
+
a = await nt(i ?? {}, { pool: r });
|
|
1740
1636
|
break;
|
|
1741
|
-
case
|
|
1742
|
-
a = await
|
|
1637
|
+
case dt:
|
|
1638
|
+
a = await pt(i ?? {});
|
|
1743
1639
|
break;
|
|
1744
1640
|
default: a = {
|
|
1745
1641
|
content: [{
|
|
@@ -1754,9 +1650,9 @@ function At(e = {}) {
|
|
|
1754
1650
|
}
|
|
1755
1651
|
//#endregion
|
|
1756
1652
|
//#region src/transport.ts
|
|
1757
|
-
async function
|
|
1758
|
-
let e =
|
|
1653
|
+
async function vt() {
|
|
1654
|
+
let e = _t(), t = new le();
|
|
1759
1655
|
await e.connect(t);
|
|
1760
1656
|
}
|
|
1761
1657
|
//#endregion
|
|
1762
|
-
export {
|
|
1658
|
+
export { I as ANNOTATE_SCREENSHOT_TOOL_NAME, B as ANNOTATE_URL_TOOL_NAME, e as BBOX_ANNOTATION_SCHEMA, t as BBOX_REDACT_REGION_SCHEMA, v as BrowserPool, W as COMPARE_SCREENSHOTS_TOOL_NAME, y as ChromiumUnavailableError, r as DimensionMismatchError, M as InvalidImageInputError, A as InvalidPngError, ve as LOCATOR_ANNOTATION_SCHEMA, D as LOCATOR_REDACT_REGION_SCHEMA, b as LocatorResolutionError, J as REDACT_SCREENSHOT_TOOL_NAME, Z as REDACT_URL_TOOL_NAME, T as SHARED_DEFS, a as aggregateDiffRegions, L as annotateScreenshotTool, Me as annotateUrlTool, o as arrowBetween, s as bboxAnnotationsToSvg, l as burnRedactions, u as burnRegions, _ as capturePage, Ke as compareScreenshotsTool, pe as createChromiumPool, _t as createServer, ee as diffScreenshots, R as handleAnnotateScreenshot, Ne as handleAnnotateUrl, qe as handleCompareScreenshots, ot as handleRedactScreenshot, ct as handleRedactUrl, j as readPngDimensions, te as rectForBoundingBox, Y as redactScreenshotTool, st as redactUrlTool, N as resolveImageInput, x as resolveLocator, me as resolveLocatorAnnotation, he as resolveLocatorAnnotations, vt as runStdioServer, ne as textAt };
|