@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 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 or single element by `ref`) |
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 (`probe` subcommand).
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 { BrowserAgent } from "../agent/browser-agent.js";
8
- import { compactReport } from "../agent/compact.js";
9
- import { GuardrailViolation } from "../lib/errors.js";
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, url] = positionals;
39
- if (command !== "probe" || !url) {
40
- process.stderr.write("usage: fuse-browser probe <url> [--click TEXT] [--fill TARGET=VALUE] [--country US] [--headed] ...\n");
41
- process.exit(1);
42
+ const [command, ...rest] = positionals;
43
+ const opts = values;
44
+ if (command === "serp-batch") {
45
+ await runSerpBatch(rest, opts);
42
46
  }
43
- const actions = [];
44
- for (const item of (values.fill ?? [])) {
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
- for (const target of (values.click ?? []))
53
- actions.push({ type: "click", target });
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
- catch (err) {
84
- if (err instanceof GuardrailViolation) {
85
- process.stderr.write(`BLOCKED: ${err.message}\n`);
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
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/bin/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/bin/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ type Values = Record<string, unknown>;
2
+ /** Run the `probe` subcommand against `url`. */
3
+ export declare function runProbeCli(url: string, values: Values): Promise<void>;
4
+ export {};
5
+ //# sourceMappingURL=probe-cli.d.ts.map
@@ -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,5 @@
1
+ type Values = Record<string, unknown>;
2
+ /** Run the `serp-batch` subcommand over `queries`. */
3
+ export declare function runSerpBatch(queries: string[], values: Values): Promise<void>;
4
+ export {};
5
+ //# sourceMappingURL=serp-batch-cli.d.ts.map
@@ -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,5 @@
1
+ type Values = Record<string, unknown>;
2
+ /** Run the `shots` subcommand against `url`. */
3
+ export declare function runShots(url: string, values: Values): Promise<void>;
4
+ export {};
5
+ //# sourceMappingURL=shots-cli.d.ts.map
@@ -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"}
@@ -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"}
@@ -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 its snapshot `ref` (focused vision, fewer image tokens).
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;AAGzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAI/D,qCAAqC;AACrC,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,CAuBxF"}
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 { errorResult, imageResult } from "../result.js";
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 a PNG for vision. Pass `ref` (from browser_snapshot) to capture only that element instead of the page.",
10
- inputSchema: { sessionId: z.string(), fullPage: z.boolean().optional(), ref: z.number().int().optional() },
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 buffer = await s.page.screenshot({ fullPage: Boolean(a.fullPage) });
22
- return imageResult(buffer.toString("base64"), `screenshot of ${s.page.url()}`);
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;AAE7D,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,qCAAqC;AACrC,MAAM,UAAU,sBAAsB,CAAC,MAAiB,EAAE,QAAwB;IAChF,MAAM,CAAC,YAAY,CACjB,oBAAoB,EACpB;QACE,KAAK,EAAE,YAAY;QACnB,WAAW,EACT,iIAAiI;QACnI,WAAW,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAE;KAC3G,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,MAAM,CAAC,GAAG,IAA+B,CAAC;QAC1C,OAAO,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YAC5D,IAAI,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;gBAC9B,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,aAAa,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;gBACxE,IAAI,CAAC,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC;oBAAE,OAAO,WAAW,CAAC,eAAe,CAAC,CAAC;gBACvE,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;gBACzD,OAAO,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACrE,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YAC1E,OAAO,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACjF,CAAC,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,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.7",
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",