From f973b9e0e5c0887ea6a413fb272519cf67e77c3b Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 18 Dec 2025 01:10:27 +0000 Subject: [PATCH] Gateway: alias canvas.* for node.invoke --- src/gateway/server.test.ts | 49 ++++++++++++++++++++++++++++++++++++++ src/gateway/server.ts | 31 +++++++++++++----------- 2 files changed, 66 insertions(+), 14 deletions(-) diff --git a/src/gateway/server.test.ts b/src/gateway/server.test.ts index 3bd7aa3da..e2e7d3eca 100644 --- a/src/gateway/server.test.ts +++ b/src/gateway/server.test.ts @@ -574,6 +574,55 @@ describe("gateway server", () => { } }); + test("maps node.invoke canvas.* to screen.*", async () => { + const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-home-")); + const prevHome = process.env.HOME; + process.env.HOME = homeDir; + + try { + bridgeInvoke.mockResolvedValueOnce({ + type: "invoke-res", + id: "inv-2", + ok: true, + payloadJSON: JSON.stringify({ result: "ok" }), + error: null, + }); + + const { server, ws } = await startServerWithClient(); + try { + await connectOk(ws); + + const res = await rpcReq(ws, "node.invoke", { + nodeId: "android-node", + command: "canvas.eval", + params: { javaScript: "1+1" }, + timeoutMs: 123, + idempotencyKey: "idem-2", + }); + expect(res.ok).toBe(true); + + expect(bridgeInvoke).toHaveBeenCalledWith( + expect.objectContaining({ + nodeId: "android-node", + command: "screen.eval", + paramsJSON: JSON.stringify({ javaScript: "1+1" }), + timeoutMs: 123, + }), + ); + } finally { + ws.close(); + await server.close(); + } + } finally { + await fs.rm(homeDir, { recursive: true, force: true }); + if (prevHome === undefined) { + delete process.env.HOME; + } else { + process.env.HOME = prevHome; + } + } + }); + test("emits presence updates for bridge connect/disconnect", async () => { const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-home-")); const prevHome = process.env.HOME; diff --git a/src/gateway/server.ts b/src/gateway/server.ts index 8748e89c6..501f8f389 100644 --- a/src/gateway/server.ts +++ b/src/gateway/server.ts @@ -3011,20 +3011,23 @@ export async function startGatewayServer(port = 18789): Promise { ); break; } - const p = params as { - nodeId: string; - command: string; - params?: unknown; - timeoutMs?: number; - idempotencyKey: string; - }; - const nodeId = String(p.nodeId ?? "").trim(); - const command = String(p.command ?? "").trim(); - if (!nodeId || !command) { - respond( - false, - undefined, - errorShape( + const p = params as { + nodeId: string; + command: string; + params?: unknown; + timeoutMs?: number; + idempotencyKey: string; + }; + const nodeId = String(p.nodeId ?? "").trim(); + const rawCommand = String(p.command ?? "").trim(); + const command = rawCommand.startsWith("canvas.") + ? `screen.${rawCommand.slice("canvas.".length)}` + : rawCommand; + if (!nodeId || !command) { + respond( + false, + undefined, + errorShape( ErrorCodes.INVALID_REQUEST, "nodeId and command required", ),