feat(browser): add downloads + response bodies

This commit is contained in:
Peter Steinberger
2026-01-12 19:40:52 +00:00
parent 3dbfe65eea
commit d4f7dc067e
8 changed files with 560 additions and 2 deletions

View File

@@ -4,7 +4,9 @@ import {
browserAct,
browserArmDialog,
browserArmFileChooser,
browserDownload,
browserNavigate,
browserWaitForDownload,
} from "../browser/client-actions.js";
import type { BrowserFormField } from "../browser/client-actions-core.js";
import { danger } from "../globals.js";
@@ -374,6 +376,76 @@ export function registerBrowserActionInputCommands(
}
});
browser
.command("waitfordownload")
.description("Wait for the next download (and save it)")
.argument("[path]", "Save path (default: /tmp/clawdbot/downloads/...)")
.option("--target-id <id>", "CDP target id (or unique prefix)")
.option(
"--timeout-ms <ms>",
"How long to wait for the next download (default: 120000)",
(v: string) => Number(v),
)
.action(async (outPath: string | undefined, opts, cmd) => {
const parent = parentOpts(cmd);
const baseUrl = resolveBrowserControlUrl(parent?.url);
const profile = parent?.browserProfile;
try {
const result = await browserWaitForDownload(baseUrl, {
path: outPath?.trim() || undefined,
targetId: opts.targetId?.trim() || undefined,
timeoutMs: Number.isFinite(opts.timeoutMs)
? opts.timeoutMs
: undefined,
profile,
});
if (parent?.json) {
defaultRuntime.log(JSON.stringify(result, null, 2));
return;
}
defaultRuntime.log(`downloaded: ${result.download.path}`);
} catch (err) {
defaultRuntime.error(danger(String(err)));
defaultRuntime.exit(1);
}
});
browser
.command("download")
.description("Click a ref and save the resulting download")
.argument("<ref>", "Ref id from snapshot to click")
.argument("<path>", "Save path")
.option("--target-id <id>", "CDP target id (or unique prefix)")
.option(
"--timeout-ms <ms>",
"How long to wait for the download to start (default: 120000)",
(v: string) => Number(v),
)
.action(async (ref: string, outPath: string, opts, cmd) => {
const parent = parentOpts(cmd);
const baseUrl = resolveBrowserControlUrl(parent?.url);
const profile = parent?.browserProfile;
try {
const result = await browserDownload(baseUrl, {
ref,
path: outPath,
targetId: opts.targetId?.trim() || undefined,
timeoutMs: Number.isFinite(opts.timeoutMs)
? opts.timeoutMs
: undefined,
profile,
});
if (parent?.json) {
defaultRuntime.log(JSON.stringify(result, null, 2));
return;
}
defaultRuntime.log(`downloaded: ${result.download.path}`);
} catch (err) {
defaultRuntime.error(danger(String(err)));
defaultRuntime.exit(1);
}
});
browser
.command("fill")
.description("Fill a form with JSON field descriptors")

View File

@@ -3,6 +3,7 @@ import { resolveBrowserControlUrl } from "../browser/client.js";
import {
browserConsoleMessages,
browserPdfSave,
browserResponseBody,
} from "../browser/client-actions.js";
import { danger } from "../globals.js";
import { defaultRuntime } from "../runtime.js";
@@ -61,4 +62,44 @@ export function registerBrowserActionObserveCommands(
defaultRuntime.exit(1);
}
});
browser
.command("responsebody")
.description("Wait for a network response and return its body")
.argument("<url>", "URL (exact, substring, or glob like **/api)")
.option("--target-id <id>", "CDP target id (or unique prefix)")
.option(
"--timeout-ms <ms>",
"How long to wait for the response (default: 20000)",
(v: string) => Number(v),
)
.option(
"--max-chars <n>",
"Max body chars to return (default: 200000)",
(v: string) => Number(v),
)
.action(async (url: string, opts, cmd) => {
const parent = parentOpts(cmd);
const baseUrl = resolveBrowserControlUrl(parent?.url);
const profile = parent?.browserProfile;
try {
const result = await browserResponseBody(baseUrl, {
url,
targetId: opts.targetId?.trim() || undefined,
timeoutMs: Number.isFinite(opts.timeoutMs)
? opts.timeoutMs
: undefined,
maxChars: Number.isFinite(opts.maxChars) ? opts.maxChars : undefined,
profile,
});
if (parent?.json) {
defaultRuntime.log(JSON.stringify(result, null, 2));
return;
}
defaultRuntime.log(result.response.body);
} catch (err) {
defaultRuntime.error(danger(String(err)));
defaultRuntime.exit(1);
}
});
}