Files
clawdbot/src/cli/browser-cli-debug.ts
2026-01-12 17:32:44 +00:00

183 lines
6.0 KiB
TypeScript

import type { Command } from "commander";
import { resolveBrowserControlUrl } from "../browser/client.js";
import {
browserHighlight,
browserPageErrors,
browserRequests,
browserTraceStart,
browserTraceStop,
} 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 registerBrowserDebugCommands(
browser: Command,
parentOpts: (cmd: Command) => BrowserParentOpts,
) {
browser
.command("highlight")
.description("Highlight an element by ref")
.argument("<ref>", "Ref id from snapshot")
.option("--target-id <id>", "CDP target id (or unique prefix)")
.action(async (ref: string, opts, cmd) => {
const parent = parentOpts(cmd);
const baseUrl = resolveBrowserControlUrl(parent?.url);
const profile = parent?.browserProfile;
try {
const result = await browserHighlight(baseUrl, {
ref: ref.trim(),
targetId: opts.targetId?.trim() || undefined,
profile,
});
if (parent?.json) {
defaultRuntime.log(JSON.stringify(result, null, 2));
return;
}
defaultRuntime.log(`highlighted ${ref.trim()}`);
} catch (err) {
defaultRuntime.error(danger(String(err)));
defaultRuntime.exit(1);
}
});
browser
.command("errors")
.description("Get recent page errors")
.option("--clear", "Clear stored errors after reading", false)
.option("--target-id <id>", "CDP target id (or unique prefix)")
.action(async (opts, cmd) => {
const parent = parentOpts(cmd);
const baseUrl = resolveBrowserControlUrl(parent?.url);
const profile = parent?.browserProfile;
try {
const result = await browserPageErrors(baseUrl, {
targetId: opts.targetId?.trim() || undefined,
clear: Boolean(opts.clear),
profile,
});
if (parent?.json) {
defaultRuntime.log(JSON.stringify(result, null, 2));
return;
}
if (!result.errors.length) {
defaultRuntime.log("No page errors.");
return;
}
defaultRuntime.log(
result.errors
.map(
(e) =>
`${e.timestamp} ${e.name ? `${e.name}: ` : ""}${e.message}`,
)
.join("\n"),
);
} catch (err) {
defaultRuntime.error(danger(String(err)));
defaultRuntime.exit(1);
}
});
browser
.command("requests")
.description("Get recent network requests (best-effort)")
.option("--filter <text>", "Only show URLs that contain this substring")
.option("--clear", "Clear stored requests after reading", false)
.option("--target-id <id>", "CDP target id (or unique prefix)")
.action(async (opts, cmd) => {
const parent = parentOpts(cmd);
const baseUrl = resolveBrowserControlUrl(parent?.url);
const profile = parent?.browserProfile;
try {
const result = await browserRequests(baseUrl, {
targetId: opts.targetId?.trim() || undefined,
filter: opts.filter?.trim() || undefined,
clear: Boolean(opts.clear),
profile,
});
if (parent?.json) {
defaultRuntime.log(JSON.stringify(result, null, 2));
return;
}
if (!result.requests.length) {
defaultRuntime.log("No requests recorded.");
return;
}
defaultRuntime.log(
result.requests
.map((r) => {
const status = typeof r.status === "number" ? ` ${r.status}` : "";
const ok = r.ok === true ? " ok" : r.ok === false ? " fail" : "";
const fail = r.failureText ? ` (${r.failureText})` : "";
return `${r.timestamp} ${r.method}${status}${ok} ${r.url}${fail}`;
})
.join("\n"),
);
} catch (err) {
defaultRuntime.error(danger(String(err)));
defaultRuntime.exit(1);
}
});
const trace = browser
.command("trace")
.description("Record a Playwright trace");
trace
.command("start")
.description("Start trace recording")
.option("--target-id <id>", "CDP target id (or unique prefix)")
.option("--no-screenshots", "Disable screenshots")
.option("--no-snapshots", "Disable snapshots")
.option("--sources", "Include sources (bigger traces)", false)
.action(async (opts, cmd) => {
const parent = parentOpts(cmd);
const baseUrl = resolveBrowserControlUrl(parent?.url);
const profile = parent?.browserProfile;
try {
const result = await browserTraceStart(baseUrl, {
targetId: opts.targetId?.trim() || undefined,
screenshots: Boolean(opts.screenshots),
snapshots: Boolean(opts.snapshots),
sources: Boolean(opts.sources),
profile,
});
if (parent?.json) {
defaultRuntime.log(JSON.stringify(result, null, 2));
return;
}
defaultRuntime.log("trace started");
} catch (err) {
defaultRuntime.error(danger(String(err)));
defaultRuntime.exit(1);
}
});
trace
.command("stop")
.description("Stop trace recording and write a .zip")
.option("--out <path>", "Output path for the trace zip")
.option("--target-id <id>", "CDP target id (or unique prefix)")
.action(async (opts, cmd) => {
const parent = parentOpts(cmd);
const baseUrl = resolveBrowserControlUrl(parent?.url);
const profile = parent?.browserProfile;
try {
const result = await browserTraceStop(baseUrl, {
targetId: opts.targetId?.trim() || undefined,
path: opts.out?.trim() || undefined,
profile,
});
if (parent?.json) {
defaultRuntime.log(JSON.stringify(result, null, 2));
return;
}
defaultRuntime.log(`TRACE:${result.path}`);
} catch (err) {
defaultRuntime.error(danger(String(err)));
defaultRuntime.exit(1);
}
});
}