import { a as normalizeLowercaseStringOrEmpty, c as normalizeOptionalString } from "./string-coerce-mnp54Vah.js";
import { _ as parseStrictFiniteNumber, b as parseStrictPositiveInteger } from "./number-coercion-CJQ8TR--.js";
import { i as formatErrorMessage } from "./errors-Bi-6nmCG.js";
import { r as theme } from "./theme-vjDs9tao.js";
import { g as shortenHomePath } from "./utils-CCC-BEJH.js";
import { n as defaultRuntime } from "./runtime-B4lgFmsS.js";
import { t as resolveNodeFromNodeList } from "./node-resolve-BawtWMwa.js";
import "./error-runtime-Db72hAfj.js";
import "./number-runtime-DBLVDypr.js";
import "./string-coerce-runtime-CEGJWkQ_.js";
import "./text-utility-runtime-BbqtGUf9.js";
import "./runtime-BWngFATP.js";
import "./gateway-runtime-DIprlEZz.js";
import { n as callGatewayFromCli } from "./gateway-rpc-B-QYs-P3.js";
import { n as runCommandWithRuntime } from "./cli-utils-Cr8nEK78.js";
import "./cli-runtime-BBt1Mari.js";
import { r as parseCanvasSnapshotPayload, t as canvasSnapshotTempPath } from "./cli-helpers-BCIblhfr.js";
import fs from "node:fs/promises";
import { randomUUID } from "node:crypto";
//#region extensions/canvas/src/a2ui-jsonl.ts
/**
* A2UI JSONL helpers for Canvas text rendering and validation.
*/
const A2UI_ACTION_KEYS = [
	"beginRendering",
	"surfaceUpdate",
	"dataModelUpdate",
	"deleteSurface",
	"createSurface"
];
/** Builds a minimal A2UI JSONL payload that renders text in a single surface. */
function buildA2UITextJsonl(text) {
	const surfaceId = "main";
	const rootId = "root";
	const textId = "text";
	return [{ surfaceUpdate: {
		surfaceId,
		components: [{
			id: rootId,
			component: { Column: { children: { explicitList: [textId] } } }
		}, {
			id: textId,
			component: { Text: {
				text: { literalString: text },
				usageHint: "body"
			} }
		}]
	} }, { beginRendering: {
		surfaceId,
		root: rootId
	} }].map((payload) => JSON.stringify(payload)).join("\n");
}
/** Validates A2UI JSONL and returns the detected dialect/version metadata. */
function validateA2UIJsonl(jsonl) {
	const lines = jsonl.split(/\r?\n/);
	const errors = [];
	let sawV08 = false;
	let sawV09 = false;
	let messageCount = 0;
	lines.forEach((line, idx) => {
		const trimmed = line.trim();
		if (!trimmed) return;
		messageCount += 1;
		let obj;
		try {
			obj = JSON.parse(trimmed);
		} catch (err) {
			errors.push(`line ${idx + 1}: ${String(err)}`);
			return;
		}
		if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
			errors.push(`line ${idx + 1}: expected JSON object`);
			return;
		}
		const record = obj;
		const actionKeys = A2UI_ACTION_KEYS.filter((key) => key in record);
		if (actionKeys.length !== 1) {
			errors.push(`line ${idx + 1}: expected exactly one action key (${A2UI_ACTION_KEYS.join(", ")})`);
			return;
		}
		if (actionKeys[0] === "createSurface") sawV09 = true;
		else sawV08 = true;
	});
	if (messageCount === 0) errors.push("no JSONL messages found");
	if (sawV08 && sawV09) errors.push("mixed A2UI v0.8 and v0.9 messages in one file");
	if (errors.length > 0) throw new Error(`Invalid A2UI JSONL:\n- ${errors.join("\n- ")}`);
	return {
		version: sawV09 ? "v0.9" : "v0.8",
		messageCount
	};
}
//#endregion
//#region extensions/canvas/src/cli.ts
/**
* Canvas node CLI command registration and runtime dependency wiring.
*/
function parseCanvasSnapshotRequestFormat(raw) {
	switch (normalizeLowercaseStringOrEmpty(normalizeOptionalString(raw) ?? "jpg")) {
		case "png": return "png";
		case "jpg":
		case "jpeg": return "jpeg";
		default: throw new Error(`invalid format: ${String(raw)} (expected png|jpg|jpeg)`);
	}
}
function parseTimeoutMs(raw) {
	if (raw === void 0 || raw === null) return;
	return parseStrictPositiveInteger(raw);
}
function parseCanvasPositiveIntOption(raw, flag) {
	if (!raw) return;
	const parsed = parseStrictPositiveInteger(raw);
	if (parsed === void 0) throw new Error(`${flag} must be a positive integer.`);
	return parsed;
}
function parseCanvasFiniteNumberOption(raw, flag) {
	if (!raw) return;
	const parsed = parseStrictFiniteNumber(raw);
	if (parsed === void 0) throw new Error(`${flag} must be a number.`);
	return parsed;
}
function parseNodeCandidates(raw) {
	const payload = raw && typeof raw === "object" ? raw : {};
	return (Array.isArray(payload.nodes) ? payload.nodes : Array.isArray(payload.paired) ? payload.paired : []).map((entry) => {
		if (!entry || typeof entry !== "object") return null;
		const node = entry;
		if (typeof node.nodeId !== "string") return null;
		const candidate = { nodeId: node.nodeId };
		if (typeof node.displayName === "string") candidate.displayName = node.displayName;
		if (typeof node.remoteIp === "string") candidate.remoteIp = node.remoteIp;
		if (typeof node.connected === "boolean") candidate.connected = node.connected;
		if (typeof node.clientId === "string") candidate.clientId = node.clientId;
		return candidate;
	}).filter((entry) => entry !== null);
}
function unauthorizedHintForMessage(message) {
	const haystack = normalizeLowercaseStringOrEmpty(message);
	if (haystack.includes("unauthorizedclient") || haystack.includes("bridge client is not authorized") || haystack.includes("unsigned bridge clients are not allowed")) return [
		"peekaboo bridge rejected the client.",
		"sign the peekaboo CLI (TeamID Y5PE65HELJ) or launch the host with",
		"PEEKABOO_ALLOW_UNSIGNED_SOCKET_CLIENTS=1 for local dev."
	].join(" ");
	return null;
}
/** Creates the default Canvas CLI dependency bundle backed by the OpenClaw gateway CLI. */
function createDefaultCanvasCliDependencies() {
	const nodesCallOpts = (cmd, defaults) => cmd.option("--url <url>", "Gateway WebSocket URL (defaults to gateway.remote.url when configured)").option("--token <token>", "Gateway token (if required)").option("--timeout <ms>", "Timeout in ms", String(defaults?.timeoutMs ?? 1e4)).option("--json", "Output JSON", false);
	const callGatewayCli = async (method, opts, params, callOpts) => {
		const timeout = String(callOpts?.transportTimeoutMs ?? opts.timeout ?? 1e4);
		return await callGatewayFromCli(method, {
			...opts,
			timeout
		}, params, { progress: opts.json !== true });
	};
	return {
		defaultRuntime,
		nodesCallOpts,
		runNodesCommand: (label, action) => runCommandWithRuntime(defaultRuntime, action, (err) => {
			const message = formatErrorMessage(err);
			defaultRuntime.error(theme.error(`nodes ${label} failed: ${message}`));
			const hint = unauthorizedHintForMessage(message);
			if (hint) defaultRuntime.error(theme.warn(hint));
			defaultRuntime.exit(1);
		}),
		getNodesTheme: () => ({ ok: theme.success }),
		parseTimeoutMs,
		resolveNodeId: async (opts, query) => {
			let raw;
			try {
				raw = await callGatewayCli("node.list", opts, {});
			} catch {
				raw = await callGatewayCli("node.pair.list", opts, {});
			}
			return resolveNodeFromNodeList(parseNodeCandidates(raw), query).nodeId;
		},
		buildNodeInvokeParams: ({ nodeId, command, params, timeoutMs }) => ({
			nodeId,
			command,
			params,
			idempotencyKey: randomUUID(),
			...typeof timeoutMs === "number" && Number.isFinite(timeoutMs) ? { timeoutMs } : {}
		}),
		callGatewayCli,
		writeBase64ToFile: async (filePath, base64) => await fs.writeFile(filePath, Buffer.from(base64, "base64")),
		shortenHomePath
	};
}
async function invokeCanvas(deps, opts, command, params) {
	const nodeId = await deps.resolveNodeId(opts, normalizeOptionalString(opts.node) ?? "");
	const timeoutMs = deps.parseTimeoutMs(opts.invokeTimeout);
	return await deps.callGatewayCli("node.invoke", opts, deps.buildNodeInvokeParams({
		nodeId,
		command,
		params,
		timeoutMs: typeof timeoutMs === "number" ? timeoutMs : void 0
	}));
}
/** Registers Canvas subcommands under the nodes CLI command group. */
function registerNodesCanvasCommands(nodes, deps) {
	const canvas = nodes.command("canvas").description("Capture or render canvas content from a paired node");
	deps.nodesCallOpts(canvas.command("snapshot").description("Capture a canvas snapshot (prints the saved path)").requiredOption("--node <idOrNameOrIp>", "Node id, name, or IP").option("--format <png|jpg|jpeg>", "Image format", "jpg").option("--max-width <px>", "Max width in px (optional)").option("--quality <0-1>", "JPEG quality (optional)").option("--invoke-timeout <ms>", "Node invoke timeout in ms (default 20000)", "20000").action(async (opts) => {
		await deps.runNodesCommand("canvas snapshot", async () => {
			const format = parseCanvasSnapshotRequestFormat(opts.format);
			const maxWidth = parseCanvasPositiveIntOption(opts.maxWidth, "--max-width");
			const quality = parseCanvasFiniteNumberOption(opts.quality, "--quality");
			const raw = await invokeCanvas(deps, opts, "canvas.snapshot", {
				format,
				maxWidth: Number.isFinite(maxWidth) ? maxWidth : void 0,
				quality: Number.isFinite(quality) ? quality : void 0
			});
			const payload = parseCanvasSnapshotPayload((typeof raw === "object" && raw !== null ? raw : {}).payload);
			const filePath = canvasSnapshotTempPath({ ext: payload.format === "jpeg" ? "jpg" : payload.format });
			await deps.writeBase64ToFile(filePath, payload.base64);
			if (opts.json) {
				deps.defaultRuntime.writeJson({ file: {
					path: filePath,
					format: payload.format
				} });
				return;
			}
			deps.defaultRuntime.log(deps.shortenHomePath(filePath));
		});
	}), { timeoutMs: 6e4 });
	deps.nodesCallOpts(canvas.command("present").description("Show the canvas (optionally with a target URL/path)").requiredOption("--node <idOrNameOrIp>", "Node id, name, or IP").option("--target <urlOrPath>", "Target URL/path (optional)").option("--x <px>", "Placement x coordinate").option("--y <px>", "Placement y coordinate").option("--width <px>", "Placement width").option("--height <px>", "Placement height").option("--invoke-timeout <ms>", "Node invoke timeout in ms").action(async (opts) => {
		await deps.runNodesCommand("canvas present", async () => {
			const placement = {
				x: parseCanvasFiniteNumberOption(opts.x, "--x"),
				y: parseCanvasFiniteNumberOption(opts.y, "--y"),
				width: parseCanvasFiniteNumberOption(opts.width, "--width"),
				height: parseCanvasFiniteNumberOption(opts.height, "--height")
			};
			const params = {};
			if (opts.target) params.url = opts.target;
			if (Number.isFinite(placement.x) || Number.isFinite(placement.y) || Number.isFinite(placement.width) || Number.isFinite(placement.height)) params.placement = placement;
			await invokeCanvas(deps, opts, "canvas.present", params);
			if (!opts.json) {
				const { ok } = deps.getNodesTheme();
				deps.defaultRuntime.log(ok("canvas present ok"));
			}
		});
	}));
	deps.nodesCallOpts(canvas.command("hide").description("Hide the canvas").requiredOption("--node <idOrNameOrIp>", "Node id, name, or IP").option("--invoke-timeout <ms>", "Node invoke timeout in ms").action(async (opts) => {
		await deps.runNodesCommand("canvas hide", async () => {
			await invokeCanvas(deps, opts, "canvas.hide", void 0);
			if (!opts.json) {
				const { ok } = deps.getNodesTheme();
				deps.defaultRuntime.log(ok("canvas hide ok"));
			}
		});
	}));
	deps.nodesCallOpts(canvas.command("navigate").description("Navigate the canvas to a URL").argument("<url>", "Target URL/path").requiredOption("--node <idOrNameOrIp>", "Node id, name, or IP").option("--invoke-timeout <ms>", "Node invoke timeout in ms").action(async (url, opts) => {
		await deps.runNodesCommand("canvas navigate", async () => {
			await invokeCanvas(deps, opts, "canvas.navigate", { url });
			if (!opts.json) {
				const { ok } = deps.getNodesTheme();
				deps.defaultRuntime.log(ok("canvas navigate ok"));
			}
		});
	}));
	deps.nodesCallOpts(canvas.command("eval").description("Evaluate JavaScript in the canvas").argument("[js]", "JavaScript to evaluate").option("--js <code>", "JavaScript to evaluate").requiredOption("--node <idOrNameOrIp>", "Node id, name, or IP").option("--invoke-timeout <ms>", "Node invoke timeout in ms").action(async (jsArg, opts) => {
		await deps.runNodesCommand("canvas eval", async () => {
			const js = opts.js ?? jsArg;
			if (!js) throw new Error("missing --js or <js>");
			const raw = await invokeCanvas(deps, opts, "canvas.eval", { javaScript: js });
			if (opts.json) {
				deps.defaultRuntime.writeJson(raw);
				return;
			}
			const payload = typeof raw === "object" && raw !== null ? raw.payload : void 0;
			if (payload?.result) deps.defaultRuntime.log(payload.result);
			else {
				const { ok } = deps.getNodesTheme();
				deps.defaultRuntime.log(ok("canvas eval ok"));
			}
		});
	}));
	const a2ui = canvas.command("a2ui").description("Render A2UI content on the canvas");
	deps.nodesCallOpts(a2ui.command("push").description("Push A2UI JSONL to the canvas").option("--jsonl <path>", "Path to JSONL payload").option("--text <text>", "Render a quick A2UI text payload").requiredOption("--node <idOrNameOrIp>", "Node id, name, or IP").option("--invoke-timeout <ms>", "Node invoke timeout in ms").action(async (opts) => {
		await deps.runNodesCommand("canvas a2ui push", async () => {
			const hasJsonl = Boolean(opts.jsonl);
			const hasText = typeof opts.text === "string";
			if (hasJsonl === hasText) throw new Error("provide exactly one of --jsonl or --text");
			const jsonl = hasText ? buildA2UITextJsonl(opts.text ?? "") : await fs.readFile(String(opts.jsonl), "utf8");
			const { version, messageCount } = validateA2UIJsonl(jsonl);
			if (version === "v0.9") throw new Error("Detected A2UI v0.9 JSONL (createSurface). OpenClaw currently supports v0.8 only.");
			await invokeCanvas(deps, opts, "canvas.a2ui.pushJSONL", { jsonl });
			if (!opts.json) {
				const { ok } = deps.getNodesTheme();
				deps.defaultRuntime.log(ok(`canvas a2ui push ok (v0.8, ${messageCount} message${messageCount === 1 ? "" : "s"})`));
			}
		});
	}));
	deps.nodesCallOpts(a2ui.command("reset").description("Reset A2UI renderer state").requiredOption("--node <idOrNameOrIp>", "Node id, name, or IP").option("--invoke-timeout <ms>", "Node invoke timeout in ms").action(async (opts) => {
		await deps.runNodesCommand("canvas a2ui reset", async () => {
			await invokeCanvas(deps, opts, "canvas.a2ui.reset", void 0);
			if (!opts.json) {
				const { ok } = deps.getNodesTheme();
				deps.defaultRuntime.log(ok("canvas a2ui reset ok"));
			}
		});
	}));
}
//#endregion
export { registerNodesCanvasCommands as n, createDefaultCanvasCliDependencies as t };
