import { fileURLToPath } from "node:url"; import { MIN_CLIENT_PROTOCOL_VERSION, PROTOCOL_VERSION, } from "../../packages/gateway-protocol/src/version.js"; import { createArgReader, createGatewayWsClient, resolveGatewayUrl } from "./gateway-ws-client.ts"; function writeStdoutLine(message: string): void { process.stdout.write(`${message}\n`); } function writeStderrLine(message: string): void { process.stderr.write(`${message}\n`); } function writeUsage(): void { writeStderrLine( "Usage: bun scripts/dev/gateway-smoke.ts --url --token \n" + "Or set env: OPENCLAW_GATEWAY_URL / OPENCLAW_GATEWAY_TOKEN", ); } type GatewaySmokeClient = ReturnType; type GatewaySmokeDeps = { createClient?: typeof createGatewayWsClient; stderr?: (message: string) => void; stdout?: (message: string) => void; }; export async function runGatewaySmoke( input: { token: string; urlRaw: string }, deps: GatewaySmokeDeps = {}, ): Promise { const url = resolveGatewayUrl(input.urlRaw); const createClient = deps.createClient ?? createGatewayWsClient; const stderr = deps.stderr ?? writeStderrLine; const stdout = deps.stdout ?? writeStdoutLine; const client: GatewaySmokeClient = createClient({ url: url.toString(), onEvent: (evt) => { // Ignore noisy connect handshakes. void evt; }, }); const { request, waitOpen, close } = client; try { await waitOpen(); // Match iOS "operator" session defaults: token auth, no device identity. const connectRes = await request("connect", { minProtocol: MIN_CLIENT_PROTOCOL_VERSION, maxProtocol: PROTOCOL_VERSION, client: { id: "openclaw-ios", displayName: "openclaw gateway smoke test", version: "dev", platform: "dev", mode: "ui", instanceId: "openclaw-dev-smoke", }, locale: "en-US", userAgent: "gateway-smoke", role: "operator", scopes: ["operator.read", "operator.write", "operator.admin"], caps: [], auth: { token: input.token }, }); if (!connectRes.ok) { stderr(`connect failed: ${String(connectRes.error)}`); return 2; } const healthRes = await request("health"); if (!healthRes.ok) { stderr(`health failed: ${String(healthRes.error)}`); return 3; } const historyRes = await request("chat.history", { sessionKey: "main" }, 15000); if (!historyRes.ok) { stderr(`chat.history failed: ${String(historyRes.error)}`); return 4; } stdout("ok: connected + health + chat.history"); return 0; } finally { close(); } } if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) { const { get: getArg } = createArgReader(); const urlRaw = getArg("--url") ?? process.env.OPENCLAW_GATEWAY_URL; const token = getArg("--token") ?? process.env.OPENCLAW_GATEWAY_TOKEN; if (!urlRaw || !token) { writeUsage(); process.exitCode = 1; } else { process.exitCode = await runGatewaySmoke({ token, urlRaw }); } }