import type { Command } from "commander"; import { browserSnapshot, resolveBrowserControlUrl, } from "../browser/client.js"; import { browserScreenshotAction } from "../browser/client-actions.js"; import { danger } from "../globals.js"; import { defaultRuntime } from "../runtime.js"; import type { BrowserParentOpts } from "./browser-cli-shared.js"; export function registerBrowserInspectCommands( browser: Command, parentOpts: (cmd: Command) => BrowserParentOpts, ) { browser .command("screenshot") .description("Capture a screenshot (MEDIA:)") .argument("[targetId]", "CDP target id (or unique prefix)") .option("--full-page", "Capture full scrollable page", false) .option("--ref ", "ARIA ref from ai snapshot") .option("--element ", "CSS selector for element screenshot") .option("--type ", "Output type (default: png)", "png") .action(async (targetId: string | undefined, opts, cmd) => { const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; try { const result = await browserScreenshotAction(baseUrl, { targetId: targetId?.trim() || undefined, fullPage: Boolean(opts.fullPage), ref: opts.ref?.trim() || undefined, element: opts.element?.trim() || undefined, type: opts.type === "jpeg" ? "jpeg" : "png", profile, }); if (parent?.json) { defaultRuntime.log(JSON.stringify(result, null, 2)); return; } defaultRuntime.log(`MEDIA:${result.path}`); } catch (err) { defaultRuntime.error(danger(String(err))); defaultRuntime.exit(1); } }); browser .command("snapshot") .description( "Capture a snapshot (default: ai; aria is the accessibility tree)", ) .option("--format ", "Snapshot format (default: ai)", "ai") .option("--target-id ", "CDP target id (or unique prefix)") .option("--limit ", "Max nodes (default: 500/800)", (v: string) => Number(v), ) .option("--out ", "Write snapshot to a file") .action(async (opts, cmd) => { const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; const format = opts.format === "aria" ? "aria" : "ai"; try { const result = await browserSnapshot(baseUrl, { format, targetId: opts.targetId?.trim() || undefined, limit: Number.isFinite(opts.limit) ? opts.limit : undefined, profile, }); if (opts.out) { const fs = await import("node:fs/promises"); if (result.format === "ai") { await fs.writeFile(opts.out, result.snapshot, "utf8"); } else { const payload = JSON.stringify(result, null, 2); await fs.writeFile(opts.out, payload, "utf8"); } if (parent?.json) { defaultRuntime.log( JSON.stringify({ ok: true, out: opts.out }, null, 2), ); } else { defaultRuntime.log(opts.out); } return; } if (parent?.json) { defaultRuntime.log(JSON.stringify(result, null, 2)); return; } if (result.format === "ai") { defaultRuntime.log(result.snapshot); return; } const nodes = "nodes" in result ? result.nodes : []; defaultRuntime.log( nodes .map((n) => { const indent = " ".repeat(Math.min(20, n.depth)); const name = n.name ? ` "${n.name}"` : ""; const value = n.value ? ` = "${n.value}"` : ""; return `${indent}- ${n.role}${name}${value}`; }) .join("\n"), ); } catch (err) { defaultRuntime.error(danger(String(err))); defaultRuntime.exit(1); } }); }