refactor(browser): prune browser automation surface
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import type { Command } from "commander";
|
||||
import { resolveBrowserControlUrl } from "../browser/client.js";
|
||||
import {
|
||||
browserBack,
|
||||
browserClick,
|
||||
browserDrag,
|
||||
browserEvaluate,
|
||||
@@ -11,7 +10,6 @@ import {
|
||||
browserNavigate,
|
||||
browserPressKey,
|
||||
browserResize,
|
||||
browserRunCode,
|
||||
browserSelectOption,
|
||||
browserType,
|
||||
browserUpload,
|
||||
@@ -21,31 +19,11 @@ import { danger } from "../globals.js";
|
||||
import { defaultRuntime } from "../runtime.js";
|
||||
import type { BrowserParentOpts } from "./browser-cli-shared.js";
|
||||
|
||||
async function readStdin(): Promise<string> {
|
||||
const chunks: string[] = [];
|
||||
return await new Promise((resolve, reject) => {
|
||||
process.stdin.setEncoding("utf8");
|
||||
process.stdin.on("data", (chunk) => chunks.push(String(chunk)));
|
||||
process.stdin.on("end", () => resolve(chunks.join("")));
|
||||
process.stdin.on("error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
async function readFile(path: string): Promise<string> {
|
||||
const fs = await import("node:fs/promises");
|
||||
return await fs.readFile(path, "utf8");
|
||||
}
|
||||
|
||||
async function readCode(opts: {
|
||||
code?: string;
|
||||
codeFile?: string;
|
||||
codeStdin?: boolean;
|
||||
}): Promise<string> {
|
||||
if (opts.codeFile) return await readFile(opts.codeFile);
|
||||
if (opts.codeStdin) return await readStdin();
|
||||
return opts.code ?? "";
|
||||
}
|
||||
|
||||
async function readFields(opts: {
|
||||
fields?: string;
|
||||
fieldsFile?: string;
|
||||
@@ -87,30 +65,6 @@ export function registerBrowserActionInputCommands(
|
||||
}
|
||||
});
|
||||
|
||||
browser
|
||||
.command("back")
|
||||
.description("Navigate back in history")
|
||||
.option("--target-id <id>", "CDP target id (or unique prefix)")
|
||||
.action(async (opts, cmd) => {
|
||||
const parent = parentOpts(cmd);
|
||||
const baseUrl = resolveBrowserControlUrl(parent?.url);
|
||||
try {
|
||||
const result = await browserBack(baseUrl, {
|
||||
targetId: opts.targetId?.trim() || undefined,
|
||||
});
|
||||
if (parent?.json) {
|
||||
defaultRuntime.log(JSON.stringify(result, null, 2));
|
||||
return;
|
||||
}
|
||||
defaultRuntime.log(
|
||||
`navigated back to ${result.url ?? "previous page"}`,
|
||||
);
|
||||
} catch (err) {
|
||||
defaultRuntime.error(danger(String(err)));
|
||||
defaultRuntime.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
browser
|
||||
.command("resize")
|
||||
.description("Resize the viewport")
|
||||
@@ -311,7 +265,7 @@ export function registerBrowserActionInputCommands(
|
||||
|
||||
browser
|
||||
.command("upload")
|
||||
.description("Upload file(s) when a file chooser is open")
|
||||
.description("Arm file upload for the next file chooser")
|
||||
.argument("<paths...>", "File paths to upload")
|
||||
.option("--target-id <id>", "CDP target id (or unique prefix)")
|
||||
.action(async (paths: string[], opts, cmd) => {
|
||||
@@ -326,7 +280,7 @@ export function registerBrowserActionInputCommands(
|
||||
defaultRuntime.log(JSON.stringify(result, null, 2));
|
||||
return;
|
||||
}
|
||||
defaultRuntime.log(`uploaded ${paths.length} file(s)`);
|
||||
defaultRuntime.log(`upload armed for ${paths.length} file(s)`);
|
||||
} catch (err) {
|
||||
defaultRuntime.error(danger(String(err)));
|
||||
defaultRuntime.exit(1);
|
||||
@@ -364,7 +318,7 @@ export function registerBrowserActionInputCommands(
|
||||
|
||||
browser
|
||||
.command("dialog")
|
||||
.description("Handle a modal dialog (alert/confirm/prompt)")
|
||||
.description("Arm the next modal dialog (alert/confirm/prompt)")
|
||||
.option("--accept", "Accept the dialog", false)
|
||||
.option("--dismiss", "Dismiss the dialog", false)
|
||||
.option("--prompt <text>", "Prompt response text")
|
||||
@@ -388,7 +342,7 @@ export function registerBrowserActionInputCommands(
|
||||
defaultRuntime.log(JSON.stringify(result, null, 2));
|
||||
return;
|
||||
}
|
||||
defaultRuntime.log(`dialog handled: ${result.type}`);
|
||||
defaultRuntime.log("dialog armed");
|
||||
} catch (err) {
|
||||
defaultRuntime.error(danger(String(err)));
|
||||
defaultRuntime.exit(1);
|
||||
@@ -453,40 +407,4 @@ export function registerBrowserActionInputCommands(
|
||||
defaultRuntime.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
browser
|
||||
.command("run")
|
||||
.description("Run a Playwright code function (page => ...) ")
|
||||
.option("--code <code>", "Function source, e.g. (page) => page.title()")
|
||||
.option("--code-file <path>", "Read function source from a file")
|
||||
.option("--code-stdin", "Read function source from stdin", false)
|
||||
.option("--target-id <id>", "CDP target id (or unique prefix)")
|
||||
.action(async (opts, cmd) => {
|
||||
const parent = parentOpts(cmd);
|
||||
const baseUrl = resolveBrowserControlUrl(parent?.url);
|
||||
try {
|
||||
const code = await readCode({
|
||||
code: opts.code,
|
||||
codeFile: opts.codeFile,
|
||||
codeStdin: Boolean(opts.codeStdin),
|
||||
});
|
||||
if (!code.trim()) {
|
||||
defaultRuntime.error(danger("Missing --code (or file/stdin)"));
|
||||
defaultRuntime.exit(1);
|
||||
return;
|
||||
}
|
||||
const result = await browserRunCode(baseUrl, {
|
||||
code,
|
||||
targetId: opts.targetId?.trim() || undefined,
|
||||
});
|
||||
if (parent?.json) {
|
||||
defaultRuntime.log(JSON.stringify(result, null, 2));
|
||||
return;
|
||||
}
|
||||
defaultRuntime.log(JSON.stringify(result.result, null, 2));
|
||||
} catch (err) {
|
||||
defaultRuntime.error(danger(String(err)));
|
||||
defaultRuntime.exit(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,9 +2,6 @@ import type { Command } from "commander";
|
||||
import { resolveBrowserControlUrl } from "../browser/client.js";
|
||||
import {
|
||||
browserConsoleMessages,
|
||||
browserMouseClick,
|
||||
browserMouseDrag,
|
||||
browserMouseMove,
|
||||
browserPdfSave,
|
||||
browserVerifyElementVisible,
|
||||
browserVerifyListVisible,
|
||||
@@ -178,110 +175,4 @@ export function registerBrowserActionObserveCommands(
|
||||
defaultRuntime.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
browser
|
||||
.command("mouse-move")
|
||||
.description("Move mouse to viewport coordinates")
|
||||
.option("--x <n>", "X coordinate", (v: string) => Number(v))
|
||||
.option("--y <n>", "Y coordinate", (v: string) => Number(v))
|
||||
.option("--target-id <id>", "CDP target id (or unique prefix)")
|
||||
.action(async (opts, cmd) => {
|
||||
const parent = parentOpts(cmd);
|
||||
const baseUrl = resolveBrowserControlUrl(parent?.url);
|
||||
if (!Number.isFinite(opts.x) || !Number.isFinite(opts.y)) {
|
||||
defaultRuntime.error(danger("--x and --y are required"));
|
||||
defaultRuntime.exit(1);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const result = await browserMouseMove(baseUrl, {
|
||||
x: opts.x,
|
||||
y: opts.y,
|
||||
targetId: opts.targetId?.trim() || undefined,
|
||||
});
|
||||
if (parent?.json) {
|
||||
defaultRuntime.log(JSON.stringify(result, null, 2));
|
||||
return;
|
||||
}
|
||||
defaultRuntime.log("mouse moved");
|
||||
} catch (err) {
|
||||
defaultRuntime.error(danger(String(err)));
|
||||
defaultRuntime.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
browser
|
||||
.command("mouse-click")
|
||||
.description("Click at viewport coordinates")
|
||||
.option("--x <n>", "X coordinate", (v: string) => Number(v))
|
||||
.option("--y <n>", "Y coordinate", (v: string) => Number(v))
|
||||
.option("--button <left|right|middle>", "Mouse button")
|
||||
.option("--target-id <id>", "CDP target id (or unique prefix)")
|
||||
.action(async (opts, cmd) => {
|
||||
const parent = parentOpts(cmd);
|
||||
const baseUrl = resolveBrowserControlUrl(parent?.url);
|
||||
if (!Number.isFinite(opts.x) || !Number.isFinite(opts.y)) {
|
||||
defaultRuntime.error(danger("--x and --y are required"));
|
||||
defaultRuntime.exit(1);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const result = await browserMouseClick(baseUrl, {
|
||||
x: opts.x,
|
||||
y: opts.y,
|
||||
button: opts.button?.trim() || undefined,
|
||||
targetId: opts.targetId?.trim() || undefined,
|
||||
});
|
||||
if (parent?.json) {
|
||||
defaultRuntime.log(JSON.stringify(result, null, 2));
|
||||
return;
|
||||
}
|
||||
defaultRuntime.log("mouse clicked");
|
||||
} catch (err) {
|
||||
defaultRuntime.error(danger(String(err)));
|
||||
defaultRuntime.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
browser
|
||||
.command("mouse-drag")
|
||||
.description("Drag by viewport coordinates")
|
||||
.option("--start-x <n>", "Start X", (v: string) => Number(v))
|
||||
.option("--start-y <n>", "Start Y", (v: string) => Number(v))
|
||||
.option("--end-x <n>", "End X", (v: string) => Number(v))
|
||||
.option("--end-y <n>", "End Y", (v: string) => Number(v))
|
||||
.option("--target-id <id>", "CDP target id (or unique prefix)")
|
||||
.action(async (opts, cmd) => {
|
||||
const parent = parentOpts(cmd);
|
||||
const baseUrl = resolveBrowserControlUrl(parent?.url);
|
||||
if (
|
||||
!Number.isFinite(opts.startX) ||
|
||||
!Number.isFinite(opts.startY) ||
|
||||
!Number.isFinite(opts.endX) ||
|
||||
!Number.isFinite(opts.endY)
|
||||
) {
|
||||
defaultRuntime.error(
|
||||
danger("--start-x, --start-y, --end-x, --end-y are required"),
|
||||
);
|
||||
defaultRuntime.exit(1);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const result = await browserMouseDrag(baseUrl, {
|
||||
startX: opts.startX,
|
||||
startY: opts.startY,
|
||||
endX: opts.endX,
|
||||
endY: opts.endY,
|
||||
targetId: opts.targetId?.trim() || undefined,
|
||||
});
|
||||
if (parent?.json) {
|
||||
defaultRuntime.log(JSON.stringify(result, null, 2));
|
||||
return;
|
||||
}
|
||||
defaultRuntime.log("mouse dragged");
|
||||
} catch (err) {
|
||||
defaultRuntime.error(danger(String(err)));
|
||||
defaultRuntime.exit(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ export const browserCoreExamples = [
|
||||
"clawdis browser screenshot",
|
||||
"clawdis browser screenshot --full-page",
|
||||
"clawdis browser screenshot --ref 12",
|
||||
'clawdis browser eval "document.title"',
|
||||
'clawdis browser query "a" --limit 5',
|
||||
"clawdis browser dom --format text --max-chars 5000",
|
||||
"clawdis browser snapshot --format aria --limit 200",
|
||||
@@ -18,7 +17,6 @@ export const browserCoreExamples = [
|
||||
|
||||
export const browserActionExamples = [
|
||||
"clawdis browser navigate https://example.com",
|
||||
"clawdis browser back",
|
||||
"clawdis browser resize 1280 720",
|
||||
"clawdis browser click 12 --double",
|
||||
'clawdis browser type 23 "hello" --submit',
|
||||
@@ -31,14 +29,10 @@ export const browserActionExamples = [
|
||||
"clawdis browser dialog --accept",
|
||||
'clawdis browser wait --text "Done"',
|
||||
"clawdis browser evaluate --fn '(el) => el.textContent' --ref 7",
|
||||
"clawdis browser run --code '(page) => page.title()'",
|
||||
"clawdis browser console --level error",
|
||||
"clawdis browser pdf",
|
||||
'clawdis browser verify-element --role button --name "Submit"',
|
||||
'clawdis browser verify-text "Welcome"',
|
||||
"clawdis browser verify-list 3 ItemA ItemB",
|
||||
"clawdis browser verify-value --ref 4 --type textbox --value hello",
|
||||
"clawdis browser mouse-move --x 120 --y 240",
|
||||
"clawdis browser mouse-click --x 120 --y 240",
|
||||
"clawdis browser mouse-drag --start-x 10 --start-y 20 --end-x 200 --end-y 300",
|
||||
];
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { Command } from "commander";
|
||||
|
||||
import {
|
||||
browserDom,
|
||||
browserEval,
|
||||
browserQuery,
|
||||
browserScreenshot,
|
||||
browserSnapshot,
|
||||
@@ -13,31 +12,6 @@ import { danger } from "../globals.js";
|
||||
import { defaultRuntime } from "../runtime.js";
|
||||
import type { BrowserParentOpts } from "./browser-cli-shared.js";
|
||||
|
||||
async function readStdin(): Promise<string> {
|
||||
const chunks: string[] = [];
|
||||
return await new Promise((resolve, reject) => {
|
||||
process.stdin.setEncoding("utf8");
|
||||
process.stdin.on("data", (chunk) => chunks.push(String(chunk)));
|
||||
process.stdin.on("end", () => resolve(chunks.join("")));
|
||||
process.stdin.on("error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
async function readTextFromSource(opts: {
|
||||
js?: string;
|
||||
jsFile?: string;
|
||||
jsStdin?: boolean;
|
||||
}): Promise<string> {
|
||||
if (opts.jsFile) {
|
||||
const fs = await import("node:fs/promises");
|
||||
return await fs.readFile(opts.jsFile, "utf8");
|
||||
}
|
||||
if (opts.jsStdin) {
|
||||
return await readStdin();
|
||||
}
|
||||
return opts.js ?? "";
|
||||
}
|
||||
|
||||
export function registerBrowserInspectCommands(
|
||||
browser: Command,
|
||||
parentOpts: (cmd: Command) => BrowserParentOpts,
|
||||
@@ -80,44 +54,6 @@ export function registerBrowserInspectCommands(
|
||||
}
|
||||
});
|
||||
|
||||
browser
|
||||
.command("eval")
|
||||
.description("Run JavaScript in the active tab")
|
||||
.argument("[js]", "JavaScript expression")
|
||||
.option("--js-file <path>", "Read JavaScript from a file")
|
||||
.option("--js-stdin", "Read JavaScript from stdin", false)
|
||||
.option("--target-id <id>", "CDP target id (or unique prefix)")
|
||||
.option("--await", "Await promise result", false)
|
||||
.action(async (js: string | undefined, opts, cmd) => {
|
||||
const parent = parentOpts(cmd);
|
||||
const baseUrl = resolveBrowserControlUrl(parent?.url);
|
||||
try {
|
||||
const source = await readTextFromSource({
|
||||
js,
|
||||
jsFile: opts.jsFile,
|
||||
jsStdin: Boolean(opts.jsStdin),
|
||||
});
|
||||
if (!source.trim()) {
|
||||
defaultRuntime.error(danger("Missing JavaScript input."));
|
||||
defaultRuntime.exit(1);
|
||||
return;
|
||||
}
|
||||
const result = await browserEval(baseUrl, {
|
||||
js: source,
|
||||
targetId: opts.targetId?.trim() || undefined,
|
||||
awaitPromise: Boolean(opts.await),
|
||||
});
|
||||
if (parent?.json) {
|
||||
defaultRuntime.log(JSON.stringify(result, null, 2));
|
||||
return;
|
||||
}
|
||||
defaultRuntime.log(JSON.stringify(result.result, null, 2));
|
||||
} catch (err) {
|
||||
defaultRuntime.error(danger(String(err)));
|
||||
defaultRuntime.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
browser
|
||||
.command("query")
|
||||
.description("Query selector matches")
|
||||
|
||||
Reference in New Issue
Block a user