mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
refactor(browser): consolidate browser CLI and normalization helpers (#119432)
This commit is contained in:
committed by
GitHub
parent
bf1bdb429e
commit
767dc7019d
@@ -16,6 +16,7 @@ import {
|
||||
type BrowserProxyUploadV1,
|
||||
} from "./browser-proxy-envelope.js";
|
||||
import { DEFAULT_UPLOAD_DIR, resolveExistingUploadPaths } from "./browser/paths.js";
|
||||
import { asRecord } from "./record-shared.js";
|
||||
|
||||
const logger = createSubsystemLogger("browser");
|
||||
const BROWSER_PROXY_UPLOAD_ROOT_NAME = ".proxy-uploads";
|
||||
@@ -76,12 +77,6 @@ export function isBrowserProxyUploadRequest(params: {
|
||||
return Boolean(body && Array.isArray(body.paths) && body.paths.length > 0);
|
||||
}
|
||||
|
||||
function asRecord(value: unknown): Record<string, unknown> | null {
|
||||
return value && typeof value === "object" && !Array.isArray(value)
|
||||
? (value as Record<string, unknown>)
|
||||
: null;
|
||||
}
|
||||
|
||||
function readUploadPaths(body: Record<string, unknown>): string[] | null {
|
||||
if (!Array.isArray(body.paths) || body.paths.length === 0) {
|
||||
return null;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* exact RunningChrome instance that owns the process.
|
||||
*/
|
||||
import type { SsrFPolicy } from "../infra/net/ssrf.js";
|
||||
import { asRecord, isRecord } from "../record-shared.js";
|
||||
import { redactCdpErrorText, withCdpSocket } from "./cdp.helpers.js";
|
||||
import { getChromeWebSocketUrl, type RunningChrome } from "./chrome.js";
|
||||
import type {
|
||||
@@ -15,8 +16,6 @@ import type {
|
||||
BrowserVideoEncodeCapability,
|
||||
} from "./client.types.js";
|
||||
|
||||
type UnknownRecord = Record<string, unknown>;
|
||||
|
||||
type ChromeGraphicsProbeOptions = {
|
||||
httpTimeoutMs?: number;
|
||||
handshakeTimeoutMs?: number;
|
||||
@@ -24,12 +23,6 @@ type ChromeGraphicsProbeOptions = {
|
||||
ssrfPolicy?: SsrFPolicy;
|
||||
};
|
||||
|
||||
function asRecord(value: unknown): UnknownRecord | null {
|
||||
return value !== null && typeof value === "object" && !Array.isArray(value)
|
||||
? (value as UnknownRecord)
|
||||
: null;
|
||||
}
|
||||
|
||||
function readString(value: unknown): string {
|
||||
return typeof value === "string" ? value.trim() : "";
|
||||
}
|
||||
@@ -63,65 +56,36 @@ function readSize(value: unknown): { width: number; height: number } {
|
||||
};
|
||||
}
|
||||
|
||||
function readRecordArray(value: unknown): Record<string, unknown>[] {
|
||||
return Array.isArray(value) ? value.filter(isRecord) : [];
|
||||
}
|
||||
|
||||
function readDevices(value: unknown): BrowserGraphicsDevice[] {
|
||||
if (!Array.isArray(value)) {
|
||||
return [];
|
||||
}
|
||||
return value.flatMap((item) => {
|
||||
const device = asRecord(item);
|
||||
if (!device) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
{
|
||||
vendorId: readNumber(device.vendorId),
|
||||
deviceId: readNumber(device.deviceId),
|
||||
vendor: readString(device.vendorString),
|
||||
device: readString(device.deviceString),
|
||||
driverVendor: readString(device.driverVendor),
|
||||
driverVersion: readString(device.driverVersion),
|
||||
},
|
||||
];
|
||||
});
|
||||
return readRecordArray(value).map((device) => ({
|
||||
vendorId: readNumber(device.vendorId),
|
||||
deviceId: readNumber(device.deviceId),
|
||||
vendor: readString(device.vendorString),
|
||||
device: readString(device.deviceString),
|
||||
driverVendor: readString(device.driverVendor),
|
||||
driverVersion: readString(device.driverVersion),
|
||||
}));
|
||||
}
|
||||
|
||||
function readVideoDecoding(value: unknown): BrowserVideoDecodeCapability[] {
|
||||
if (!Array.isArray(value)) {
|
||||
return [];
|
||||
}
|
||||
return value.flatMap((item) => {
|
||||
const capability = asRecord(item);
|
||||
if (!capability) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
{
|
||||
profile: readString(capability.profile),
|
||||
minResolution: readSize(capability.minResolution),
|
||||
maxResolution: readSize(capability.maxResolution),
|
||||
},
|
||||
];
|
||||
});
|
||||
return readRecordArray(value).map((capability) => ({
|
||||
profile: readString(capability.profile),
|
||||
minResolution: readSize(capability.minResolution),
|
||||
maxResolution: readSize(capability.maxResolution),
|
||||
}));
|
||||
}
|
||||
|
||||
function readVideoEncoding(value: unknown): BrowserVideoEncodeCapability[] {
|
||||
if (!Array.isArray(value)) {
|
||||
return [];
|
||||
}
|
||||
return value.flatMap((item) => {
|
||||
const capability = asRecord(item);
|
||||
if (!capability) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
{
|
||||
profile: readString(capability.profile),
|
||||
maxResolution: readSize(capability.maxResolution),
|
||||
maxFramerateNumerator: readNumber(capability.maxFramerateNumerator),
|
||||
maxFramerateDenominator: readNumber(capability.maxFramerateDenominator),
|
||||
},
|
||||
];
|
||||
});
|
||||
return readRecordArray(value).map((capability) => ({
|
||||
profile: readString(capability.profile),
|
||||
maxResolution: readSize(capability.maxResolution),
|
||||
maxFramerateNumerator: readNumber(capability.maxFramerateNumerator),
|
||||
maxFramerateDenominator: readNumber(capability.maxFramerateDenominator),
|
||||
}));
|
||||
}
|
||||
|
||||
function firstAttribute(
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { loadJsonFile, saveJsonFile } from "openclaw/plugin-sdk/json-store";
|
||||
import { asRecord } from "../record-shared.js";
|
||||
import {
|
||||
DEFAULT_OPENCLAW_BROWSER_COLOR,
|
||||
DEFAULT_OPENCLAW_BROWSER_PROFILE_NAME,
|
||||
@@ -19,22 +20,13 @@ function decoratedMarkerPath(userDataDir: string) {
|
||||
}
|
||||
|
||||
function safeReadJson(filePath: string): Record<string, unknown> | null {
|
||||
const parsed = loadJsonFile(filePath);
|
||||
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
|
||||
? (parsed as Record<string, unknown>)
|
||||
: null;
|
||||
return asRecord(loadJsonFile(filePath));
|
||||
}
|
||||
|
||||
function safeWriteJson(filePath: string, data: Record<string, unknown>) {
|
||||
saveJsonFile(filePath, data);
|
||||
}
|
||||
|
||||
function asRecord(value: unknown): Record<string, unknown> | null {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value)
|
||||
? (value as Record<string, unknown>)
|
||||
: null;
|
||||
}
|
||||
|
||||
function readNestedRecord(root: unknown, key: string): Record<string, unknown> | null {
|
||||
return asRecord(asRecord(root)?.[key]);
|
||||
}
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
*/
|
||||
import type { Command } from "commander";
|
||||
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { ACT_MAX_VIEWPORT_DIMENSION } from "../../browser/act-policy.js";
|
||||
import { runBrowserResizeWithOutput } from "../browser-cli-resize.js";
|
||||
import {
|
||||
parseBrowserViewportDimension,
|
||||
runBrowserResizeWithOutput,
|
||||
} from "../browser-cli-resize.js";
|
||||
import {
|
||||
BROWSER_TAB_REFERENCE_HELP,
|
||||
callBrowserRequest,
|
||||
parseBrowserPositiveIntegerValue,
|
||||
type BrowserParentOpts,
|
||||
} from "../browser-cli-shared.js";
|
||||
import { danger, defaultRuntime } from "../core-api.js";
|
||||
@@ -19,21 +20,6 @@ export function registerBrowserNavigationCommands(
|
||||
browser: Command,
|
||||
parentOpts: (cmd: Command) => BrowserParentOpts,
|
||||
) {
|
||||
const parsePositiveInteger = (value: unknown, label: string): number | undefined => {
|
||||
const parsed = parseBrowserPositiveIntegerValue(value);
|
||||
if (parsed === undefined) {
|
||||
defaultRuntime.error(danger(`Invalid ${label}: must be a positive integer`));
|
||||
defaultRuntime.exit(1);
|
||||
return undefined;
|
||||
}
|
||||
if (parsed > ACT_MAX_VIEWPORT_DIMENSION) {
|
||||
defaultRuntime.error(danger(`Invalid ${label}: maximum is ${ACT_MAX_VIEWPORT_DIMENSION}`));
|
||||
defaultRuntime.exit(1);
|
||||
return undefined;
|
||||
}
|
||||
return parsed;
|
||||
};
|
||||
|
||||
browser
|
||||
.command("navigate")
|
||||
.description("Navigate the current tab to a URL")
|
||||
@@ -73,8 +59,8 @@ export function registerBrowserNavigationCommands(
|
||||
.argument("<height>", "Viewport height")
|
||||
.option("--target-id <id>", BROWSER_TAB_REFERENCE_HELP)
|
||||
.action(async (width: string, height: string, opts, cmd) => {
|
||||
const normalizedWidth = parsePositiveInteger(width, "width");
|
||||
const normalizedHeight = parsePositiveInteger(height, "height");
|
||||
const normalizedWidth = parseBrowserViewportDimension(width, "width");
|
||||
const normalizedHeight = parseBrowserViewportDimension(height, "height");
|
||||
if (normalizedWidth === undefined || normalizedHeight === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
resolveBrowserExtractTimeoutMs,
|
||||
validateBrowserExtractSchema,
|
||||
} from "../browser-extract.js";
|
||||
import { runCommandWithRuntime } from "../core-api.js";
|
||||
import {
|
||||
completeWithPreparedSimpleCompletionModel,
|
||||
extractAssistantText,
|
||||
@@ -23,9 +22,11 @@ import {
|
||||
BROWSER_TAB_REFERENCE_HELP,
|
||||
callBrowserRequest,
|
||||
parseBrowserPositiveIntegerOption,
|
||||
printBrowserJsonResult,
|
||||
runBrowserCliCommand as runBrowserObserve,
|
||||
type BrowserParentOpts,
|
||||
} from "./browser-cli-shared.js";
|
||||
import { danger, defaultRuntime, getRuntimeConfig, shortenHomePath } from "./core-api.js";
|
||||
import { defaultRuntime, getRuntimeConfig, shortenHomePath } from "./core-api.js";
|
||||
|
||||
const browserCliExtractDeps = {
|
||||
completeWithPreparedSimpleCompletionModel,
|
||||
@@ -58,13 +59,6 @@ function parseSchemaOption(value: string | undefined): JsonSchemaObject | undefi
|
||||
return parsed as JsonSchemaObject;
|
||||
}
|
||||
|
||||
function runBrowserObserve(action: () => Promise<void>) {
|
||||
return runCommandWithRuntime(defaultRuntime, action, (err) => {
|
||||
defaultRuntime.error(danger(String(err)));
|
||||
defaultRuntime.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
/** Registers Browser commands that observe current page state without direct input. */
|
||||
export function registerBrowserActionObserveCommands(
|
||||
browser: Command,
|
||||
@@ -140,8 +134,7 @@ export function registerBrowserActionObserveCommands(
|
||||
const text = result.content.find((block) => block.type === "text")?.text;
|
||||
throw new Error(text || "Browser extract failed");
|
||||
}
|
||||
if (parent?.json) {
|
||||
defaultRuntime.writeJson(result);
|
||||
if (printBrowserJsonResult(parent, result)) {
|
||||
return;
|
||||
}
|
||||
const text = result.content.find((block) => block.type === "text")?.text;
|
||||
@@ -173,8 +166,7 @@ export function registerBrowserActionObserveCommands(
|
||||
},
|
||||
{ timeoutMs: 20000 },
|
||||
);
|
||||
if (parent?.json) {
|
||||
defaultRuntime.writeJson(result);
|
||||
if (printBrowserJsonResult(parent, result)) {
|
||||
return;
|
||||
}
|
||||
defaultRuntime.writeJson(result.messages);
|
||||
@@ -199,8 +191,7 @@ export function registerBrowserActionObserveCommands(
|
||||
},
|
||||
{ timeoutMs: 20000 },
|
||||
);
|
||||
if (parent?.json) {
|
||||
defaultRuntime.writeJson(result);
|
||||
if (printBrowserJsonResult(parent, result)) {
|
||||
return;
|
||||
}
|
||||
defaultRuntime.log(`PDF: ${shortenHomePath(result.path)}`);
|
||||
@@ -241,8 +232,7 @@ export function registerBrowserActionObserveCommands(
|
||||
},
|
||||
{ timeoutMs: timeoutMs ?? 20000 },
|
||||
);
|
||||
if (parent?.json) {
|
||||
defaultRuntime.writeJson(result);
|
||||
if (printBrowserJsonResult(parent, result)) {
|
||||
return;
|
||||
}
|
||||
defaultRuntime.log(result.response.body);
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
*/
|
||||
import type { Command } from "commander";
|
||||
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { runCommandWithRuntime } from "../core-api.js";
|
||||
import {
|
||||
BROWSER_TAB_REFERENCE_HELP,
|
||||
callBrowserRequest,
|
||||
printBrowserJsonResult as printJsonResult,
|
||||
resolveBrowserProfileQuery as resolveProfileQuery,
|
||||
runBrowserCliCommand,
|
||||
type BrowserParentOpts,
|
||||
} from "./browser-cli-shared.js";
|
||||
import { danger, defaultRuntime, shortenHomePath } from "./core-api.js";
|
||||
import { defaultRuntime, shortenHomePath } from "./core-api.js";
|
||||
|
||||
const BROWSER_DEBUG_TIMEOUT_MS = 20000;
|
||||
|
||||
@@ -20,20 +22,13 @@ type DebugContext = {
|
||||
profile?: string;
|
||||
};
|
||||
|
||||
function runBrowserDebug(action: () => Promise<void>) {
|
||||
return runCommandWithRuntime(defaultRuntime, action, (err) => {
|
||||
defaultRuntime.error(danger(String(err)));
|
||||
defaultRuntime.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
async function withDebugContext(
|
||||
cmd: Command,
|
||||
parentOpts: (cmd: Command) => BrowserParentOpts,
|
||||
action: (context: DebugContext) => Promise<void>,
|
||||
) {
|
||||
const parent = parentOpts(cmd);
|
||||
await runBrowserDebug(() =>
|
||||
await runBrowserCliCommand(() =>
|
||||
action({
|
||||
parent,
|
||||
profile: parent.browserProfile,
|
||||
@@ -41,14 +36,6 @@ async function withDebugContext(
|
||||
);
|
||||
}
|
||||
|
||||
function printJsonResult(parent: BrowserParentOpts, result: unknown): boolean {
|
||||
if (!parent.json) {
|
||||
return false;
|
||||
}
|
||||
defaultRuntime.writeJson(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
async function callDebugRequest<T>(
|
||||
parent: BrowserParentOpts,
|
||||
params: BrowserRequestParams,
|
||||
@@ -56,10 +43,6 @@ async function callDebugRequest<T>(
|
||||
return callBrowserRequest<T>(parent, params, { timeoutMs: BROWSER_DEBUG_TIMEOUT_MS });
|
||||
}
|
||||
|
||||
function resolveProfileQuery(profile?: string) {
|
||||
return profile ? { profile } : undefined;
|
||||
}
|
||||
|
||||
function resolveDebugQuery(params: {
|
||||
targetId?: unknown;
|
||||
clear?: unknown;
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
*/
|
||||
import type { Command } from "commander";
|
||||
import { formatBrowserGraphicsSummary } from "../browser/chrome.graphics.js";
|
||||
import { runCommandWithRuntime } from "../core-api.js";
|
||||
import {
|
||||
BROWSER_TAB_REFERENCE_HELP,
|
||||
callBrowserRequest,
|
||||
parseBrowserPositiveIntegerValue,
|
||||
printBrowserJsonResult as printJsonResult,
|
||||
resolveBrowserProfileQuery as resolveProfileQuery,
|
||||
runBrowserCliCommand as runBrowserCommand,
|
||||
type BrowserParentOpts,
|
||||
} from "./browser-cli-shared.js";
|
||||
import {
|
||||
@@ -37,28 +39,6 @@ type BrowserDoctorCheck = {
|
||||
warning?: boolean;
|
||||
};
|
||||
|
||||
function resolveProfileQuery(
|
||||
profile?: string,
|
||||
extra?: Record<string, string | number | boolean | undefined>,
|
||||
) {
|
||||
const query: Record<string, string | number | boolean | undefined> = {};
|
||||
if (profile) {
|
||||
query.profile = profile;
|
||||
}
|
||||
if (extra) {
|
||||
Object.assign(query, extra);
|
||||
}
|
||||
return Object.keys(query).length > 0 ? query : undefined;
|
||||
}
|
||||
|
||||
function printJsonResult(parent: BrowserParentOpts, payload: unknown): boolean {
|
||||
if (!parent?.json) {
|
||||
return false;
|
||||
}
|
||||
defaultRuntime.writeJson(payload);
|
||||
return true;
|
||||
}
|
||||
|
||||
function sanitizeTableCell(value: string): string {
|
||||
// Strip C0/C1 control characters (Unicode Cc) so profile names cannot inject
|
||||
// terminal escapes into the printed table.
|
||||
@@ -124,13 +104,6 @@ async function runBrowserToggle(
|
||||
defaultRuntime.log(info(`🦞 browser [${name}] running: ${status.running}${headlessLabel}`));
|
||||
}
|
||||
|
||||
function runBrowserCommand(action: () => Promise<void>) {
|
||||
return runCommandWithRuntime(defaultRuntime, action, (err) => {
|
||||
defaultRuntime.error(danger(String(err)));
|
||||
defaultRuntime.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
function parseTabIndex(value: string): number {
|
||||
return parseBrowserPositiveIntegerValue(value) ?? Number.NaN;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,28 @@
|
||||
* Shared Browser CLI resize runner used by resize and set viewport commands.
|
||||
*/
|
||||
import { ACT_MAX_VIEWPORT_DIMENSION } from "../browser/act-policy.js";
|
||||
import { callBrowserResize, type BrowserParentOpts } from "./browser-cli-shared.js";
|
||||
import {
|
||||
callBrowserResize,
|
||||
parseBrowserPositiveIntegerValue,
|
||||
type BrowserParentOpts,
|
||||
} from "./browser-cli-shared.js";
|
||||
import { danger, defaultRuntime } from "./core-api.js";
|
||||
|
||||
/** Parses a bounded viewport dimension for both Browser resize commands. */
|
||||
export function parseBrowserViewportDimension(value: unknown, label: string): number | undefined {
|
||||
const parsed = parseBrowserPositiveIntegerValue(value);
|
||||
if (parsed !== undefined && parsed <= ACT_MAX_VIEWPORT_DIMENSION) {
|
||||
return parsed;
|
||||
}
|
||||
const reason =
|
||||
parsed === undefined
|
||||
? "must be a positive integer"
|
||||
: `maximum is ${ACT_MAX_VIEWPORT_DIMENSION}`;
|
||||
defaultRuntime.error(danger(`Invalid ${label}: ${reason}`));
|
||||
defaultRuntime.exit(1);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** Validates viewport dimensions, sends resize action, and writes CLI output. */
|
||||
export async function runBrowserResizeWithOutput(params: {
|
||||
parent: BrowserParentOpts;
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
BROWSER_REQUEST_GATEWAY_SCOPES,
|
||||
} from "../browser-gateway-contract.js";
|
||||
import { normalizeBrowserTimerDelayMs } from "../browser/timer-delay.js";
|
||||
import { danger, defaultRuntime, runCommandWithRuntime } from "../core-api.js";
|
||||
import { callGatewayFromCli, type GatewayRpcOpts } from "./core-api.js";
|
||||
|
||||
/** Parent Browser CLI options inherited by subcommands. */
|
||||
@@ -30,6 +31,32 @@ type BrowserRequestParams = {
|
||||
body?: unknown;
|
||||
};
|
||||
|
||||
/** Runs a Browser CLI command with the standard runtime error handling. */
|
||||
export function runBrowserCliCommand(action: () => Promise<void>) {
|
||||
return runCommandWithRuntime(defaultRuntime, action, (error) => {
|
||||
defaultRuntime.error(danger(String(error)));
|
||||
defaultRuntime.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
/** Writes a Browser command result when structured output was requested. */
|
||||
export function printBrowserJsonResult(parent: BrowserParentOpts, payload: unknown): boolean {
|
||||
if (!parent?.json) {
|
||||
return false;
|
||||
}
|
||||
defaultRuntime.writeJson(payload);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Combines the selected Browser profile with optional request query fields. */
|
||||
export function resolveBrowserProfileQuery(
|
||||
profile?: string,
|
||||
extra?: BrowserRequestParams["query"],
|
||||
): BrowserRequestParams["query"] {
|
||||
const query = { ...(profile ? { profile } : {}), ...extra };
|
||||
return Object.keys(query).length > 0 ? query : undefined;
|
||||
}
|
||||
|
||||
function normalizeQuery(query: BrowserRequestParams["query"]): Record<string, string> | undefined {
|
||||
if (!query) {
|
||||
return undefined;
|
||||
@@ -78,17 +105,13 @@ export async function callBrowserRequest<T>(
|
||||
params: BrowserRequestParams,
|
||||
extra?: { timeoutMs?: number; progress?: boolean },
|
||||
): Promise<T> {
|
||||
const resolvedTimeoutMs =
|
||||
const resolvedTimeout =
|
||||
typeof extra?.timeoutMs === "number" && Number.isFinite(extra.timeoutMs)
|
||||
? normalizeBrowserTimerDelayMs(extra.timeoutMs)
|
||||
: typeof opts.timeout === "string"
|
||||
? normalizeBrowserTimerDelayMs(parseBrowserPositiveIntegerOption(opts.timeout, "--timeout"))
|
||||
: undefined;
|
||||
const resolvedTimeout =
|
||||
typeof resolvedTimeoutMs === "number" && Number.isFinite(resolvedTimeoutMs)
|
||||
? resolvedTimeoutMs
|
||||
: undefined;
|
||||
const timeout = typeof resolvedTimeout === "number" ? String(resolvedTimeout) : opts.timeout;
|
||||
const timeout = resolvedTimeout === undefined ? opts.timeout : String(resolvedTimeout);
|
||||
const payload = await callGatewayFromCli(
|
||||
BROWSER_REQUEST_GATEWAY_METHOD,
|
||||
{ ...opts, timeout },
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
* HTTP context settings.
|
||||
*/
|
||||
import type { Command } from "commander";
|
||||
import { parseStrictFiniteNumber } from "openclaw/plugin-sdk/number-runtime";
|
||||
import {
|
||||
normalizeOptionalLowercaseString,
|
||||
normalizeOptionalString,
|
||||
} from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { ACT_MAX_VIEWPORT_DIMENSION } from "../browser/act-policy.js";
|
||||
import { runCommandWithRuntime } from "../core-api.js";
|
||||
import { runBrowserResizeWithOutput } from "./browser-cli-resize.js";
|
||||
import { parseBrowserViewportDimension, runBrowserResizeWithOutput } from "./browser-cli-resize.js";
|
||||
import {
|
||||
BROWSER_TAB_REFERENCE_HELP,
|
||||
callBrowserRequest,
|
||||
parseBrowserPositiveIntegerValue,
|
||||
printBrowserJsonResult,
|
||||
runBrowserCliCommand as runBrowserCommand,
|
||||
type BrowserParentOpts,
|
||||
} from "./browser-cli-shared.js";
|
||||
import { registerBrowserCookiesAndStorageCommands } from "./browser-cli-state.cookies-storage.js";
|
||||
@@ -24,30 +24,12 @@ function parseOnOff(raw: string): boolean | null {
|
||||
return parsed === undefined ? null : parsed;
|
||||
}
|
||||
|
||||
function parsePositiveInteger(value: unknown, label: string): number | undefined {
|
||||
const parsed = parseBrowserPositiveIntegerValue(value);
|
||||
if (parsed === undefined) {
|
||||
defaultRuntime.error(danger(`Invalid ${label}: must be a positive integer`));
|
||||
defaultRuntime.exit(1);
|
||||
return undefined;
|
||||
}
|
||||
if (parsed > ACT_MAX_VIEWPORT_DIMENSION) {
|
||||
defaultRuntime.error(danger(`Invalid ${label}: maximum is ${ACT_MAX_VIEWPORT_DIMENSION}`));
|
||||
defaultRuntime.exit(1);
|
||||
return undefined;
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function parseFiniteNumberOption(value: string | undefined, label: string): number | undefined {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const raw = value.trim();
|
||||
const parsed = /^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))(?:e[+-]?\d+)?$/i.test(raw)
|
||||
? Number(raw)
|
||||
: Number.NaN;
|
||||
if (!Number.isFinite(parsed)) {
|
||||
const parsed = parseStrictFiniteNumber(value);
|
||||
if (parsed === undefined) {
|
||||
defaultRuntime.error(danger(`Invalid ${label}: must be a finite number`));
|
||||
defaultRuntime.exit(1);
|
||||
return undefined;
|
||||
@@ -55,13 +37,6 @@ function parseFiniteNumberOption(value: string | undefined, label: string): numb
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function runBrowserCommand(action: () => Promise<void>) {
|
||||
return runCommandWithRuntime(defaultRuntime, action, (err) => {
|
||||
defaultRuntime.error(danger(String(err)));
|
||||
defaultRuntime.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
async function runBrowserSetRequest(params: {
|
||||
parent: BrowserParentOpts;
|
||||
path: string;
|
||||
@@ -80,8 +55,7 @@ async function runBrowserSetRequest(params: {
|
||||
},
|
||||
{ timeoutMs: 20000 },
|
||||
);
|
||||
if (params.parent?.json) {
|
||||
defaultRuntime.writeJson(result);
|
||||
if (printBrowserJsonResult(params.parent, result)) {
|
||||
return;
|
||||
}
|
||||
defaultRuntime.log(params.successMessage);
|
||||
@@ -104,8 +78,8 @@ export function registerBrowserStateCommands(
|
||||
.argument("<height>", "Viewport height")
|
||||
.option("--target-id <id>", BROWSER_TAB_REFERENCE_HELP)
|
||||
.action(async (widthRaw: string, heightRaw: string, opts, cmd) => {
|
||||
const width = parsePositiveInteger(widthRaw, "width");
|
||||
const height = parsePositiveInteger(heightRaw, "height");
|
||||
const width = parseBrowserViewportDimension(widthRaw, "width");
|
||||
const height = parseBrowserViewportDimension(heightRaw, "height");
|
||||
if (width === undefined || height === undefined) {
|
||||
return;
|
||||
}
|
||||
@@ -186,8 +160,7 @@ export function registerBrowserStateCommands(
|
||||
},
|
||||
{ timeoutMs: 20000 },
|
||||
);
|
||||
if (parent?.json) {
|
||||
defaultRuntime.writeJson(result);
|
||||
if (printBrowserJsonResult(parent, result)) {
|
||||
return;
|
||||
}
|
||||
defaultRuntime.log("headers set");
|
||||
|
||||
Reference in New Issue
Block a user