@fusengine/browser-mcp 0.1.7 → 0.1.9
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/README.md +8 -1
- package/dist/agent/shots.d.ts +12 -0
- package/dist/agent/shots.d.ts.map +1 -0
- package/dist/agent/shots.js +35 -0
- package/dist/agent/shots.js.map +1 -0
- package/dist/bin/cli.js +19 -52
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/probe-cli.d.ts +5 -0
- package/dist/bin/probe-cli.d.ts.map +1 -0
- package/dist/bin/probe-cli.js +62 -0
- package/dist/bin/probe-cli.js.map +1 -0
- package/dist/bin/serp-batch-cli.d.ts +5 -0
- package/dist/bin/serp-batch-cli.d.ts.map +1 -0
- package/dist/bin/serp-batch-cli.js +31 -0
- package/dist/bin/serp-batch-cli.js.map +1 -0
- package/dist/bin/shots-cli.d.ts +5 -0
- package/dist/bin/shots-cli.d.ts.map +1 -0
- package/dist/bin/shots-cli.js +33 -0
- package/dist/bin/shots-cli.js.map +1 -0
- package/dist/engine/viewport.d.ts +28 -0
- package/dist/engine/viewport.d.ts.map +1 -0
- package/dist/engine/viewport.js +23 -0
- package/dist/engine/viewport.js.map +1 -0
- package/dist/server/result.d.ts +5 -0
- package/dist/server/result.d.ts.map +1 -1
- package/dist/server/result.js +8 -0
- package/dist/server/result.js.map +1 -1
- package/dist/server/tools/screenshot.d.ts +1 -1
- package/dist/server/tools/screenshot.d.ts.map +1 -1
- package/dist/server/tools/screenshot.js +30 -5
- package/dist/server/tools/screenshot.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,6 +47,13 @@ npx fuse-browser probe 'https://www.booking.com/searchresults.html?ss=Tokyo' \
|
|
|
47
47
|
|
|
48
48
|
# Use the installed Chrome
|
|
49
49
|
npx fuse-browser probe https://example.com --channel chrome
|
|
50
|
+
|
|
51
|
+
# SEO rank tracking across many keywords (one session)
|
|
52
|
+
npx fuse-browser serp-batch "agence web vevey" "création site web lausanne" \
|
|
53
|
+
--rank-domain fusengine.ch --serp-pages 2 --hl fr --gl ch
|
|
54
|
+
|
|
55
|
+
# Responsive screenshots (saved PNGs) — works on localhost too
|
|
56
|
+
npx fuse-browser shots http://localhost:8000 --viewports mobile,desktop,1280x720
|
|
50
57
|
```
|
|
51
58
|
|
|
52
59
|
Sensitive actions (`pay`, `book`, `checkout`, `confirm`, …) are **blocked** unless
|
|
@@ -95,7 +102,7 @@ Supported: `FUSE_ENGINE`, `FUSE_CHANNEL`, `FUSE_CDP_ENDPOINT`, `FUSE_EXECUTABLE_
|
|
|
95
102
|
| **Agentic** | `browser_snapshot` (indexed refs), `browser_act` (by ref + page diff), `browser_run` (multi-step plan) |
|
|
96
103
|
| **Extract** | `browser_extract` (text/prices/hotels/challenges), `browser_extract_schema` (typed, by CSS selectors) |
|
|
97
104
|
| **SERP** | `browser_serp_batch` — multi-query Google search in one session, per-query organic results + domain rank |
|
|
98
|
-
| **Vision** | `browser_screenshot` (page
|
|
105
|
+
| **Vision** | `browser_screenshot` (page, single element by `ref`, or responsive set via `viewport`/`viewports`) |
|
|
99
106
|
|
|
100
107
|
Key agentic patterns:
|
|
101
108
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ViewportInput } from "../engine/viewport.js";
|
|
2
|
+
import type { ResolvedConfig } from "./config.js";
|
|
3
|
+
/** One saved responsive screenshot. */
|
|
4
|
+
export interface Shot {
|
|
5
|
+
viewport: string;
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
path: string;
|
|
9
|
+
}
|
|
10
|
+
/** Open `url`, screenshot it at each viewport, return the saved file paths. */
|
|
11
|
+
export declare function captureShots(config: ResolvedConfig, url: string, viewports: ViewportInput[]): Promise<Shot[]>;
|
|
12
|
+
//# sourceMappingURL=shots.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shots.d.ts","sourceRoot":"","sources":["../../src/agent/shots.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,aAAa,EAAmB,MAAM,uBAAuB,CAAC;AAG5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,uCAAuC;AACvC,MAAM,WAAW,IAAI;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,+EAA+E;AAC/E,wBAAsB,YAAY,CAChC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,aAAa,EAAE,GACzB,OAAO,CAAC,IAAI,EAAE,CAAC,CAoBjB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture one page across several viewports, saving a PNG per viewport.
|
|
3
|
+
* Uses `setViewportSize` (CSS-responsive screenshot, not full device emulation).
|
|
4
|
+
* @module agent/shots
|
|
5
|
+
*/
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { selectEngineForConfig } from "../engine/registry.js";
|
|
8
|
+
import { teardownOpened } from "../engine/teardown.js";
|
|
9
|
+
import { resolveViewport } from "../engine/viewport.js";
|
|
10
|
+
import { ensureDir, sha1 } from "../lib/fs.js";
|
|
11
|
+
import { gotoWithRetry } from "../net/navigate.js";
|
|
12
|
+
/** Open `url`, screenshot it at each viewport, return the saved file paths. */
|
|
13
|
+
export async function captureShots(config, url, viewports) {
|
|
14
|
+
ensureDir(config.outputDir);
|
|
15
|
+
const runId = sha1(`${url}-shots`).slice(0, 10);
|
|
16
|
+
const opened = await selectEngineForConfig(config).open(config);
|
|
17
|
+
const page = opened.page ?? (await opened.context.newPage());
|
|
18
|
+
const shots = [];
|
|
19
|
+
try {
|
|
20
|
+
await gotoWithRetry(page, url, { waitUntil: "domcontentloaded", timeout: 30_000 }, config.retry);
|
|
21
|
+
for (const v of viewports) {
|
|
22
|
+
const size = resolveViewport(v);
|
|
23
|
+
await page.setViewportSize(size);
|
|
24
|
+
const name = typeof v === "string" ? v : `${size.width}x${size.height}`;
|
|
25
|
+
const path = join(config.outputDir, `${runId}-${name}.png`);
|
|
26
|
+
await page.screenshot({ path, fullPage: true });
|
|
27
|
+
shots.push({ viewport: name, width: size.width, height: size.height, path });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
await teardownOpened(opened);
|
|
32
|
+
}
|
|
33
|
+
return shots;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=shots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shots.js","sourceRoot":"","sources":["../../src/agent/shots.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAsB,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAWnD,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAsB,EACtB,GAAW,EACX,SAA0B;IAE1B,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,GAAG,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAW,EAAE,CAAC;IACzB,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QACjG,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;YAChC,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACxE,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,KAAK,IAAI,IAAI,MAAM,CAAC,CAAC;YAC5D,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YAChD,KAAK,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/bin/cli.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* fuse-browser CLI entry point
|
|
3
|
+
* fuse-browser CLI entry point. Subcommands: `probe`, `serp-batch`.
|
|
4
4
|
* @module bin/cli
|
|
5
5
|
*/
|
|
6
6
|
import { parseArgs } from "node:util";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { runProbeCli } from "./probe-cli.js";
|
|
8
|
+
import { runSerpBatch } from "./serp-batch-cli.js";
|
|
9
|
+
import { runShots } from "./shots-cli.js";
|
|
10
10
|
const { positionals, values } = parseArgs({
|
|
11
11
|
allowPositionals: true,
|
|
12
12
|
options: {
|
|
@@ -21,6 +21,10 @@ const { positionals, values } = parseArgs({
|
|
|
21
21
|
"extract-serp": { type: "boolean" },
|
|
22
22
|
"serp-pages": { type: "string" },
|
|
23
23
|
"rank-domain": { type: "string" },
|
|
24
|
+
viewports: { type: "string" },
|
|
25
|
+
hl: { type: "string" },
|
|
26
|
+
gl: { type: "string" },
|
|
27
|
+
"delay-ms": { type: "string" },
|
|
24
28
|
"human-mode": { type: "boolean" },
|
|
25
29
|
approved: { type: "boolean" },
|
|
26
30
|
replay: { type: "boolean" },
|
|
@@ -35,56 +39,19 @@ const { positionals, values } = parseArgs({
|
|
|
35
39
|
fill: { type: "string", multiple: true },
|
|
36
40
|
},
|
|
37
41
|
});
|
|
38
|
-
const [command,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
const [command, ...rest] = positionals;
|
|
43
|
+
const opts = values;
|
|
44
|
+
if (command === "serp-batch") {
|
|
45
|
+
await runSerpBatch(rest, opts);
|
|
42
46
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const eq = item.indexOf("=");
|
|
46
|
-
if (eq < 0) {
|
|
47
|
-
process.stderr.write("--fill must be TARGET=VALUE\n");
|
|
48
|
-
process.exit(1);
|
|
49
|
-
}
|
|
50
|
-
actions.push({ type: "fill", target: item.slice(0, eq), value: item.slice(eq + 1) });
|
|
47
|
+
else if (command === "shots" && rest[0]) {
|
|
48
|
+
await runShots(rest[0], opts);
|
|
51
49
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const agent = new BrowserAgent({
|
|
55
|
-
engine: values.engine,
|
|
56
|
-
countryCode: values.country,
|
|
57
|
-
currency: values.currency,
|
|
58
|
-
headless: !values.headed,
|
|
59
|
-
humanMode: Boolean(values["human-mode"]),
|
|
60
|
-
outputDir: values["output-dir"],
|
|
61
|
-
storageStatePath: values["storage-state"],
|
|
62
|
-
proxyUrl: values.proxy,
|
|
63
|
-
proxyMapPath: values["proxy-map"],
|
|
64
|
-
userDataDir: values["user-data-dir"],
|
|
65
|
-
replayEnabled: Boolean(values.replay),
|
|
66
|
-
siteMemoryDir: values["site-memory-dir"],
|
|
67
|
-
});
|
|
68
|
-
try {
|
|
69
|
-
const report = await agent.probe(url, {
|
|
70
|
-
actions,
|
|
71
|
-
humanApproved: Boolean(values.approved),
|
|
72
|
-
autoConsent: Boolean(values["auto-consent"]),
|
|
73
|
-
extractPrices: Boolean(values["extract-prices"]),
|
|
74
|
-
detectChallenges: Boolean(values["detect-challenges"]),
|
|
75
|
-
observeVisual: Boolean(values["observe-visual"]),
|
|
76
|
-
extractSerp: Boolean(values["extract-serp"]),
|
|
77
|
-
serpPages: values["serp-pages"] ? Number(values["serp-pages"]) : undefined,
|
|
78
|
-
rankDomain: values["rank-domain"],
|
|
79
|
-
waitMs: values["wait-ms"] ? Number(values["wait-ms"]) : 0,
|
|
80
|
-
});
|
|
81
|
-
process.stdout.write(`${JSON.stringify(compactReport(report), null, 2)}\n`);
|
|
50
|
+
else if (command === "probe" && rest[0]) {
|
|
51
|
+
await runProbeCli(rest[0], opts);
|
|
82
52
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
process.exit(2);
|
|
87
|
-
}
|
|
88
|
-
throw err;
|
|
53
|
+
else {
|
|
54
|
+
process.stderr.write("usage: fuse-browser probe <url> [...] | serp-batch <query...> --rank-domain <d> | shots <url> --viewports mobile,desktop\n");
|
|
55
|
+
process.exit(1);
|
|
89
56
|
}
|
|
90
57
|
//# sourceMappingURL=cli.js.map
|
package/dist/bin/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/bin/cli.ts"],"names":[],"mappings":";AACA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/bin/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"probe-cli.d.ts","sourceRoot":"","sources":["../../src/bin/probe-cli.ts"],"names":[],"mappings":"AAUA,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAiBtC,gDAAgD;AAChD,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoC5E"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `probe` subcommand handler: run one probe and print the compact report.
|
|
3
|
+
* @module bin/probe-cli
|
|
4
|
+
*/
|
|
5
|
+
import { BrowserAgent } from "../agent/browser-agent.js";
|
|
6
|
+
import { compactReport } from "../agent/compact.js";
|
|
7
|
+
import { GuardrailViolation } from "../lib/errors.js";
|
|
8
|
+
const str = (v) => (typeof v === "string" ? v : undefined);
|
|
9
|
+
function buildActions(values) {
|
|
10
|
+
const actions = [];
|
|
11
|
+
for (const item of values.fill ?? []) {
|
|
12
|
+
const eq = item.indexOf("=");
|
|
13
|
+
if (eq < 0) {
|
|
14
|
+
process.stderr.write("--fill must be TARGET=VALUE\n");
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
actions.push({ type: "fill", target: item.slice(0, eq), value: item.slice(eq + 1) });
|
|
18
|
+
}
|
|
19
|
+
for (const target of values.click ?? [])
|
|
20
|
+
actions.push({ type: "click", target });
|
|
21
|
+
return actions;
|
|
22
|
+
}
|
|
23
|
+
/** Run the `probe` subcommand against `url`. */
|
|
24
|
+
export async function runProbeCli(url, values) {
|
|
25
|
+
const agent = new BrowserAgent({
|
|
26
|
+
engine: str(values.engine),
|
|
27
|
+
countryCode: str(values.country),
|
|
28
|
+
currency: str(values.currency),
|
|
29
|
+
headless: !values.headed,
|
|
30
|
+
humanMode: Boolean(values["human-mode"]),
|
|
31
|
+
outputDir: str(values["output-dir"]),
|
|
32
|
+
storageStatePath: str(values["storage-state"]),
|
|
33
|
+
proxyUrl: str(values.proxy),
|
|
34
|
+
proxyMapPath: str(values["proxy-map"]),
|
|
35
|
+
userDataDir: str(values["user-data-dir"]),
|
|
36
|
+
replayEnabled: Boolean(values.replay),
|
|
37
|
+
siteMemoryDir: str(values["site-memory-dir"]),
|
|
38
|
+
});
|
|
39
|
+
try {
|
|
40
|
+
const report = await agent.probe(url, {
|
|
41
|
+
actions: buildActions(values),
|
|
42
|
+
humanApproved: Boolean(values.approved),
|
|
43
|
+
autoConsent: Boolean(values["auto-consent"]),
|
|
44
|
+
extractPrices: Boolean(values["extract-prices"]),
|
|
45
|
+
detectChallenges: Boolean(values["detect-challenges"]),
|
|
46
|
+
observeVisual: Boolean(values["observe-visual"]),
|
|
47
|
+
extractSerp: Boolean(values["extract-serp"]),
|
|
48
|
+
serpPages: values["serp-pages"] ? Number(values["serp-pages"]) : undefined,
|
|
49
|
+
rankDomain: str(values["rank-domain"]),
|
|
50
|
+
waitMs: values["wait-ms"] ? Number(values["wait-ms"]) : 0,
|
|
51
|
+
});
|
|
52
|
+
process.stdout.write(`${JSON.stringify(compactReport(report), null, 2)}\n`);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
if (err instanceof GuardrailViolation) {
|
|
56
|
+
process.stderr.write(`BLOCKED: ${err.message}\n`);
|
|
57
|
+
process.exit(2);
|
|
58
|
+
}
|
|
59
|
+
throw err;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=probe-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"probe-cli.js","sourceRoot":"","sources":["../../src/bin/probe-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serp-batch-cli.d.ts","sourceRoot":"","sources":["../../src/bin/serp-batch-cli.ts"],"names":[],"mappings":"AAQA,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAGtC,sDAAsD;AACtD,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBnF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `serp-batch` subcommand handler: run several Google searches, print JSON rows.
|
|
3
|
+
* @module bin/serp-batch-cli
|
|
4
|
+
*/
|
|
5
|
+
import { resolveConfig } from "../agent/config.js";
|
|
6
|
+
import { serpBatch } from "../agent/serp-batch.js";
|
|
7
|
+
const str = (v) => (typeof v === "string" ? v : undefined);
|
|
8
|
+
/** Run the `serp-batch` subcommand over `queries`. */
|
|
9
|
+
export async function runSerpBatch(queries, values) {
|
|
10
|
+
if (queries.length === 0) {
|
|
11
|
+
process.stderr.write("serp-batch needs at least one query\n");
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
const config = resolveConfig({
|
|
15
|
+
engine: str(values.engine),
|
|
16
|
+
countryCode: str(values.country),
|
|
17
|
+
headless: !values.headed,
|
|
18
|
+
outputDir: str(values["output-dir"]),
|
|
19
|
+
proxyUrl: str(values.proxy),
|
|
20
|
+
});
|
|
21
|
+
const rows = await serpBatch(config, {
|
|
22
|
+
queries,
|
|
23
|
+
rankDomain: str(values["rank-domain"]),
|
|
24
|
+
pages: values["serp-pages"] ? Number(values["serp-pages"]) : undefined,
|
|
25
|
+
hl: str(values.hl),
|
|
26
|
+
gl: str(values.gl),
|
|
27
|
+
delayMs: values["delay-ms"] ? Number(values["delay-ms"]) : undefined,
|
|
28
|
+
});
|
|
29
|
+
process.stdout.write(`${JSON.stringify(rows, null, 2)}\n`);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=serp-batch-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serp-batch-cli.js","sourceRoot":"","sources":["../../src/bin/serp-batch-cli.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAInD,MAAM,GAAG,GAAG,CAAC,CAAU,EAAsB,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAExF,sDAAsD;AACtD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAiB,EAAE,MAAc;IAClE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,MAAM,GAAG,aAAa,CAAC;QAC3B,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,CAA2B;QACpD,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;QAChC,QAAQ,EAAE,CAAC,MAAM,CAAC,MAAM;QACxB,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACpC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;KAC5B,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE;QACnC,OAAO;QACP,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QACtC,KAAK,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;QACtE,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAClB,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;KACrE,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shots-cli.d.ts","sourceRoot":"","sources":["../../src/bin/shots-cli.ts"],"names":[],"mappings":"AASA,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAiBtC,gDAAgD;AAChD,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CASzE"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `shots` subcommand handler: responsive screenshots saved to disk.
|
|
3
|
+
* @module bin/shots-cli
|
|
4
|
+
*/
|
|
5
|
+
import { resolveConfig } from "../agent/config.js";
|
|
6
|
+
import { captureShots } from "../agent/shots.js";
|
|
7
|
+
const str = (v) => (typeof v === "string" ? v : undefined);
|
|
8
|
+
const PRESETS = ["mobile", "tablet", "desktop"];
|
|
9
|
+
/** Parse a `--viewports` CSV ("mobile,desktop,1280x720") into viewport inputs. */
|
|
10
|
+
function parseViewports(csv) {
|
|
11
|
+
return (csv ?? "mobile,desktop")
|
|
12
|
+
.split(",")
|
|
13
|
+
.map((s) => s.trim())
|
|
14
|
+
.filter(Boolean)
|
|
15
|
+
.map((p) => {
|
|
16
|
+
if (PRESETS.includes(p))
|
|
17
|
+
return p;
|
|
18
|
+
const [w, h] = p.split("x").map(Number);
|
|
19
|
+
return Number.isFinite(w) && Number.isFinite(h) ? { width: w, height: h } : "desktop";
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/** Run the `shots` subcommand against `url`. */
|
|
23
|
+
export async function runShots(url, values) {
|
|
24
|
+
const config = resolveConfig({
|
|
25
|
+
engine: str(values.engine),
|
|
26
|
+
countryCode: str(values.country),
|
|
27
|
+
headless: !values.headed,
|
|
28
|
+
outputDir: str(values["output-dir"]),
|
|
29
|
+
});
|
|
30
|
+
const shots = await captureShots(config, url, parseViewports(str(values.viewports)));
|
|
31
|
+
process.stdout.write(`${JSON.stringify(shots, null, 2)}\n`);
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=shots-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shots-cli.js","sourceRoot":"","sources":["../../src/bin/shots-cli.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKjD,MAAM,GAAG,GAAG,CAAC,CAAU,EAAsB,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AACxF,MAAM,OAAO,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AAEhD,kFAAkF;AAClF,SAAS,cAAc,CAAC,GAAuB;IAC7C,OAAO,CAAC,GAAG,IAAI,gBAAgB,CAAC;SAC7B,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,CAAC,EAAiB,EAAE;QACxB,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,OAAO,CAAkB,CAAC;QACnD,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACxC,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAW,EAAE,MAAM,EAAE,CAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5G,CAAC,CAAC,CAAC;AACP,CAAC;AAED,gDAAgD;AAChD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAW,EAAE,MAAc;IACxD,MAAM,MAAM,GAAG,aAAa,CAAC;QAC3B,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,CAA2B;QACpD,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;QAChC,QAAQ,EAAE,CAAC,MAAM,CAAC,MAAM;QACxB,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;KACrC,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,GAAG,EAAE,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACrF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Named device viewport presets (CSS pixels). */
|
|
2
|
+
export declare const VIEWPORT_PRESETS: {
|
|
3
|
+
readonly mobile: {
|
|
4
|
+
readonly width: 390;
|
|
5
|
+
readonly height: 844;
|
|
6
|
+
};
|
|
7
|
+
readonly tablet: {
|
|
8
|
+
readonly width: 768;
|
|
9
|
+
readonly height: 1024;
|
|
10
|
+
};
|
|
11
|
+
readonly desktop: {
|
|
12
|
+
readonly width: 1365;
|
|
13
|
+
readonly height: 900;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
/** A viewport: a preset name or an explicit size. */
|
|
17
|
+
export type ViewportInput = keyof typeof VIEWPORT_PRESETS | {
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
};
|
|
21
|
+
/** Resolve a viewport input to concrete width/height. */
|
|
22
|
+
export declare function resolveViewport(input: ViewportInput): {
|
|
23
|
+
width: number;
|
|
24
|
+
height: number;
|
|
25
|
+
};
|
|
26
|
+
/** Human label for a viewport (preset name or `WxH`). */
|
|
27
|
+
export declare function viewportLabel(input: ViewportInput): string;
|
|
28
|
+
//# sourceMappingURL=viewport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewport.d.ts","sourceRoot":"","sources":["../../src/engine/viewport.ts"],"names":[],"mappings":"AAMA,kDAAkD;AAClD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;CAInB,CAAC;AAEX,qDAAqD;AACrD,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,gBAAgB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9F,yDAAyD;AACzD,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAGvF;AAED,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAG1D"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Viewport presets and resolution for responsive screenshots.
|
|
3
|
+
* @module engine/viewport
|
|
4
|
+
*/
|
|
5
|
+
import { VIEWPORT } from "./context.js";
|
|
6
|
+
/** Named device viewport presets (CSS pixels). */
|
|
7
|
+
export const VIEWPORT_PRESETS = {
|
|
8
|
+
mobile: { width: 390, height: 844 },
|
|
9
|
+
tablet: { width: 768, height: 1024 },
|
|
10
|
+
desktop: { width: VIEWPORT.width, height: VIEWPORT.height },
|
|
11
|
+
};
|
|
12
|
+
/** Resolve a viewport input to concrete width/height. */
|
|
13
|
+
export function resolveViewport(input) {
|
|
14
|
+
if (typeof input === "string")
|
|
15
|
+
return { ...VIEWPORT_PRESETS[input] };
|
|
16
|
+
return { width: input.width, height: input.height };
|
|
17
|
+
}
|
|
18
|
+
/** Human label for a viewport (preset name or `WxH`). */
|
|
19
|
+
export function viewportLabel(input) {
|
|
20
|
+
const { width, height } = resolveViewport(input);
|
|
21
|
+
return `${typeof input === "string" ? input : "custom"} ${width}x${height}`;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=viewport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewport.js","sourceRoot":"","sources":["../../src/engine/viewport.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,kDAAkD;AAClD,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;IACnC,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IACpC,OAAO,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE;CACnD,CAAC;AAKX,yDAAyD;AACzD,MAAM,UAAU,eAAe,CAAC,KAAoB;IAClD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;IACrE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;AACtD,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,aAAa,CAAC,KAAoB;IAChD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACjD,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,IAAI,KAAK,IAAI,MAAM,EAAE,CAAC;AAC9E,CAAC"}
|
package/dist/server/result.d.ts
CHANGED
|
@@ -9,4 +9,9 @@ export declare function jsonResult(payload: Record<string, unknown>): CallToolRe
|
|
|
9
9
|
export declare function errorResult(message: string): CallToolResult;
|
|
10
10
|
/** Image result (PNG base64) with an optional text note. */
|
|
11
11
|
export declare function imageResult(base64: string, note?: string): CallToolResult;
|
|
12
|
+
/** Several images (PNG base64), each preceded by a label note. No structuredContent. */
|
|
13
|
+
export declare function multiImageResult(items: Array<{
|
|
14
|
+
base64: string;
|
|
15
|
+
note: string;
|
|
16
|
+
}>): CallToolResult;
|
|
12
17
|
//# sourceMappingURL=result.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../../src/server/result.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,qCAAqC;AACrC,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,cAAc,CAK3E;AAED,uCAAuC;AACvC,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAE3D;AAED,4DAA4D;AAC5D,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,CAIzE"}
|
|
1
|
+
{"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../../src/server/result.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,qCAAqC;AACrC,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,cAAc,CAK3E;AAED,uCAAuC;AACvC,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAE3D;AAED,4DAA4D;AAC5D,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,CAIzE;AAED,wFAAwF;AACxF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,cAAc,CAM/F"}
|
package/dist/server/result.js
CHANGED
|
@@ -15,4 +15,12 @@ export function imageResult(base64, note) {
|
|
|
15
15
|
const text = note ? [{ type: "text", text: note }] : [];
|
|
16
16
|
return { content: [image, ...text] };
|
|
17
17
|
}
|
|
18
|
+
/** Several images (PNG base64), each preceded by a label note. No structuredContent. */
|
|
19
|
+
export function multiImageResult(items) {
|
|
20
|
+
const content = items.flatMap((it) => [
|
|
21
|
+
{ type: "text", text: it.note },
|
|
22
|
+
{ type: "image", data: it.base64, mimeType: "image/png" },
|
|
23
|
+
]);
|
|
24
|
+
return { content };
|
|
25
|
+
}
|
|
18
26
|
//# sourceMappingURL=result.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/server/result.ts"],"names":[],"mappings":"AAMA,qCAAqC;AACrC,MAAM,UAAU,UAAU,CAAC,OAAgC;IACzD,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QACnE,iBAAiB,EAAE,OAAO;KAC3B,CAAC;AACJ,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACvE,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,IAAa;IACvD,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,OAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;IAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;AACvC,CAAC"}
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/server/result.ts"],"names":[],"mappings":"AAMA,qCAAqC;AACrC,MAAM,UAAU,UAAU,CAAC,OAAgC;IACzD,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QACnE,iBAAiB,EAAE,OAAO;KAC3B,CAAC;AACJ,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACvE,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,IAAa;IACvD,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,OAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;IAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;AACvC,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,gBAAgB,CAAC,KAA8C;IAC7E,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC;QACpC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE;QACxC,EAAE,IAAI,EAAE,OAAgB,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE;KACnE,CAAC,CAAC;IACH,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Screenshot tool: returns a PNG as MCP image content. Optionally targets a
|
|
3
|
-
* single element by
|
|
3
|
+
* single element by `ref`, or captures across one/several viewports (responsive).
|
|
4
4
|
* @module server/tools/screenshot
|
|
5
5
|
*/
|
|
6
6
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../../src/server/tools/screenshot.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../../src/server/tools/screenshot.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAS/D,qCAAqC;AACrC,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,CA0CxF"}
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { REF_ATTRIBUTE } from "../../extraction/snapshot.js";
|
|
3
|
-
import {
|
|
3
|
+
import { resolveViewport, viewportLabel } from "../../engine/viewport.js";
|
|
4
|
+
import { errorResult, imageResult, multiImageResult } from "../result.js";
|
|
4
5
|
import { withSession } from "./with-session.js";
|
|
6
|
+
const VIEWPORT_SCHEMA = z.union([
|
|
7
|
+
z.enum(["mobile", "tablet", "desktop"]),
|
|
8
|
+
z.object({ width: z.number().int(), height: z.number().int() }),
|
|
9
|
+
]);
|
|
5
10
|
/** Register `browser_screenshot`. */
|
|
6
11
|
export function registerScreenshotTool(server, sessions) {
|
|
7
12
|
server.registerTool("browser_screenshot", {
|
|
8
13
|
title: "Screenshot",
|
|
9
|
-
description: "Capture the live page as
|
|
10
|
-
inputSchema: {
|
|
14
|
+
description: "Capture the live page as PNG(s) for vision. Pass `ref` for one element, `viewport` for one size, or `viewports` (e.g. [\"mobile\",\"desktop\"]) for a responsive set.",
|
|
15
|
+
inputSchema: {
|
|
16
|
+
sessionId: z.string(),
|
|
17
|
+
fullPage: z.boolean().optional(),
|
|
18
|
+
ref: z.number().int().optional(),
|
|
19
|
+
viewport: VIEWPORT_SCHEMA.optional(),
|
|
20
|
+
viewports: z.array(VIEWPORT_SCHEMA).optional(),
|
|
21
|
+
},
|
|
11
22
|
}, async (args) => {
|
|
12
23
|
const a = args;
|
|
13
24
|
return withSession(sessions, String(a.sessionId), async (s) => {
|
|
@@ -18,8 +29,22 @@ export function registerScreenshotTool(server, sessions) {
|
|
|
18
29
|
const buf = await locator.screenshot({ timeout: 5_000 });
|
|
19
30
|
return imageResult(buf.toString("base64"), `element ref=${a.ref}`);
|
|
20
31
|
}
|
|
21
|
-
const
|
|
22
|
-
|
|
32
|
+
const fullPage = Boolean(a.fullPage);
|
|
33
|
+
const list = (Array.isArray(a.viewports) ? a.viewports : a.viewport ? [a.viewport] : []);
|
|
34
|
+
if (list.length === 0) {
|
|
35
|
+
const buffer = await s.page.screenshot({ fullPage });
|
|
36
|
+
return imageResult(buffer.toString("base64"), `screenshot of ${s.page.url()}`);
|
|
37
|
+
}
|
|
38
|
+
const original = s.page.viewportSize();
|
|
39
|
+
const shots = [];
|
|
40
|
+
for (const v of list) {
|
|
41
|
+
await s.page.setViewportSize(resolveViewport(v));
|
|
42
|
+
const buf = await s.page.screenshot({ fullPage });
|
|
43
|
+
shots.push({ base64: buf.toString("base64"), note: viewportLabel(v) });
|
|
44
|
+
}
|
|
45
|
+
if (original)
|
|
46
|
+
await s.page.setViewportSize(original);
|
|
47
|
+
return multiImageResult(shots);
|
|
23
48
|
});
|
|
24
49
|
});
|
|
25
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../../src/server/tools/screenshot.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../../src/server/tools/screenshot.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusengine/browser-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "MCP server + CLI giving AI agents a real, stealth browser (Patchright/Playwright) — per-country identity, self-healing actions, snapshots, multi-step plans, structured extraction, CDP attach.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Fusengine",
|