diff --git a/src/cli/nodes-cli/register.camera.ts b/src/cli/nodes-cli/register.camera.ts index 76f839f6a74..3039189f0ff 100644 --- a/src/cli/nodes-cli/register.camera.ts +++ b/src/cli/nodes-cli/register.camera.ts @@ -1,6 +1,5 @@ import type { Command } from "commander"; import type { NodesRpcOpts } from "./types.js"; -import { randomIdempotencyKey } from "../../gateway/call.js"; import { defaultRuntime } from "../../runtime.js"; import { renderTable } from "../../terminal/table.js"; import { shortenHomePath } from "../../utils.js"; @@ -14,7 +13,7 @@ import { } from "../nodes-camera.js"; import { parseDurationMs } from "../parse-duration.js"; import { getNodesTheme, runNodesCommand } from "./cli-utils.js"; -import { callGatewayCli, nodesCallOpts, resolveNodeId } from "./rpc.js"; +import { buildNodeInvokeParams, callGatewayCli, nodesCallOpts, resolveNodeId } from "./rpc.js"; const parseFacing = (value: string): CameraFacing => { const v = String(value ?? "") @@ -37,12 +36,15 @@ export function registerNodesCameraCommands(nodes: Command) { .action(async (opts: NodesRpcOpts) => { await runNodesCommand("camera list", async () => { const nodeId = await resolveNodeId(opts, String(opts.node ?? "")); - const raw = await callGatewayCli("node.invoke", opts, { - nodeId, - command: "camera.list", - params: {}, - idempotencyKey: randomIdempotencyKey(), - }); + const raw = await callGatewayCli( + "node.invoke", + opts, + buildNodeInvokeParams({ + nodeId, + command: "camera.list", + params: {}, + }), + ); const res = typeof raw === "object" && raw !== null ? (raw as { payload?: unknown }) : {}; const payload = @@ -130,7 +132,7 @@ export function registerNodesCameraCommands(nodes: Command) { }> = []; for (const facing of facings) { - const invokeParams: Record = { + const invokeParams = buildNodeInvokeParams({ nodeId, command: "camera.snap", params: { @@ -141,11 +143,8 @@ export function registerNodesCameraCommands(nodes: Command) { delayMs: Number.isFinite(delayMs) ? delayMs : undefined, deviceId: deviceId || undefined, }, - idempotencyKey: randomIdempotencyKey(), - }; - if (typeof timeoutMs === "number" && Number.isFinite(timeoutMs)) { - invokeParams.timeoutMs = timeoutMs; - } + timeoutMs, + }); const raw = await callGatewayCli("node.invoke", opts, invokeParams); const res = @@ -204,7 +203,7 @@ export function registerNodesCameraCommands(nodes: Command) { : undefined; const deviceId = opts.deviceId ? String(opts.deviceId).trim() : undefined; - const invokeParams: Record = { + const invokeParams = buildNodeInvokeParams({ nodeId, command: "camera.clip", params: { @@ -214,11 +213,8 @@ export function registerNodesCameraCommands(nodes: Command) { format: "mp4", deviceId: deviceId || undefined, }, - idempotencyKey: randomIdempotencyKey(), - }; - if (typeof timeoutMs === "number" && Number.isFinite(timeoutMs)) { - invokeParams.timeoutMs = timeoutMs; - } + timeoutMs, + }); const raw = await callGatewayCli("node.invoke", opts, invokeParams); const res = typeof raw === "object" && raw !== null ? (raw as { payload?: unknown }) : {}; diff --git a/src/cli/nodes-cli/register.canvas.ts b/src/cli/nodes-cli/register.canvas.ts index 5883953eb47..d9877f8ad15 100644 --- a/src/cli/nodes-cli/register.canvas.ts +++ b/src/cli/nodes-cli/register.canvas.ts @@ -1,7 +1,6 @@ import type { Command } from "commander"; import fs from "node:fs/promises"; import type { NodesRpcOpts } from "./types.js"; -import { randomIdempotencyKey } from "../../gateway/call.js"; import { defaultRuntime } from "../../runtime.js"; import { shortenHomePath } from "../../utils.js"; import { writeBase64ToFile } from "../nodes-camera.js"; @@ -9,21 +8,21 @@ import { canvasSnapshotTempPath, parseCanvasSnapshotPayload } from "../nodes-can import { parseTimeoutMs } from "../nodes-run.js"; import { buildA2UITextJsonl, validateA2UIJsonl } from "./a2ui-jsonl.js"; import { getNodesTheme, runNodesCommand } from "./cli-utils.js"; -import { callGatewayCli, nodesCallOpts, resolveNodeId } from "./rpc.js"; +import { buildNodeInvokeParams, callGatewayCli, nodesCallOpts, resolveNodeId } from "./rpc.js"; async function invokeCanvas(opts: NodesRpcOpts, command: string, params?: Record) { const nodeId = await resolveNodeId(opts, String(opts.node ?? "")); - const invokeParams: Record = { - nodeId, - command, - params, - idempotencyKey: randomIdempotencyKey(), - }; const timeoutMs = parseTimeoutMs(opts.invokeTimeout); - if (typeof timeoutMs === "number") { - invokeParams.timeoutMs = timeoutMs; - } - return await callGatewayCli("node.invoke", opts, invokeParams); + return await callGatewayCli( + "node.invoke", + opts, + buildNodeInvokeParams({ + nodeId, + command, + params, + timeoutMs: typeof timeoutMs === "number" ? timeoutMs : undefined, + }), + ); } export function registerNodesCanvasCommands(nodes: Command) { @@ -42,7 +41,6 @@ export function registerNodesCanvasCommands(nodes: Command) { .option("--invoke-timeout ", "Node invoke timeout in ms (default 20000)", "20000") .action(async (opts: NodesRpcOpts) => { await runNodesCommand("canvas snapshot", async () => { - const nodeId = await resolveNodeId(opts, String(opts.node ?? "")); const formatOpt = String(opts.format ?? "jpg") .trim() .toLowerCase(); @@ -54,25 +52,11 @@ export function registerNodesCanvasCommands(nodes: Command) { const maxWidth = opts.maxWidth ? Number.parseInt(String(opts.maxWidth), 10) : undefined; const quality = opts.quality ? Number.parseFloat(String(opts.quality)) : undefined; - const timeoutMs = opts.invokeTimeout - ? Number.parseInt(String(opts.invokeTimeout), 10) - : undefined; - - const invokeParams: Record = { - nodeId, - command: "canvas.snapshot", - params: { - format: formatForParams, - maxWidth: Number.isFinite(maxWidth) ? maxWidth : undefined, - quality: Number.isFinite(quality) ? quality : undefined, - }, - idempotencyKey: randomIdempotencyKey(), - }; - if (typeof timeoutMs === "number" && Number.isFinite(timeoutMs)) { - invokeParams.timeoutMs = timeoutMs; - } - - const raw = await callGatewayCli("node.invoke", opts, invokeParams); + const raw = await invokeCanvas(opts, "canvas.snapshot", { + format: formatForParams, + maxWidth: Number.isFinite(maxWidth) ? maxWidth : undefined, + quality: Number.isFinite(quality) ? quality : undefined, + }); const res = typeof raw === "object" && raw !== null ? (raw as { payload?: unknown }) : {}; const payload = parseCanvasSnapshotPayload(res.payload); const filePath = canvasSnapshotTempPath({ diff --git a/src/cli/nodes-cli/register.screen.ts b/src/cli/nodes-cli/register.screen.ts index 60ff4ec9716..e2034be1699 100644 --- a/src/cli/nodes-cli/register.screen.ts +++ b/src/cli/nodes-cli/register.screen.ts @@ -1,6 +1,5 @@ import type { Command } from "commander"; import type { NodesRpcOpts } from "./types.js"; -import { randomIdempotencyKey } from "../../gateway/call.js"; import { defaultRuntime } from "../../runtime.js"; import { shortenHomePath } from "../../utils.js"; import { @@ -10,7 +9,7 @@ import { } from "../nodes-screen.js"; import { parseDurationMs } from "../parse-duration.js"; import { runNodesCommand } from "./cli-utils.js"; -import { callGatewayCli, nodesCallOpts, resolveNodeId } from "./rpc.js"; +import { buildNodeInvokeParams, callGatewayCli, nodesCallOpts, resolveNodeId } from "./rpc.js"; export function registerNodesScreenCommands(nodes: Command) { const screen = nodes @@ -38,7 +37,7 @@ export function registerNodesScreenCommands(nodes: Command) { ? Number.parseInt(String(opts.invokeTimeout), 10) : undefined; - const invokeParams: Record = { + const invokeParams = buildNodeInvokeParams({ nodeId, command: "screen.record", params: { @@ -48,11 +47,8 @@ export function registerNodesScreenCommands(nodes: Command) { format: "mp4", includeAudio: opts.audio !== false, }, - idempotencyKey: randomIdempotencyKey(), - }; - if (typeof timeoutMs === "number" && Number.isFinite(timeoutMs)) { - invokeParams.timeoutMs = timeoutMs; - } + timeoutMs, + }); const raw = await callGatewayCli("node.invoke", opts, invokeParams); const res = typeof raw === "object" && raw !== null ? (raw as { payload?: unknown }) : {}; diff --git a/src/cli/nodes-cli/rpc.ts b/src/cli/nodes-cli/rpc.ts index a51e0fa2a9a..691da4dd7fa 100644 --- a/src/cli/nodes-cli/rpc.ts +++ b/src/cli/nodes-cli/rpc.ts @@ -1,6 +1,6 @@ import type { Command } from "commander"; import type { NodeListNode, NodesRpcOpts } from "./types.js"; -import { callGateway } from "../../gateway/call.js"; +import { callGateway, randomIdempotencyKey } from "../../gateway/call.js"; import { resolveNodeIdFromCandidates } from "../../shared/node-match.js"; import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../../utils/message-channel.js"; import { withProgress } from "../progress.js"; @@ -37,6 +37,25 @@ export const callGatewayCli = async ( }), ); +export function buildNodeInvokeParams(params: { + nodeId: string; + command: string; + params?: Record; + timeoutMs?: number; + idempotencyKey?: string; +}): Record { + const invokeParams: Record = { + nodeId: params.nodeId, + command: params.command, + params: params.params, + idempotencyKey: params.idempotencyKey ?? randomIdempotencyKey(), + }; + if (typeof params.timeoutMs === "number" && Number.isFinite(params.timeoutMs)) { + invokeParams.timeoutMs = params.timeoutMs; + } + return invokeParams; +} + export function unauthorizedHintForMessage(message: string): string | null { const haystack = message.toLowerCase(); if (